之前有在外面面試,遇到一題如下:
filea.c char *p = "abcdefg"; fileb.c extern char p[]; printf("p[0]=%d\n", p[0]); result=?
當時只是糾結於printf中的%d打印char類型數據,會不會按地址將abcd這四個字節的數據打印出來,所以給出的答案是:0x61626364.
類似的還有這種做法:
filea.c char p[10]; fileb.c extern char p[]; extern char *p; p[0] = ?
上面這個char p[10], p只是個別名,下面的extern char *p提取p的地址可能是0,然后對p[0]賦值可能導致程序崩潰。
之后,回來查了些資料,寫了個代碼試了下:
filea.c
char *str = "abcdefg";
fileb.c
#include "stdio.h" extern char str[]; char *str2 = "abcdef"; void main(void) { int i = 0; printf("str1:addr=0x%08x, %d, %d, %d\n", (unsigned int)str, str[0], str[1], str[2]); printf("str2\n"); for(i = 0; i < sizeof(str2); i++) { printf("[%d]=%c ", i, str2[i]); } }
Makefile
objects = filea.o fileb.o hello:$(objects) gcc -o hello $(objects) filea.o: filea.c fileb.o: fileb.c clean: rm hello $(objects)
Result:
str:addr=0x00601048, -52, 6, 64 str2 [0]=a [1]=b [2]=c [3]=d [4]=e [5]=f [6]= [7]=s %
可以看出str的輸出並不是我們想要的。
為什么呢?
首先,關於指針和數組名
- 系統會為“指針名”分配4個字節的內存空間。存放指針的內存空間和該內存中存放的數據,前者為存放指針的地址,后者為存放有效數據(如abcdef)的地址。
- 而數組名則不會,數組名只是一塊存放數據地址空間的別名。
其次,由於在fileb.c中extern char str[]; str被申明為數組,那么str就是代表一塊地址空間的別名,也就是存放str指針地址空間的別名,而不是上面說道的有效數據的地址空間,所以str[0]只是存放abcdef地址空間的值。
結論:使用聲明和定義要匹配。