函数参数数组退化为指针后,指针地址和"指针首元素"的地址不一致.

winner8080 2010-07-16 01:55:45
有如下代码:

char ga[] = "abcdefghijklm"; //全局数组

void my_pointer_func(char *pa)
{
printf("addr of ptr param = %x \n", &pa);//打印pa的地址
printf("addr (pa[0]) = %x\n", &(pa[0])); //打印pa的第一个元素的地址
printf("addr (pa[1]) = %x\n", &(pa[1]));

printf("++pa = %x\n\n", ++pa);
}


void main()
{
printf("addr of global array =%x\n", &ga); //打印ga的地址,

printf("addr (ga[0]) = %x\n", &(ga[0]));
printf("addr (ga[1]) = %x\n\n\n", &(ga[1]));

my_pointer_func(ga);//把数组当作参数

system("pause");
}


我在VC6下,打印出内容如下:

addr of global array =427340
addr (ga[0]) = 427340
addr (ga[1]) = 427341

addr of ptr param = 12ff30 //注意看这里
addr (pa[0]) = 427340
addr (pa[1]) = 427341
++pa = 427341

请按任意键继续. . .



ga是一个全局数组,在调用函数的时候为了防止发生复制数组的情况所以转化为指针pa,
所以这个pa的值就是数组ga的地址0x00427340,

那么函数中我又取pa的地址,&pa,此时的值是0x0012ff30,查看内存发现这个0x0012ff30中保存的值正好是0x00427340.

现在我不明白的事,地址0x0012ff30上存储的就是指针pa,然后pa指向地址0x00427340.
编译器怎么确定的这个地址0x0012ff30呢?
我这么理解对吗?
...全文
382 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
mijuewnpu 2011-09-05
  • 打赏
  • 举报
回复
不错、不错,分析的很透彻。。。
raceant 2011-03-22
  • 打赏
  • 举报
回复
支持3楼
winner8080 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 frankhb1989 的回复:]

在一元操作符&之后的数组标识符表示整个数组对象而不是指向数组首个元素的指针。ga、ga + 0和&ga[0]等价,但&ga和ga语义上不等价。&ga和ga的值相等是数组标识符作为一元&的操作数的特殊情况。规定这个相等关系的原因是,这个值表示一个地址,既可以表示整个数组的首地址(&ga),又可以表示数组首个元素的地址(ga + 0、&ga[0……
[/Quote]

比较精辟
winner8080 2010-07-16
  • 打赏
  • 举报
回复
楼上的怎么和4楼的回答一模一样?
fancanqin 2010-07-16
  • 打赏
  • 举报
回复
&pa只是pa这个变量的地址,而pa是这个指针指向的地址
pa的地址,与pa指向的地址,当然是不一样的
这就是指针类型的特点

你可以再用
char *pa1 = pa;
char *pa2 = pa;
你会发现,pa1,pa2,指向的都是0x00427340.
但是&pa1,&pa2都是不一样的
cao_julians 2010-07-16
  • 打赏
  • 举报
回复
误矣误矣!用%x输出的是输出值的十六进制表示,而有差异的两个值,一个是数组ga的地址,一个是形参变量pa自己的地址(不是它接受到的实参地址),它们肯定是不一样了!
正确的方法是用%p格式,
printf("addr of ptr param = %p \n", pa);//
printf("addr of global array =%p\n", ga);
chengshuangshuang 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 b_duan 的回复:]
现在我不明白的事,地址0x0012ff30上存储的就是指针pa,然后pa指向地址0x00427340.
编译器怎么确定的这个地址0x0012ff30呢?

---个人猜测应该运行进程时,分配的吧,这个0x0012ff30不一定每次都是他吧。
[/Quote]
编绎的时候就确定了,而且不管运行多少次都是0x0012ff30,因为全局变量,是在内存的静态存储空间分配的地址。
PG 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用楼主 winner8080 的回复:]
现在我不明白的事,地址0x0012ff30上存储的就是指针pa,然后pa指向地址0x00427340.
编译器怎么确定的这个地址0x0012ff30呢?
我这么理解对吗?
[/Quote]

1.你已经写出OxXXXXX这样的东西了,机器保存的是机器码,可以理解pa只是地址0x0012ff30的另外一个名称,而地址0x0012ff30上存储的内容(相当于你此次运行来讲)是0x00427340。

2.为什么说”相对于你此次运行的结果来讲“?因为每次运行这个pa里面的内容都可能是不同的,更直接地讲pa=&x,&x没次编译运行后他所分配的地址都可能不同。这就说明,编译器不需要去确定你pa里面到底是什么东西,他只需知道,你的pa是什么东西就OK了(如你的例子中pa是一个char型的指针,他就知道怎样去解析里面的东西了)。
b_duan 2010-07-16
  • 打赏
  • 举报
回复
现在我不明白的事,地址0x0012ff30上存储的就是指针pa,然后pa指向地址0x00427340.
编译器怎么确定的这个地址0x0012ff30呢?

---个人猜测应该运行进程时,分配的吧,这个0x0012ff30不一定每次都是他吧。
luciferisnotsatan 2010-07-16
  • 打赏
  • 举报
回复
打印的是pa这个指针自身所在的地址。而这个地址里的内容是ga所在的地址
krela 2010-07-16
  • 打赏
  • 举报
