为指针正确赋值可以避免未定义行为(如野指针)。指针可以指向变量、数组、另一个指针(多级指针)、函数等。
指针的初始化可以在声明时进行,也可以在声明之后进行。
初始化为 nullptr
从 C++11 开始,建议初始化未指向任何具体对象的指针为 nullptr。这是一个特殊的值,代表该指针没有指向任何内存地址。在 C++11 之前,NULL 被用来表示空指针。它通常被定义为 0 或者 ((void*)0)。
不过,使用 nullptr 可以提高代码的表达能力,因为 nullptr 的类型是 nullptr_t,而 NULL 实际上是一个整数。
int* pInt = nullptr;
int* ptr = NULL;
初始化为变量的地址
可以通过取地址运算符 & 获取一个变量的地址,并将其赋给指针。这个指针现在指向了该变量。
int value = 5;
pInt = &value;
初始化为数组的地址
也可以使用 new 关键字为一个数组分配内存。
void func()
{
int arr[] = {1, 2, 3, 4, 5};
int* ptrToArray = arr;
int* ptrToElement = &arr[2];
}
void func1()
{
int* arrayPtr = new int[10];
delete[] arrayPtr;
}
初始化为另一个指针的值
int* ptrToAnother = ptrToInt;
初始化为动态分配的内存
使用 new 关键字动态地分配内存,并把返回的地址赋给指针。
int* ptrToDynamicInt = new int;
int* ptr = new int;
*ptr = 5;
delete ptr;
常量指针和指针常量的初始化
初始化指向常量的指针(指针可以改变,但所指向的值不能改变)。
const int constantVar = 10;
const int* ptrToConst = &constantVar;
初始化指针常量(指针一旦指向一个地址就不能改变,但可以通过指针改变所指向地址的值)。
int var = 10;
int* const constPtr = &var;
*constPtr = 20;
初始化为函数的指针
void myFunction() {
}
void (*functionPtr)() = myFunction;
int add(int a, int b) {
return a + b;
}
int (*functionPtr)(int, int);
functionPtr = add;
int result = functionPtr(3, 4);
int (*functionPtr)(int, int) = add;
列表初始化(C++11 及以后)
C++11 引入了列表初始化,可以用来初始化指针。
void func()
{
int* ptrToZero = new int{};
int* ptrToArrayInit = new int[5]{};
}
void func1()
{
int* ptr = new int{5};
int value = 5;
int* ptr = &value;
int* ptr{};
}
用 auto 初始化指针
使用 auto 时的注意事项,必须明确初始化语句
- 如果用变量的地址初始化指针,auto 将推导为相应的指针类型。
- 如果用 new 操作符初始化指针,auto 也会推导为指向新分配类型的指针。
- 当使用 auto 初始化数组名时,它会被推导为指向数组首元素的指针类型。然而,使用 auto& 可以使得推导出的类型为数组类型的引用。
- 如果用函数的名字初始化,auto 将推导为指向函数类型的指针。
auto ptr = &var;
auto ptr = new int(5);
int array[] = {1, 2, 3};
auto ptr = array;
void myFunction() {
}
auto funcPtr = myFunction;
const int constantValue = 100;
auto constPtr = &constantValue;
int value = 10;
auto constPtr = &value;
注意事项
在使用指针时,始终要确保已经给它们赋了一个确定的、有效的地址。随机的、未知的或已释放的内存地址都可能导致未定义的行为。特别地,从未初始化、已释放或已解引用的指针里读取数据,或者向这样的指针里写入数据,都可能导致程序崩溃或其他意想不到的行为。