熟悉C里指针的朋友来帮我检查一下这段代码的注释:关于数组名和指针互相转换的

slowgrace 2009-09-29 07:05:52
熟悉C里指针的朋友来帮我检查一下这段代码的注释,好么?

主要是依据以下关于数组名和指针互相转换的道理:

(1)当一个数组标识符出现在表达式中,这个标识符的类型就从“某种类型T的数组”转换成“指向类型T的指针”,而且它的值就等于数组第一个元素的地址。并且这个指针是个常量指针,不可改变其值的。
(2)但是当数组标识符被用作sizeof和取址(&)操作的操作数时,sizeof返回的是整个数组的大小,而取址操作返回的是指向数组的指针(而不是指向一个值为数组头元素地址的指针的指针)。
(3)既然数组标示符在表达式中被“转换为”指针用,那对于二维数组又是什么情况呢?对于一个二维数组如:int a[3][3], a是指向一维数组的指针;当进行一次a[i]这样的运算后所得到的值是一个指针,其所指对象是一个int类型,[]运算符的作用除了变址,还将一个行指针变为一个列指针;同理当进行一次&a[i]这样的运算后所得到的指针又是一个指向一维数组的指针,即行指针。


	int a[3] = {1, 2, 3};
char **s;
char p[3][5] = {{'a', 'b', 'c', 'c','\0'},
{'d', 'e', 'f', 'f','\0'},
{'\0', '\0', '\0', '\0', '\0'}};

s = (char **)p;

printf("a: %p\n", a); //0012FF74:a在表达式里被转为int *,指向a[0]
printf("*&a: %p\n", *&a); //0012FF74:a首先是int *,对一个指针型变量取地址之后再取值就是它本身,所以结果同上一行
printf("&a: %p\n", &a); //0012FF74:&a返回的是数组指针,因为数组的地址同a[0]的地址,所以结果同上一行
printf("&a[0]: %p\n", &a[0]); //0012FF74:打印的a[0]同学的地址,所以结果同上一行

printf("a[0]: %p\n", a[0]); //00000001:把a[0]的值以双字的形式打印出来
printf("*a: %p\n", *a); //00000001:把*a里的值当指针打印出其地址。记住a在表达式里被转为int *,指向a[0],
//所以*a其实就是a[0],所以结果同上一行。

printf("p: %p\n", p); //0012FF60:p是指向一维数组的指针,这个语句是要打印该一维数组的地址,等于p[0][0]的地址
printf("&p: %p\n", &p); //0012FF60:打印二维数组p的地址,等于p[0][0]的地址,所以结果同上一行
printf("p[0]: %p\n", p[0]); //0012FF60:p[0]是一维数组的数组名,出现在表达式中作为char *使用。
//这个语句是要打印p[0]所指向的字符的地址,也就是p[0][0]的地址,所以结果同上一行


printf("&p[0]: %p\n", &p[0]); //0012FF60:打印一维数组p[0]的地址,等于p[0][0]的地址,所以结果同上一行
printf("p[1]: %p\n", p[1]); //0012FF65:一维数组名p[1]作为char *,指向p[1][0]。
//这个语句是要打印p[1][0]的地址,该地址等于p[0][0]的地址加5


printf("p[2]: %p\n", p[2]); //0012FF6A:一维数组名p[2]作为char *,指向p[2][0]。
//这个语句是要打印p[2][0]的地址,该地址等于p[1][0]的地址加5


printf("&p[0][0]: %p\n", &p[0][0]); //0012FF60:打印p[0][0]的地址
printf("&p[1][0]: %p\n", &p[1][0]); //0012FF65:打印p[1][0]的地址
printf("&p[2][0]: %p\n", &p[2][0]); //0012FF6A:打印p[2][0]的地址

printf("s的值: %p\n", s); //0012FF60:s的值等于p的值,因此等于p[0][0]的地址;
printf("s+1的值: %p\n", s+1); //0012FF64:s是指针的指针,因此s+1等于s的地址加4字节(32位系统);
printf("*s: %p\n", *s); //63636261:s是char **,*s就是char*。
//因此这句意思是把s指向的内存取4个字节(也就是p[0][0]到p[0][]3)作为char*,打印其值。


printf("以s的值为地址的内存里的内容:%s \n", s); //abcc :从s所指向的地址取出连续内存(遇到'\0'为止)作为字符串来打印。
printf("以s+1的值为地址的内存里的内容:%s \n", s+1); // :从s+1所指向的地址取字符串来打印。
...全文
713 69 打赏 收藏 转发到动态 举报
写回复
用AI写文章
69 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tiger_Zhao 2009-10-09
  • 打赏
  • 举报
回复
讨论了老半天,我们讲的“左值/右值”根本不是同一个。
Tiger_Zhao 2009-10-09
  • 打赏
  • 举报
回复
翻译的问题,看这个帖子114楼回复。
slowgrace 2009-10-09
  • 打赏
  • 举报
回复
b和i都是左值,不管它出现在左边还是右边。

用于判断“能否放在等号左边”,只是左值概念的最常见应用和最初的来源,但不是它的全部应用,更不是它的定义

这个帖子49楼的左值的定义。
Tiger_Zhao 2009-10-09
  • 打赏
  • 举报
回复
其实左值/右值是很简单的事,只是 C 的“压缩”语法把它搞复杂了。
比如下面的 b 是左值还是右值?
a=b=c


