数组和指针,相信大部分人会认为这是基本上相同的东西,可以互相交换使用。假如你有这种思想,那将为你后续的bug埋下伏笔。
数组和指针的区别在多文件,extern外部变量时表达得淋漓尽致,只要不是类型一一对应的,都将会出错。
假如运行直接内存错误挂掉了,你将庆幸问题暴露出来了。假如你使用的是下文所指的第三种第四种情况,那就没有那么庆幸了。bug已经悄悄的在你身边不定时的准备爆发了。
以下是一段示例程序,将帮助你理解:
a.cpp
//声明变量
int xx[100];
int *x = xx;
int y[100];
int aa[100];
int *a = aa;
int b[100];
b.cpp
//主文件
extern int aa[];
extern int xx[];
//session 1:正常使用,都是正确的
extern int *x;
extern int y[];
//session 2:
extern int a[];
extern int *b;
int main(int argc, char* argv[])
{
printf("Hello World!/n");
//session 1:指针正常使用,没有问题
*x = 10;
printf("%d/n", *x);
//session 2:数组正常使用,没有问题
y[0] = 10;
printf("%d/n", y[0]);
//session 3:原本定义为:int aa[100]; int *a = aa;现在解释为a[],没有问题
//因为原本就将a定义为int *,所以在使用a[0]=10时,编译器会将a地址(即指针a的地址),
//所存的内容(即aa的地址),加上偏移量作为左值。效果跟aa[0]是一致的
printf("aa: %d a:%d/n", aa, a[0]);
a[0] = 10;
printf("%d/n", a[0]);
//session 4; 但是如果使用a[1]的话,那情况就改变了,a[1],编译器会将a的地址(即指针a的地址),
//再加上1个步长,即变成了int *a的下一个指针的位置,所指的地址,作为左值
//明显,这是一个野指针,因为那块地址并未分配出去。
printf("aa: %d a[1]:%d/n", aa, a[1]);
a[1] = 10;
printf("%d/n", a[1]);
//session 5:原本定义为:int b[100]; 先解释为 *b,然后使用b[],出现内存错误
//因为原先就将b定义 int b[],但是extern时,解释为int *,所以在使用b[]时,
//编译器会将b所指向的内存的内容取出(这部分本来就是数组元素b[0]的内容),
//再加上偏移地址,最终地址变成将原本b[0]的内容+偏移地址,
//再取出最终地址的内容,那么结果出错是必然的
b[0] = 10;
printf("%d/n", b[0]);
//session 6:
char *p = "breakfruit";//对于字符串常量是一个例外,即给指针分配了自身内存,且为指针所指对象分配了空间
//但是明显,对于其他情况却没有那么幸运了。
//且字符串常量将不能被修改
char a_p[] = "gooseberry";//同样,数组的字符串却可以修改
strncpy(a_p, "black", 5);//改变字符串内容
printf("%s/n", a_p);
//conclusion :多文件声明时,最好的方法必然是原先定义的是指针,就使用 extern 指针
//定义的是数组,就使用extern 数组,即一一对应关系。
//否则,如果交叉使用,最终必然都会引起错误
return 0;
}