在声明和初始化指针时可能会出现问题,更准确地说,指针初始化失败。在本节中,我们会研究出现这类问题的情况。
不恰当的指针声明
考虑如下声明:
int* ptr1, ptr2;
声明本身没错,不过,可能跟我们的本意不同,它把ptr1
声明为整数指针,而把ptr2
声明为整数。我们将星号有意紧挨着数据类型,而ptr1
前面则加了空格。这样的位置对编译器来说没有区别,但是对于读代码的人来说,可能暗示着ptr1
和ptr2
都是整数指针。然而,只有ptr1
是指针。
在同一行中把两个变量都声明为指针的正确写法如下所示:
int *ptr1, *ptr2;
注意 每个变量声明独占一行更好。
用类型定义代替宏定义是另一个好习惯。类型定义允许编译器检查作用域规则,而宏定义不一定会。
我们可以使用宏指令辅助声明变量,如下所示。在这里,define
指令包装了整数指针,并用它来声明变量:
#define PINT int*
PINT ptr1, ptr2;
不过,结果就跟前面所说的一样。更好的方法是用下面的类型定义:
typedef int* PINT;
PINT ptr1, ptr2;
两个变量均被声明为整数指针。
使用指针前未初始化
在初始化指针之前就使用指针会导致运行时错误,有时候将这种指针称为野指针。下面这个简单的例子声明了一个整数指针,但是使用之前没有为其赋值:
int *pi;
...
printf(“%d\n”,*pi);
图7-1说明了此时的内存分配情况。
图7-1:野指针
这里没有初始化pi
变量,因此它会包含垃圾数据(在图中用省略号表示)。如果pi
中的内存地址超出了应用程序的合法地址空间,这段代码很可能会在执行过程中终止。否则打印出来的就是恰好位于那个地址的数据(不管具体是什么),而且会表示为整数。如果我们用的是字符串指针,就经常会看到打印出奇怪的字符(直到遇到末尾的0才停止)。
处理未初始化指针
指针本身并不能告诉我们它是否有效,所以,不能只靠检查指针的内容来判断它是否有效。不过,有三种方法可以用来处理未初始化的指针:
- 总是用
NULL
来初始化指针; - 用
assert
函数; - 用第三方工具。
把指针初始化为NULL
更容易检查是否使用正确。即便这样,检查空值也比较麻烦,如下所示:
int *pi = NULL;
...
if(pi == NULL) {
// 不应该解引pi
} else {
// 可以使用pi
}
我们可以用assert
函数来测试指针是否为空值。下例测试了pi
变量是否为空值。如果表达式为真,那么什么都不会发生,如果表达式为假,程序会终止。这样,指针为空的话程序就会终止。
assert(pi != NULL);
对于应用程序的调试版本,这种方法可能可以接受。如果指针是空值,输出类似下面:
Assertion failed: pi != NULL
我们在assert.h头文件中声明assert
函数。
可使用第三方工具来帮助定位这类问题,此外,有些编译器选项也比较有用,使用静态分析工具中会讲到。
评论前必须登录!
注册