还有64楼讲 i++ 和 ++i 的区别,其实作为独立语句时是等价的;当然出现在表达式中,“展开”的语句会不一样。
还是一句话,具体场景具体分析。如果不能“展开”成带 = 的表达式,就无所谓左值/右值。
飞天御剑流 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 56 楼 slowgrace 的回复:]
不过的话,好玩的一点在于,如果右值是指“表达式的值”,而左值是“一种表达式”,那么非左值表达式是啥?

比如:

int a;

&a是啥?

它是个表达式,不是表达式的值,因此它不是右值;

另外,据说它也不是左值表达式。

它既不是左值,也不是右值,它是啥呢?
[/Quote]

&a的结果是一个右值,&a是一个右值表达式,因为&a的结果不是对象。
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 57 楼 tiger_zhao 的回复:]
左值/右值首先看出现的等号的哪边,没有等号是不能判定左右的。
[/Quote]

那些制定标准的同学们貌似在这一点上已经走得很远了,和最初的左右已经大大不相同了……

另外,你是上班了还是上班了?
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 58 楼 hpsmouse 的回复:]
晕……原来“the result of an expression”和“the value of an expression”还不是一回事……
[/Quote]

晕++,你从哪里看出来的?
2009-10-07
  • 打赏
  • 举报
回复
晕……原来“the result of an expression”和“the value of an expression”还不是一回事……
Tiger_Zhao 2009-10-07
  • 打赏
  • 举报
回复
左值/右值首先看出现的等号的哪边,没有等号是不能判定左右的。
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
不过的话,好玩的一点在于,如果右值是指“表达式的值”,而左值是“一种表达式”,那么非左值表达式是啥?

比如:

int a;

&a是啥?

它是个表达式,不是表达式的值,因此它不是右值;

另外,据说它也不是左值表达式。

它既不是左值,也不是右值,它是啥呢?
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
谢谢,有了这个定义,许多争论就直接可以消停了。
飞天御剑流 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 53 楼 slowgrace 的回复:]
引用 47 楼 supermegaboy 的回复:
在C中,右值的定义就是表达式的值。


这个出处在哪里?
[/Quote]

C90和C99分别在第36页和46页的脚注里进行了说明:

What is sometimes called ‘‘rvalue’’ is in this International Standard described
as the ‘‘value of an expression’’.
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 47 楼 supermegaboy 的回复:]
在C中,右值的定义就是表达式的值。
[/Quote]

这个出处在哪里
slowgrace 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 63 楼 hpsmouse 的回复:]
引用 54 楼 supermegaboy 的回复:
C90和C99分别在第36页和46页的脚注里进行了说明:

    What is sometimes called ‘‘rvalue’’ is in this International Standard described
as the ‘‘value of an expression’’.

然后,在 C99 的 79 页,
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating theobject.
既然“the value of an expression”是 rvalue,这里这个“the result”是个 lvalue,那么“the value”应该不是“the result”……
[/Quote]

推理正确。++(晕++)
2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 62 楼 tiger_zhao 的回复:]
引用 60 楼 slowgrace 的回复:那些制定标准的同学们貌似在这一点上已经走得很远了,和最初的左右已经大大不相同了……
不要被 C “简洁”的语法迷惑了。
比如看到 i++,自己翻译为 i=i+1,就很容易区分左值/右值了。
[/Quote]
貌似 i++ 不可以翻译为 i=i+1,++i 才可以……
2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 59 楼 slowgrace 的回复:]
引用 58 楼 hpsmouse 的回复:
晕……原来“the result of an expression”和“the value of an expression”还不是一回事……


晕++,你从哪里看出来的?
[/Quote]
[Quote=引用 54 楼 supermegaboy 的回复:]
C90和C99分别在第36页和46页的脚注里进行了说明:

    What is sometimes called ‘‘rvalue’’ is in this International Standard described
as the ‘‘value of an expression’’.
[/Quote]
然后,在 C99 的 79 页,
The unary * operator denotes indirection. If the operand points to a function, the result is
a function designator; if it points to an object, the result is an lvalue designating the
object.

既然“the value of an expression”是 rvalue,这里这个“the result”是个 lvalue,那么“the value”应该不是“the result”……
Tiger_Zhao 2009-10-07
  • 打赏
  • 举报
回复
[Quote=引用 60 楼 slowgrace 的回复:]那些制定标准的同学们貌似在这一点上已经走得很远了,和最初的左右已经大大不相同了……[/Quote]
不要被 C “简洁”的语法迷惑了。
比如看到 i++,自己翻译为 i=i+1,就很容易区分左值/右值了。
pmerOFc 2009-10-06
  • 打赏
  • 举报
回复
[Quote=引用 51 楼 supermegaboy 的回复:]
C里的左值转换还只是个雏形,但C++由于重载解析的需要,把它正规化了。
[/Quote]

这个我就不太懂了
飞天御剑流 2009-10-06
  • 打赏
  • 举报
回复
C里的左值转换还只是个雏形,但C++由于重载解析的需要,把它正规化了。
pmerOFc 2009-10-06
  • 打赏
  • 举报
回复
[Quote=引用 49 楼 supermegaboy 的回复:]
C99的内容,C90一样。

6.3.2.1 Lvalues, arrays, and function designators
    Except when it is the operand of the sizeof operator, the unary & operator, the ++operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue).


6.5.16 Assignment operators
    An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
[/Quote]

非常感谢!

说句心里话
我很不欣赏标准的这段话
觉得可以动用一下奥卡姆剃刀

会不会是考虑到编译器的作者
标准才这样写
如果对于程序员
可以不这样说而换成一种更简洁的说法呢
(我这个考虑同样针对你的数组名的convert)
加载更多回复(49)

69,383

社区成员

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

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