回复
学习学习~~~~
FrankHB1989 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 huan0911612504 的回复:]
而且我发现从一开始地址 0x0012fef8 中就存了地址 0x00426a30
这是为什么呢?
[/Quote]
非引用的函数参数传递是按值复制的,0x00426a30是my_pointer_func(ga)传递进去的,并不是程序一开始这个地址就储存了这个值。
由于ga的类型是char[],而形式参数的类型为char*,元素类型一致,于是ga就退化为char*类型,值被复制给pa了。这里ga是作为&ga[0]的含义,并不表示整个数组,否则参数传递过程中的(复制)语义就有问题了(数组“变成”了指针)。
另外,打印指针最好用%p,不要用%x。
liuwei2500 2010-07-16
  • 打赏
  • 举报
回复
我来回答下,不对的话请纠正:
因为是一个全局的数组,在定义的初期已经为数组开辟了一段内存,那么在main函数里面是用&ga,这样就是取得了数组中第一个成员的地址即数组的首地址,当调用void my_pointer_func(char *pa)函数的时候,实则是定义了一个指针pa指向了ga数组,要注意pa本身就是一个指针,那么他就应该有相应的内存地址,你去&pa实则是取了指针pa在内存中的地址,而并不是他所执行的ga数组的头地址。
zjf30366 2010-07-16
  • 打赏
  • 举报
回复
指针里存放的是元素的首地址。。&ga表示的是取ga变量的地址。。
zjf30366 2010-07-16
  • 打赏
  • 举报
回复
其实是这样的

char ga[] = "abcdefghijklm"; //全局数组

void my_pointer_func(char *pa)
{
printf("addr of ptr param = %x \n", pa);//打印pa的地址 /***********************/
printf("addr (pa[0]) = %x\n", &(pa[0])); //打印pa的第一个元素的地址
printf("addr (pa[1]) = %x\n", &(pa[1]));

printf("++pa = %x\n\n", ++pa);
}


void main()
{
printf("addr of global array =%x\n", ga); //打印ga的地址,/***************************/

printf("addr (ga[0]) = %x\n", &(ga[0]));
printf("addr (ga[1]) = %x\n\n\n", &(ga[1]));

my_pointer_func(ga);//把数组当作参数

system("pause");
}
FrankHB1989 2010-07-16
  • 打赏
  • 举报
回复
关于数组标识符的特殊性在这里的用法,是标准委员会为了维护数组作为对象的左值语义的妥协(见《再再论指针》)。数组标识符的其它典型左值上下文还有:作为sizeof的操作数;定义数组时。这些情况下,数组标识符表示整个数组,而不是指向数组首个元素的指针。
仅仅是关于“数组名”的特例而已,和“指针类型的特点”“形参是分配在栈上的”没多大关系。为了简化问题起见,LZ可以在主函数中直接比较打印出来的一元&表达式和指针的值,不需要经过参数传递。
huan0911612504 2010-07-16
  • 打赏
  • 举报
回复
我按楼上的试了一下 代码为:

#include <stdio.h>
#include <stdlib.h>

char ga[] = "abcdefghijklm"; //全局数组

void my_pointer_func(char *pa)
{
printf("addr of ptr param = %x \n", &pa);//打印pa的地址
printf("addr of ptr param = %x \n", (int)pa);
printf("addr (pa[0]) = %x\n", &(pa[0])); //打印pa的第一个元素的地址
printf("addr (pa[1]) = %x\n", &(pa[1]));

printf("++pa = %x\n\n", ++pa);
}


void main()
{
printf("addr of global array =%x\n", &ga); //打印ga的地址,
printf("addr of ptr param = %x \n", (int)ga);
printf("addr (ga[0]) = %x\n", &(ga[0]));
printf("addr (ga[1]) = %x\n\n\n", &(ga[1]));

my_pointer_func(ga);//把数组当作参数

system("pause");
}


运行结果为:

而且我发现从一开始地址 0x0012fef8 中就存了地址 0x00426a30
这是为什么呢?
FrankHB1989 2010-07-16
  • 打赏
  • 举报
回复
在一元操作符&之后的数组标识符表示整个数组对象而不是指向数组首个元素的指针。ga、ga + 0和&ga[0]等价,但&ga和ga语义上不等价。&ga和ga的值相等是数组标识符作为一元&的操作数的特殊情况。规定这个相等关系的原因是,这个值表示一个地址,既可以表示整个数组的首地址(&ga),又可以表示数组首个元素的地址(ga + 0、&ga[0])。
而指针(无论是否是数组标识符传递参数时退化而来的)就不具有这个性质。对于指针的一元&运算,值是指针这个对象本身的地址。
因此LZ的&ga和&pa根本就不是一回事,指向的不是同一个对象(&ga指向整个数组ga,相当于指向ga[0],而&pa指向pa),自然结果不同。

winner8080 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 we_sky2008 的回复:]

C/C++ code

void my_pointer_func(char *pa)
{
printf("addr of ptr param = %x \n", &pa);//打印pa的地址,注意是形参的地址,形参是分配在栈上的,pa指向数组首元素,你可以打印pa查看下
printf("addr (pa[0]) = %x\n", &(pa[0]));
……
[/Quote]

通俗易懂
winner8080 2010-07-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 zhangweiit 的回复:]

&pa只是pa这个变量的地址,而pa是这个指针指向的地址
pa的地址,与pa指向的地址,当然是不一样的
这就是指针类型的特点

你可以再用
char *pa1 = pa;
char *pa2 = pa;
你会发现,pa1,pa2,指向的都是0x00427340.
但是&pa1,&pa2都是不一样的
[/Quote]

通俗易懂.
加载更多回复(5)

69,370

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