前段时间闲来看了下《c专家编程》这本书,总天来说写得不错,就是省略了些东西,当时没搞明白--数组和指针的纠结关系,最近写了几句代码测试了下,顿时豁然开朗...
我写了段测试代码:
#include
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
.typefunc1, @function
func1:
pushl%ebp
movl%esp, %ebp
subl$24, %esp
movl8(%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
callprintf
addl$16, %esp
subl$8, %esp
leal-7(%ebp), %eax
pushl%eax
pushl$.LC1
callprintf
addl$16, %esp
subl$8, %esp
leal8(%ebp), %eax
pushl%eax
pushl$.LC2
callprintf
addl$16, %esp
movl8(%ebp), %eax
subl$8, %esp
pushl%eax
pushl$.LC3
callprintf
addl$16, %esp
movl8(%ebp), %eax
subl$8, %esp
pushl%eax
pushl$.LC4
callprintf
addl$16, %esp
movl8(%ebp), %eax
movb(%eax), %al
movsbl%al,%eax
subl$8, %esp
pushl%eax
pushl$.LC5
callprintf
addl$16, %esp
subl$8, %esp
leal-4(%ebp), %eax
pushl%eax
pushl$.LC6
callprintf
addl$16, %esp
movl-4(%ebp), %eax
subl$8, %esp
pushl%eax
pushl$.LC7
callprintf
addl$16, %esp
leave
ret
.sizefunc1, .-func1
.globl main
.typemain, @function
main:
leal4(%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
callfunc1
addl$16, %esp
movl$0, %eax
movl-4(%ebp), %ecx
leave
leal-4(%ecx), %esp
ret
.sizemain, .-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变量本身的地址,到//这个地址里面取的内容,则就是数组的起始地址的内容.
其实这里得出的结论只有一句话:在数组名做为函数参数和用于表达式中的时候,数组名就退化成了指针,这个退化是完全意义上的,即数组名实际上就是成了一个指针变量,可以完全用解析指针的方法来解析数组名.