我们通常总是把数组名和指针当成一回事,认为他们都是地址.
是地址没错, 然而他们之间的一个本质区别就是: 指针是专门存放地址值的一个字长数据(目前通常是32位), 它有专门的内存空间 ; 而数组名就不然了, 它在被当作参数传递时, 把这个名称转化为该数组首字节所在内存空间的地址, 数组名本身并不占有内存空间.
具体一个例子来讲:
对file1.c:
char buffer[128]="12345678";
//内存分配情况是: buffer被分配128字节的空间, 并被初始化为:0x 31323334 35363738 00000000 ...
//后116字节也全是0
对file2.c
如果是:
extern char * buffer;
int main()
{
printf("%x\n", buffer); //A
printf("%s\n", buffer); //B
int 0;
}
编译运行你会发现如下结果:
Administrator@dni-yinjie ~
$ gcc file1.c file2.c
Administrator@dni-yinjie ~
$ ./a.exe
34333231
Segmentation fault (core dumped)
如果把file2.c改成:
extern char * buffer;
int main()
{
printf("%x\n", &buffer); //C
printf("%s\n", &buffer); //D
int 0;
}
编译运行你会发现如下结果:
Administrator@dni-yinjie ~
$ gcc file1.c file2.c
Administrator@dni-yinjie ~
$ ./a.exe
402000
12345678
那么对于这两种完全不同的结果:
printf()函数的输出, 究竟是传进来的参数地址值还是地址所指向的内存空间值, 取决于格式串和传进来的参数地址.
buffer本身只是一个数组名称. 然而在file2.c中extern char * buffer; 语句确把buffer转义成了一个指针变量. 这个指针变量和数组前四个字节肯定是同一内存空间了
那么这个指针变量的4个字节的内容便是0x31323334(按地址从低到高书写, 如果当作整型数据打印且为little endian的话, 应该是0x34333231). 在其后出现的buffer均被看作指针来处理了. 这样一来解释这里出现的几种怪怪现象就不难了.
对于情况A: printf("%x\n", buffer); 对应输出是: 0x34333231 //输出变量buffer的值, 这个较简单.
对于情况B: printf("%s\n", buffer); 对应输出是: Segmentation fault (core dumped)
//它想输出地址0x34333231处的内容. (字符串"12345678"放在地址0x00402000处呢.) 你说它能访问么? 能才怪
对于情况C: printf("%x\n", &buffer); 对应输出是: 402000 = 0x00402000 这是啥玩意? buffer的地址呗, buffer的地址不就是数组的首地址么?
对于情况D: printf("%s\n", &buffer); 对应输出是: 12345678 哎呀, 妈呀.终于对了. 不容易啊~.~
对于A和B, 传进来的都是buffer(变量buffer的值=0x34333231), printf()可只把它看作地址哦.
对于C和D, 传进来的都是&buffer (变量buffer的地址=数组首地址=0x00402000), 碰到%x则输出地址本身0x00402000; 而碰到%s则输出地址所指向的内存处的字串"12345678". printf() 可不管你传来的是啥玩意呢, 只要是地址就行, 然后根据我的格式串来选择输出你这个地址本身呢还是你这个地址所指向的内容.
阅读(761) | 评论(0) | 转发(0) |