C语言中数组和指针--数组的退化

前段时间闲来看了下《c专家编程》这本书,总天来说写得不错,就是省略了些东西,当时没搞明白--数组和指针的纠结关系,最近写了几句代码测试了下,顿时豁然开朗...

 

我写了段测试代码:

#include<stdio.h> void func1(char str[]) { char *ptr = str; char str1[3] = {'s','w','v'}; printf("***str1's neirong:%x/n",str1); printf("***str1's addr:%x/n",&str1); //上面弄个局部变量数组做为对比 //下面就是做为函数参数的数组的变化 printf("*******************************/n"); printf("***str's addr:%x/n",&str); printf("***str's neirong:%x/n",str); printf("***str[0]'s addr:%x/n",&str[0]); printf("***str[0]'s neirong:%c/n",str[0]); printf("***ptr's addr:%x/n",&ptr); printf("***ptr's neirong:%x/n",ptr); } int main() { char str[5] = {'a','b','c','d','e'}; func1(str); return 0; }

 

下面是对应的汇编代码:

.file "array.c" .section .rodata .LC0: .string "***str1's neirong:%x/n" .LC1: .string "***str1's addr:%x/n" .LC2: .string "***str's addr:%x/n" .LC3: .string "***str's neirong:%x/n" .LC4: .string "***str[0]'s addr:%x/n" .LC5: .string "***str[0]'s neirong:%x/n" .LC6: .string "***ptr's addr:%x/n" .LC7: .string "***ptr's neirong:%x/n" .text .globl func1 .type func1, @function func1: pushl %ebp movl %esp, %ebp subl $24, %esp movl 8(%ebp), %eax movl %eax, -4(%ebp) movb $115, -7(%ebp) movb $119, -6(%ebp) movb $118, -5(%ebp) subl $8, %esp leal -7(%ebp), %eax pushl %eax pushl $.LC0 call printf addl $16, %esp subl $8, %esp leal -7(%ebp), %eax pushl %eax pushl $.LC1 call printf addl $16, %esp subl $8, %esp leal 8(%ebp), %eax pushl %eax pushl $.LC2 call printf addl $16, %esp movl 8(%ebp), %eax subl $8, %esp pushl %eax pushl $.LC3 call printf addl $16, %esp movl 8(%ebp), %eax subl $8, %esp pushl %eax pushl $.LC4 call printf addl $16, %esp movl 8(%ebp), %eax movb (%eax), %al movsbl %al,%eax subl $8, %esp pushl %eax pushl $.LC5 call printf addl $16, %esp subl $8, %esp leal -4(%ebp), %eax pushl %eax pushl $.LC6 call printf addl $16, %esp movl -4(%ebp), %eax subl $8, %esp pushl %eax pushl $.LC7 call printf addl $16, %esp leave ret .size func1, .-func1 .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $20, %esp movb $97, -9(%ebp) movb $98, -8(%ebp) movb $99, -7(%ebp) movb $100, -6(%ebp) movb $101, -5(%ebp) subl $12, %esp leal -9(%ebp), %eax pushl %eax call func1 addl $16, %esp movl $0, %eax movl -4(%ebp), %ecx leave leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.1.2" .section .note.GNU-stack,"",@progbits

下面是这段代码的输出:

***str1's neirong:bfe381f1 ***str1's addr:bfe381f1 //这里,str1和&str1的值是完全一样的,所以在数组做为局部变量的时候,//数组名就是数组的起始地址,也就是在编译器中的符号表中数组名str1直//接对应的地址就是数组的起始地址,并不是指针的形式. ***str's addr:bfe38200 ***str's neirong:bfe3821f ***str[0]'s addr:bfe3821f ***str[0]'s neirong:61 ***ptr's addr:bfe381f4 ***ptr's neirong:bfe3821f //这里就是作为函数形参传递的时候,str和&str[0]以及ptr的值都是以//一样的,这里str已经退化成了指针,就需要按照指针的解析来对数组名//进行解析,而str本身的地址&str则是和&ptr一样,具有自己的地址的,//因此在这里,str和ptr是一样的,已经变成了一个指针.也就是说在编//译器中的符号表中,有与str对应的地址,就是str变量本身的地址,到//这个地址里面取的内容,则就是数组的起始地址的内容.

 

其实这里得出的结论只有一句话:在数组名做为函数参数和用于表达式中的时候,数组名就退化成了指针,这个退化是完全意义上的,即数组名实际上就是成了一个指针变量,可以完全用解析指针的方法来解析数组名.

你可能感兴趣的:(编程,c,汇编,测试,语言,编译器)