18、复合类型之指针(P47、P48、P49、P50);C++ primer 2.3.2
1、C++中的“声明符”是什么?
声明符是用来指定变量或函数的类型、名称和属性的符号。例如:
int list[20];
声明了一个名为 list 的整型数组,它有 20 个元素。int是类型说明符,list[20]是声明符char *cp;
声明了一个名为 cp 的指向字符的指针1。*cp是声明符double func( void );
声明了一个名为 func 的函数,它没有参数,返回一个双精度浮点数。func( void )声明符
2、因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。
这句话的意思是,引用不是一个独立的变量,它只是某个变量的别名,所以它没有自己的地址,也不能被取地址。指针是一个变量,它存储的是一个地址,指向内存的一个存储单元,所以它有自己的地址,也可以被取地址。举个例子:
int a = 10; // 定义一个整型变量 a
int &b = a; // 定义一个引用 b,指向 a
int *c = &a; // 定义一个指针 c,指向 a 的地址
int *d = &b; // 定义一个指针 d,指向 b 的地址
int **e = &c; // 定义一个指针 e,指向 c 的地址
// int *&f = &b; // 错误!不能定义指向引用的指针
cout << "a = " << a << endl; // 输出 a 的值
cout << "b = " << b << endl; // 输出 b 的值,等于 a 的值
cout << "c = " << c << endl; // 输出 c 的值,等于 a 的地址
cout << "d = " << d << endl; // 输出 d 的值,等于 b 的地址,也等于 a 的地址
cout << "e = " << e << endl; // 输出 e 的值,等于 c 的地址
// cout << "f = " << f << endl; // 错误!不能输出 f 的值
cout << "&a = " << &a << endl; // 输出 a 的地址
cout << "&b = " << &b << endl; // 输出 b 的地址,等于 a 的地址
cout << "&c = " << &c << endl; // 输出 c 的地址
cout << "&d = " << &d << endl; // 输出 d 的地址
cout << "&e = " << &e << endl; // 输出 e 的地址
// cout << "&f = " << &f << endl; // 错误!不能输出 f 的地址
运行结果:
a = 10
b = 10
c = 0x7ffeefbff5ac
d = 0x7ffeefbff5ac
e = 0x7ffeefbff5a0
&a = 0x7ffeefbff5ac
&b = 0x7ffeefbff5ac
&c = 0x7ffeefbff5a0
&d = 0x7ffeefbff5a8
&e = 0x7ffeefbff598
从上面的例子可以看出,引用 b 和变量 a 是同一个东西,它们的值和地址都相同;而指针 c 和 d 是不同的东西,它们的值是 a 的地址,但它们自己也有不同的地址;而 e 是指向指针的指针,它的值是 c 的地址,它自己也有不同的地址。所以,引用和指针是有本质区别的。
3、什么是声明语句?
声明语句是一种用来为变量、常量、函数、类型或命名空间等实体命名和指定类型的语句12345。声明语句可以出现在不同的编程语言中,如C、C++、Java、Visual Basic等,但具体的语法和规则可能有所不同。例如:
// Java 中的声明语句
int x; // 声明一个整型变量 x
String s = "Hello"; // 声明一个字符串变量 s,并赋值为 "Hello"
final double PI = 3.14; // 声明一个常量 PI,并赋值为 3.14
void print(String msg) { // 声明一个函数 print,参数为字符串 msg
System.out.println(msg); // 函数体
}
4、nullptr可以被转成任意其他的指针类型
nullptr
是C++11引入的空指针常量,可以用来初始化任何指针类型。在C++11之前,程序员通常使用NULL
或者0
来表示空指针,但是这样做可能会导致一些问题。例如,NULL
被定义为整数0,而不是指针类型,这可能会导致一些类型转换的问题。相比之下,nullptr
是一个真正的指针类型,可以隐式转换为任何指针类型。下面是一个例子:
int* p = nullptr; // 初始化一个整型指针为空指针
double* q = nullptr; // 初始化一个双精度浮点型指针为空指针
这里我们定义了两个指针变量p
和q
,并将它们都初始化为空指针。由于nullptr
可以隐式转换为任何指针类型,因此我们可以将其用于任何指针类型的初始化。
5、什么是预处理变量?
C++中的预处理变量是指在编译器对源代码进行编译之前,由预处理器进行处理的一些变量或指令。预处理变量以#开头,可以用来定义宏、包含文件、设置条件编译等功能。预处理变量可以提高代码的可读性、可维护性和效率。
举例来说,我们可以使用#define来定义一个常量或一个带参数的函数宏,例如:
#define PI 3.14159 //定义一个常量
#define MAX(a,b) ((a)>(b)?(a):(b)) //定义一个函数宏,用来求两个数的最大值
这样,在源代码中出现PI或MAX(a,b)的地方,都会被预处理器替换为对应的值或表达式。
另一个例子是,我们可以使用#ifndef和#endif来避免头文件的重复包含,例如:
#ifndef MY_HEADER_H //如果没有定义MY_HEADER_H这个宏
#define MY_HEADER_H //则定义它
//头文件的内容
#endif //结束条件编译
这样,当我们在多个源文件中包含同一个头文件时,只有第一次包含时会执行头文件的内容,后面的包含都会被忽略,从而避免了重复定义或声明的错误。
#include <iostream>
#include <algorithm>
using namespace std;
#define MY_HEADER_H 12
int main(){
std::cout<< MY_HEADER_H<<endl;
#ifndef MY_HEADER_H
#define MY_HEADER_H 10//则定义
std::cout<< MY_HEADER_H<<endl;
#endif //结束条件编译
std::cout<< MY_HEADER_H<<endl;
return 0;
}
6、void*指针作为函数的输入或输出。
void*
指针是一种通用的指针类型,它可以指向任何数据类型的内存地址。因此,它经常用于函数的输入或输出,以使函数能够处理各种不同类型的数据或返回不确定类型的数据。这种用法通常在 C 和 C++ 等编程语言中见到。
以下是一些示例,说明如何在函数中使用 void*
指针作为输入或输出参数:
1. void*
作为函数输入参数:
void processData(void* data, size_t dataSize) {
// 在这里,您可以根据需要对数据进行操作,因为它是一个通用指针。
// 您可能需要知道数据的大小(dataSize)来正确处理数据。
}
int main() {
int intValue = 42;
double doubleValue = 3.14;
processData(&intValue, sizeof(int));
processData(&doubleValue, sizeof(double));
return 0;
}
void*
指针是一种通用的指针类型,它可以指向任何数据类型的内存地址。因此,它经常用于函数的输入或输出,以使函数能够处理各种不同类型的数据或返回不确定类型的数据。这种用法通常在 C 和 C++ 等编程语言中见到。
以下是一些示例,说明如何在函数中使用 void*
指针作为输入或输出参数:
1. void*
作为函数输入参数:
void processData(void* data, size_t dataSize) { // 在这里,您可以根据需要对数据进行操作,因为它是一个通用指针。 // 您可能需要知道数据的大小(dataSize)来正确处理数据。 } int main() { int intValue = 42; double doubleValue = 3.14; processData(&intValue, sizeof(int)); processData(&doubleValue, sizeof(double)); return 0; }
上面的示例中,processData
函数接受一个 void*
指针作为输入参数,以及一个表示数据大小的参数 dataSize
。这使得函数可以处理不同类型的数据。
2. void*
作为函数输出参数:
void* allocateMemory(size_t size) {
void* ptr = malloc(size);
return ptr;
}
int main() {
int* intArray;
double* doubleArray;
intArray = (int*)allocateMemory(5 * sizeof(int));
doubleArray = (double*)allocateMemory(3 * sizeof(double));
// 在这里使用分配的内存
free(intArray);
free(doubleArray);
return 0;
}
在上面的示例中,allocateMemory
函数返回一个 void*
指针,该指针指向动态分配的内存块。在 main
函数中,我们将返回的指针转换为适当的数据类型(例如,int*
和 double*
)以便使用。这使得我们可以动态地分配内存并在程序中使用它。
需要注意的是,使用 void*
指针需要谨慎,因为它们不提供类型安全性,可能需要在使用时进行显式的类型转换。确保在使用 void*
指针时,您了解所处理的数据类型,并小心处理大小和类型转换。