指针的作用特别强,对许多问题是必须的。同时,偶尔错用指针,会带来意想不到的错误,甚至是灾难性的后果。
指针错误难以定位,因为指针本身并没有问题。问题在于,通过错误指针操作时,程序对未知内存区进行读写操作。读操作时,最坏的情况是取得无用数据;而写操作时,可能冲掉其他代码或数据。
(一)使用未初始化的指针(uninitialized pointer)
int main(void)
{
int x, *p;
x = 10;
*p = x; //错误,指针未初始化
return 0;
}
(二)误解指针的用法,将值当做地址赋给指针
#include <stdio.h>
int main(void)
{
int x, *p;
x = 10;
p = x; //错误,应该是p=&x,指针保存的是地址,而不是值
printf("%d", *p);
return 0;
}
(三)这种错误是对内存中数据存放位置的错误假定。比较指向不同对象的指针时,容易产生意外结果。例如:
char s[80], y[80];
char *p1, *p2;
p1 = s;
p2 = y;
if(p1 < p2) . . . //错误,不能确保数据处于内存的同样位置,也不能确保各种机器都用同样的格式保存数据
类似的错误是想当然地以为同时定义的两个数组在内存区是顺序排列,从而简单地对指针增值,期望像使用两者组成的一个数组那样跨越数组边界。例如:
int first[10], second[10];
int *p, t;
p = first;
for(t=0; t<20; ++t) *p++ = t;
(四)
/* 这段程序有错误 */
#include <string.h>
#include <stdio.h>
int main(void)
{
char *p1;
char s[80];
p1 = s;
do {
gets(s); /* read a string */
/* print the decimal equivalent of each
character */
while(*p1) printf(" %d", *p1++);
} while(strcmp(s, "done"));
return 0;
}
上述程序通过p1打印出与s中诸字符关联的ASCII值。问题是只对p赋值(s的地址)一次。第一轮循环中,p1指向s中首字符。第二轮循环时,因为未再置成s的起点,p值从第一轮的结束点继续。此时,p可能指向另一个串,另一个变量,甚至程序的某一段。正确程序应该是:
#include <string.h>
#include <stdio.h>
int main(void)
{
char *p1;
char s[80];
do {
p1 = s; /* reset p1 to beginning of s */
gets(s); /* read a string */
/* print the decimal equivalent of each
character */
while(*p1) printf(" %d", *p1++);
} while(strcmp(s, "done"));
return 0;
}