c语言数组和指针删除,C语言中数组和指针--数组的退化

本文通过分析C语言代码及汇编实现,探讨了数组名在作为函数参数时如何退化为指针,以及在不同情境下数组名、指针变量和数组元素地址的区别。作者通过实例展示了在函数调用中,数组名相当于数组首元素的地址,而当作为参数传递时,数组名失去其数组特性,表现得如同指针。
摘要由CSDN通过智能技术生成

前段时间闲来看了下《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变量本身的地址,到//这个地址里面取的内容,则就是数组的起始地址的内容.

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值