之前有在外面面试,遇到一题如下:
filea.c char *p = "abcdefg"; fileb.c extern char p[]; printf("p[0]=%d ", 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 ", (unsigned int)str, str[0], str[1], str[2]); printf("str2 "); 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地址空间的值。
结论:使用声明和定义要匹配。