A *(*(p+i)+j) B *(p[i]+j)
C p[i*4+j] D *(a[i]+j)
求解释,~~~~(>_<)~~~~
57 个解决方案
#1
不做强转,题目编译能过?
#2
你可以编个程序测试下。
#3
答案选C,这是为什么?还有D为什么不行呢?不明白
#4
还是用赵老师的话回答你.
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#5
楼上是啥?我水平太次,看不懂啊。。。。。。
#6
指针的东西 复杂的我一般画个图。。
#7
有木有人正视一下俺的题啊。。。。太简单了么?你们都不屑回答??
#8
D也是对的,我认为啊
CD 都是对的
CD 都是对的
#9
a在内存中的状态是按顺序 a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], ..., a[3][3],
a[0]获得的是指向a[0][0]的指针,把它赋值给p后,想得到指向a[i][j]的指针就可以写p + i * 4 + j,获得其内容就是*(p + i * 4 + j)等价于p[i * 4 + j]
a[0]获得的是指向a[0][0]的指针,把它赋值给p后,想得到指向a[i][j]的指针就可以写p + i * 4 + j,获得其内容就是*(p + i * 4 + j)等价于p[i * 4 + j]
#10
D是错的,a[i]+j,实际等于a[i+j]...是不是这样?
#11
那D呢,我觉得D也可以啊
#12
D是对的...
建议楼主下次这样的题目直接写程序来试验...
建议楼主下次这样的题目直接写程序来试验...
#13
我编译过,cd都可以
#14
a[i]是一个行指针,其值为:第i个一维数组的首元素的地址
然后+j, 即a[i][j]
a[i][j] 反汇编估计是这样的:两步骤:1,定位到第i个一维数组的首元素的地址,2:偏移
所以cd都是对的
不对请指出
另外:楼主可以自行测试。。我没有测试
#15
我觉得对于这种问题,先在编译器上试下,然后自己有些思考,然后查下书,这样对于知识的理解就会更深
#16
好感动,我明白 了,刚自学C不久,有点迷糊,谢谢各位的指点啊!(*^__^*)
#17
还是用赵老师的话回答你.
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#18
蛋疼的东西~~
#19
赵老师是谁呀
#20
嗯……一时半会没反应过来
#21
学聪明了,,直接把题目写成小女子了。。。。
哈哈哈哈哈哈。。。
目前没看到详细且正确的答案。。。
答案是CD
哈哈哈哈哈哈。。。
目前没看到详细且正确的答案。。。
答案是CD
#22
哈哈,那你有何高见呐?(*^__^*)
#23
是否可以认为p=&a[0][0]?
#24
纠正一下,我犯了错误,还是基础不扎实
a[i]不是行指针,是数组名,
在表达式汇中,自动转位a[i]的首元素的地址
对于&a[i]才是获得行指针
a[i]不是行指针,是数组名,
在表达式汇中,自动转位a[i]的首元素的地址
对于&a[i]才是获得行指针
#25
a[i]等价&a[i][0],*(a[i] + j)就是*(&a[i][0] + j)也就是a[i][j]
数组除了取地址和取长度运算都是自动转指针的
数组除了取地址和取长度运算都是自动转指针的
#26
a[i]就是数组名
#27
那我得告诉你,下标运算只能作用于指针(因为是*的等价运算)... 如果a[i]不能给出一个指针右值a[i][0]就是非法的。
#28
不知道你想表达什么,大概猜测:你是说a[i] 不是数组名???
如果不是数组名,请问他是什么???
int a[3][4];
int(*p)[4]=&a[0];
你试试这代码,对不对,我的vs2010是对的
再比如:
int a[]={1,35,4356,90};
int(*p)[4]=&a;
a[0][1],它的值是35
如果不是数组名,请问他是什么???
int a[3][4];
int(*p)[4]=&a[0];
你试试这代码,对不对,我的vs2010是对的
再比如:
int a[]={1,35,4356,90};
int(*p)[4]=&a;
a[0][1],它的值是35
#29
其实我很想吐槽“数组名到底是个什么玩意”... 表达式里其实只有左右值
#include <stdio.h>
int a[2][2] = {1, 2, 3, 4};
int main()
{
int *p0 = a[0];
int (*p1)[2] = &a[0];
printf("%d %d\n", p0[3], p1[1][1]);
}
#30
注意上面的a[0]和&a[0]地址一样但是类型不一样,但参与运算的时候都是指针。
#31
a[i]不是数组名。它是一个表达式,这个表达式的类型是数组类型。
#32
表示学习了,C语言的指针已经有段时间没碰了。现在学C#的委托,这个类似于指针吧。
#33
比如用二维的字符数组存放多个字符串:
char s[3][40]={"Hello","How are you?","I'm fine, thank you."};
那么 cout<<s[0]; 显示的是 Hello
cout<<s[1]; 显示的是 How are you?
cout<<s[2]; 显示的是 I'm fine, thank you.
说明 s[0]、s[1]、s[2]都是一个字符指针,即 char*,
s[0] 指向Hello中的字符“H”
s[1] 指向How中的字符“H”
s[2] 指向字符“I”
char s[3][40]={"Hello","How are you?","I'm fine, thank you."};
那么 cout<<s[0]; 显示的是 Hello
cout<<s[1]; 显示的是 How are you?
cout<<s[2]; 显示的是 I'm fine, thank you.
说明 s[0]、s[1]、s[2]都是一个字符指针,即 char*,
s[0] 指向Hello中的字符“H”
s[1] 指向How中的字符“H”
s[2] 指向字符“I”
#34
左值和右值的定义和区别,能解释一下吗?
#35
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
因为 *(p+i) 相当于 p[i],所以A\B是一样的。因为*(p+i)+j的结果是整型数据,所以再运用取内容运算符*是错误的。A B 都是错误的。
因为数组在内存中按行连续存储的,所以也可以按一维数组的形式来访问,所以C是对的
把a[i]看成p,选项D就变成了*(p+j),可转换成p[j],再把p换成a[i],就是a[i][j],所以D也是对的。
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
因为 *(p+i) 相当于 p[i],所以A\B是一样的。因为*(p+i)+j的结果是整型数据,所以再运用取内容运算符*是错误的。A B 都是错误的。
因为数组在内存中按行连续存储的,所以也可以按一维数组的形式来访问,所以C是对的
把a[i]看成p,选项D就变成了*(p+j),可转换成p[j],再把p换成a[i],就是a[i][j],所以D也是对的。
#36
严格来说只有D是对的,详细可以参考《C陷阱与缺陷》第三章3.1数组与指针45页。
由于未声明是32位系统故严格来说C不正确,中的i*4,4是32位系统int所占字节。
由于未声明是32位系统故严格来说C不正确,中的i*4,4是32位系统int所占字节。
#37
答案肯定选D
C这个答案严格来说有局限性,牵扯到系统和编译器。 其只对32位程序成立。
C这个答案严格来说有局限性,牵扯到系统和编译器。 其只对32位程序成立。
#38
CD 正解
无法解释 请调试
无法解释 请调试
#39
++
#40
标准答案:D。
原因楼上的多说了。。
原因楼上的多说了。。
#41
答案c,不完全对。这里默认int 为4字节。
#42
答案C。不完全对int 这里默认是4字节。。。
#43
C和D都是正确的,但是C中的i*4这个4并不是代表4字节int型,而是表示a[4][4]列元素大小。
int *p=a[0]是将a的第0行的首地址赋于指针p,等效于p = &a[0][0]和p = a;
p[i*4+j]是p指向的地址偏移i*4+j个元素的值,它和a[i*4+j]是一样的。
*(a[i]+j) 其中a[i]+j是第i行的首地址加上列偏移量j,也就是i*4+j的地址,*(a[i]+j)就是这个地址的值。
#44
小女子的问题很快就有人答了,哎,世道啊....
#45
我不同意“中的i*4,4是32位系统int所占字节”,这里的4指列数的4,跟机器无关,只与数组的列有关,若数组a为5列,则a[i][j] = p[i*5 + j]
#46
我也是这么想的, p与a[0]的类型是不一样的, 用C++中的typeid可以明确知道的
但用code::blocks(gcc4.6.1)居然能编译通过, 真扯!
楼主请先看上面这个分析
再看上面这个说明(其实我也才听说有这么回事)
如果题目是这样:
int a[4][4];
int (*p)[4] = a;
那么我和1楼就不会说题目编译不过了, 而且这时的答案为ABD
#47
如果你觉得我说得对
请给1楼, 35楼, 36楼多给点分, 也记得给我1分, 这是我帮你总结的苦劳分
请给1楼, 35楼, 36楼多给点分, 也记得给我1分, 这是我帮你总结的苦劳分
#48
zhao4zhong1:
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#49
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
1: int a[4][4];
2: int *p=a[0];
3: int i=2;j=3,v;
4: void main() {
//0401000 55 push ebp
//0401001 8B EC mov ebp,esp
//0401003 83 EC 40 sub esp,40h
//0401006 53 push ebx
//0401007 56 push esi
//0401008 57 push edi
5: v=a[i][j];
//0401009 A1 34 E0 40 00 mov eax,[i (0040e034)]
//040100E C1 E0 04 shl eax,4
//0401011 8B 0D 38 E0 40 00 mov ecx,dword ptr [j (0040e038)]
//0401017 8B 94 88 00 EB 40 00 mov edx,dword ptr [eax+ecx*4+40EB00h]
//040101E 89 15 40 EB 40 00 mov dword ptr [v (0040eb40)],edx
6: //v=*(*(p+i)+j);//A error C2100: illegal indirec
7: //v=*(p[i]+j); //B error C2100: illegal indirec
8: v=p[i*4+j]; //C
//0401024 A1 34 E0 40 00 mov eax,[i (0040e034)]
//0401029 8B 0D 38 E0 40 00 mov ecx,dword ptr [j (0040e038)]
//040102F 8D 14 81 lea edx,[ecx+eax*4]
//0401032 A1 30 E0 40 00 mov eax,[p (0040e030)]
//0401037 8B 0C 90 mov ecx,dword ptr [eax+edx*4]
//040103A 89 0D 40 EB 40 00 mov dword ptr [v (0040eb40)],ecx
9: v=*(a[i]+j); //D
//0401040 8B 15 34 E0 40 00 mov edx,dword ptr [i (0040e034)]
//0401046 C1 E2 04 shl edx,4
//0401049 A1 38 E0 40 00 mov eax,[j (0040e038)]
//040104E 8B 8C 82 00 EB 40 00 mov ecx,dword ptr [edx+eax*4+40EB00h]
//0401055 89 0D 40 EB 40 00 mov dword ptr [v (0040eb40)],ecx
10: }
#50
现行国内教程中有大量这样的题目,难为了许多人。
现行国内教程又说不清数组与指针的关系,这样的题目真的就成为学生的拦路虎了。
我来说一下:
基本概念
1.数组名是&数组名[0]的缩写(不是所有场合下,此处不深入说),这转化成一种纸上演算:数组名====&数组名
[0]
2.*与&是一对逆操作:&--取地址、*--按地址取值,所以有*&对象====对象,&*地址====地址
3.地址前的*与地址(数组名)后[0] 存在互换关系
下面使用这些概念解释LZ的问题:
int a[4][4],*p=a[0];
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
==================
第一行:a是二维数组,四行四列; p指向了&a[0]
[0]--是元素的地址
第二行A:p+i是地址+偏移--仍是地址,*(p+i)是取地址的值--即int数值,(*(p+i)+j)是数值,*(*(p+i)+j)则错了--不能*数值
第三行B:同A--p[i]是*(p+i)另一表述法(用上边的概念可以推演出来)
第四行C:i*4是指第 i行前共有的元素数量,j是指第i行中第j列元素(即a[i][j])前元素数量,则i*4+j是a[i][j]这个元素前的元素个数,p[i*4+j]即这个元素的值
!!!!LS有人将4理解为32位系统中sizeof(int)值,有误----这个4是“四列”
第五行D:*(a[i]+j)====*(&a[i][0]+j)====*(&a[i][j])====*&a[i][j]====a[i][j]
指针(地址)表达式是C语言的脊梁骨,立则C立
现行国内教程又说不清数组与指针的关系,这样的题目真的就成为学生的拦路虎了。
我来说一下:
基本概念
1.数组名是&数组名[0]的缩写(不是所有场合下,此处不深入说),这转化成一种纸上演算:数组名====
2.*与&是一对逆操作:&--取地址、*--按地址取值,所以有*&对象====对象,&*地址====地址
3.地址前的*与地址(数组名)后[0] 存在互换关系
下面使用这些概念解释LZ的问题:
int a[4][4],*p=a[0];
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
==================
第一行:a是二维数组,四行四列; p指向了
第二行A:p+i是地址+偏移--仍是地址,*(p+i)是取地址的值--即int数值,(*(p+i)+j)是数值,*(*(p+i)+j)则错了--不能*数值
第三行B:同A--p[i]是*(p+i)另一表述法(用上边的概念可以推演出来)
第四行C:i*4是指第 i行前共有的元素数量,j是指第i行中第j列元素(即a[i][j])前元素数量,则i*4+j是a[i][j]这个元素前的元素个数,p[i*4+j]即这个元素的值
!!!!LS有人将4理解为32位系统中sizeof(int)值,有误----这个4是“四列”
第五行D:*(a[i]+j)====*(&a[i][0]+j)====*(&a[i][j])====*&a[i][j]====a[i][j]
指针(地址)表达式是C语言的脊梁骨,立则C立
#1
不做强转,题目编译能过?
#2
你可以编个程序测试下。
#3
答案选C,这是为什么?还有D为什么不行呢?不明白
#4
还是用赵老师的话回答你.
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#5
楼上是啥?我水平太次,看不懂啊。。。。。。
#6
指针的东西 复杂的我一般画个图。。
#7
有木有人正视一下俺的题啊。。。。太简单了么?你们都不屑回答??
#8
D也是对的,我认为啊
CD 都是对的
CD 都是对的
#9
a在内存中的状态是按顺序 a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], ..., a[3][3],
a[0]获得的是指向a[0][0]的指针,把它赋值给p后,想得到指向a[i][j]的指针就可以写p + i * 4 + j,获得其内容就是*(p + i * 4 + j)等价于p[i * 4 + j]
a[0]获得的是指向a[0][0]的指针,把它赋值给p后,想得到指向a[i][j]的指针就可以写p + i * 4 + j,获得其内容就是*(p + i * 4 + j)等价于p[i * 4 + j]
#10
D是错的,a[i]+j,实际等于a[i+j]...是不是这样?
#11
那D呢,我觉得D也可以啊
#12
D是对的...
建议楼主下次这样的题目直接写程序来试验...
建议楼主下次这样的题目直接写程序来试验...
#13
我编译过,cd都可以
#14
a[i]是一个行指针,其值为:第i个一维数组的首元素的地址
然后+j, 即a[i][j]
a[i][j] 反汇编估计是这样的:两步骤:1,定位到第i个一维数组的首元素的地址,2:偏移
所以cd都是对的
不对请指出
另外:楼主可以自行测试。。我没有测试
#15
我觉得对于这种问题,先在编译器上试下,然后自己有些思考,然后查下书,这样对于知识的理解就会更深
#16
好感动,我明白 了,刚自学C不久,有点迷糊,谢谢各位的指点啊!(*^__^*)
#17
还是用赵老师的话回答你.
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#18
蛋疼的东西~~
#19
赵老师是谁呀
#20
嗯……一时半会没反应过来
#21
学聪明了,,直接把题目写成小女子了。。。。
哈哈哈哈哈哈。。。
目前没看到详细且正确的答案。。。
答案是CD
哈哈哈哈哈哈。。。
目前没看到详细且正确的答案。。。
答案是CD
#22
哈哈,那你有何高见呐?(*^__^*)
#23
是否可以认为p=&a[0][0]?
#24
纠正一下,我犯了错误,还是基础不扎实
a[i]不是行指针,是数组名,
在表达式汇中,自动转位a[i]的首元素的地址
对于&a[i]才是获得行指针
a[i]不是行指针,是数组名,
在表达式汇中,自动转位a[i]的首元素的地址
对于&a[i]才是获得行指针
#25
a[i]等价&a[i][0],*(a[i] + j)就是*(&a[i][0] + j)也就是a[i][j]
数组除了取地址和取长度运算都是自动转指针的
数组除了取地址和取长度运算都是自动转指针的
#26
a[i]就是数组名
#27
那我得告诉你,下标运算只能作用于指针(因为是*的等价运算)... 如果a[i]不能给出一个指针右值a[i][0]就是非法的。
#28
不知道你想表达什么,大概猜测:你是说a[i] 不是数组名???
如果不是数组名,请问他是什么???
int a[3][4];
int(*p)[4]=&a[0];
你试试这代码,对不对,我的vs2010是对的
再比如:
int a[]={1,35,4356,90};
int(*p)[4]=&a;
a[0][1],它的值是35
如果不是数组名,请问他是什么???
int a[3][4];
int(*p)[4]=&a[0];
你试试这代码,对不对,我的vs2010是对的
再比如:
int a[]={1,35,4356,90};
int(*p)[4]=&a;
a[0][1],它的值是35
#29
其实我很想吐槽“数组名到底是个什么玩意”... 表达式里其实只有左右值
#include <stdio.h>
int a[2][2] = {1, 2, 3, 4};
int main()
{
int *p0 = a[0];
int (*p1)[2] = &a[0];
printf("%d %d\n", p0[3], p1[1][1]);
}
#30
注意上面的a[0]和&a[0]地址一样但是类型不一样,但参与运算的时候都是指针。
#31
a[i]不是数组名。它是一个表达式,这个表达式的类型是数组类型。
#32
表示学习了,C语言的指针已经有段时间没碰了。现在学C#的委托,这个类似于指针吧。
#33
比如用二维的字符数组存放多个字符串:
char s[3][40]={"Hello","How are you?","I'm fine, thank you."};
那么 cout<<s[0]; 显示的是 Hello
cout<<s[1]; 显示的是 How are you?
cout<<s[2]; 显示的是 I'm fine, thank you.
说明 s[0]、s[1]、s[2]都是一个字符指针,即 char*,
s[0] 指向Hello中的字符“H”
s[1] 指向How中的字符“H”
s[2] 指向字符“I”
char s[3][40]={"Hello","How are you?","I'm fine, thank you."};
那么 cout<<s[0]; 显示的是 Hello
cout<<s[1]; 显示的是 How are you?
cout<<s[2]; 显示的是 I'm fine, thank you.
说明 s[0]、s[1]、s[2]都是一个字符指针,即 char*,
s[0] 指向Hello中的字符“H”
s[1] 指向How中的字符“H”
s[2] 指向字符“I”
#34
左值和右值的定义和区别,能解释一下吗?
#35
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
因为 *(p+i) 相当于 p[i],所以A\B是一样的。因为*(p+i)+j的结果是整型数据,所以再运用取内容运算符*是错误的。A B 都是错误的。
因为数组在内存中按行连续存储的,所以也可以按一维数组的形式来访问,所以C是对的
把a[i]看成p,选项D就变成了*(p+j),可转换成p[j],再把p换成a[i],就是a[i][j],所以D也是对的。
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
因为 *(p+i) 相当于 p[i],所以A\B是一样的。因为*(p+i)+j的结果是整型数据,所以再运用取内容运算符*是错误的。A B 都是错误的。
因为数组在内存中按行连续存储的,所以也可以按一维数组的形式来访问,所以C是对的
把a[i]看成p,选项D就变成了*(p+j),可转换成p[j],再把p换成a[i],就是a[i][j],所以D也是对的。
#36
严格来说只有D是对的,详细可以参考《C陷阱与缺陷》第三章3.1数组与指针45页。
由于未声明是32位系统故严格来说C不正确,中的i*4,4是32位系统int所占字节。
由于未声明是32位系统故严格来说C不正确,中的i*4,4是32位系统int所占字节。
#37
答案肯定选D
C这个答案严格来说有局限性,牵扯到系统和编译器。 其只对32位程序成立。
C这个答案严格来说有局限性,牵扯到系统和编译器。 其只对32位程序成立。
#38
CD 正解
无法解释 请调试
无法解释 请调试
#39
++
#40
标准答案:D。
原因楼上的多说了。。
原因楼上的多说了。。
#41
答案c,不完全对。这里默认int 为4字节。
#42
答案C。不完全对int 这里默认是4字节。。。
#43
C和D都是正确的,但是C中的i*4这个4并不是代表4字节int型,而是表示a[4][4]列元素大小。
int *p=a[0]是将a的第0行的首地址赋于指针p,等效于p = &a[0][0]和p = a;
p[i*4+j]是p指向的地址偏移i*4+j个元素的值,它和a[i*4+j]是一样的。
*(a[i]+j) 其中a[i]+j是第i行的首地址加上列偏移量j,也就是i*4+j的地址,*(a[i]+j)就是这个地址的值。
#44
小女子的问题很快就有人答了,哎,世道啊....
#45
我不同意“中的i*4,4是32位系统int所占字节”,这里的4指列数的4,跟机器无关,只与数组的列有关,若数组a为5列,则a[i][j] = p[i*5 + j]
#46
我也是这么想的, p与a[0]的类型是不一样的, 用C++中的typeid可以明确知道的
但用code::blocks(gcc4.6.1)居然能编译通过, 真扯!
楼主请先看上面这个分析
再看上面这个说明(其实我也才听说有这么回事)
如果题目是这样:
int a[4][4];
int (*p)[4] = a;
那么我和1楼就不会说题目编译不过了, 而且这时的答案为ABD
#47
如果你觉得我说得对
请给1楼, 35楼, 36楼多给点分, 也记得给我1分, 这是我帮你总结的苦劳分
请给1楼, 35楼, 36楼多给点分, 也记得给我1分, 这是我帮你总结的苦劳分
#48
zhao4zhong1:
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
#49
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
1: int a[4][4];
2: int *p=a[0];
3: int i=2;j=3,v;
4: void main() {
//0401000 55 push ebp
//0401001 8B EC mov ebp,esp
//0401003 83 EC 40 sub esp,40h
//0401006 53 push ebx
//0401007 56 push esi
//0401008 57 push edi
5: v=a[i][j];
//0401009 A1 34 E0 40 00 mov eax,[i (0040e034)]
//040100E C1 E0 04 shl eax,4
//0401011 8B 0D 38 E0 40 00 mov ecx,dword ptr [j (0040e038)]
//0401017 8B 94 88 00 EB 40 00 mov edx,dword ptr [eax+ecx*4+40EB00h]
//040101E 89 15 40 EB 40 00 mov dword ptr [v (0040eb40)],edx
6: //v=*(*(p+i)+j);//A error C2100: illegal indirec
7: //v=*(p[i]+j); //B error C2100: illegal indirec
8: v=p[i*4+j]; //C
//0401024 A1 34 E0 40 00 mov eax,[i (0040e034)]
//0401029 8B 0D 38 E0 40 00 mov ecx,dword ptr [j (0040e038)]
//040102F 8D 14 81 lea edx,[ecx+eax*4]
//0401032 A1 30 E0 40 00 mov eax,[p (0040e030)]
//0401037 8B 0C 90 mov ecx,dword ptr [eax+edx*4]
//040103A 89 0D 40 EB 40 00 mov dword ptr [v (0040eb40)],ecx
9: v=*(a[i]+j); //D
//0401040 8B 15 34 E0 40 00 mov edx,dword ptr [i (0040e034)]
//0401046 C1 E2 04 shl edx,4
//0401049 A1 38 E0 40 00 mov eax,[j (0040e038)]
//040104E 8B 8C 82 00 EB 40 00 mov ecx,dword ptr [edx+eax*4+40EB00h]
//0401055 89 0D 40 EB 40 00 mov dword ptr [v (0040eb40)],ecx
10: }
#50
现行国内教程中有大量这样的题目,难为了许多人。
现行国内教程又说不清数组与指针的关系,这样的题目真的就成为学生的拦路虎了。
我来说一下:
基本概念
1.数组名是&数组名[0]的缩写(不是所有场合下,此处不深入说),这转化成一种纸上演算:数组名====&数组名
[0]
2.*与&是一对逆操作:&--取地址、*--按地址取值,所以有*&对象====对象,&*地址====地址
3.地址前的*与地址(数组名)后[0] 存在互换关系
下面使用这些概念解释LZ的问题:
int a[4][4],*p=a[0];
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
==================
第一行:a是二维数组,四行四列; p指向了&a[0]
[0]--是元素的地址
第二行A:p+i是地址+偏移--仍是地址,*(p+i)是取地址的值--即int数值,(*(p+i)+j)是数值,*(*(p+i)+j)则错了--不能*数值
第三行B:同A--p[i]是*(p+i)另一表述法(用上边的概念可以推演出来)
第四行C:i*4是指第 i行前共有的元素数量,j是指第i行中第j列元素(即a[i][j])前元素数量,则i*4+j是a[i][j]这个元素前的元素个数,p[i*4+j]即这个元素的值
!!!!LS有人将4理解为32位系统中sizeof(int)值,有误----这个4是“四列”
第五行D:*(a[i]+j)====*(&a[i][0]+j)====*(&a[i][j])====*&a[i][j]====a[i][j]
指针(地址)表达式是C语言的脊梁骨,立则C立
现行国内教程又说不清数组与指针的关系,这样的题目真的就成为学生的拦路虎了。
我来说一下:
基本概念
1.数组名是&数组名[0]的缩写(不是所有场合下,此处不深入说),这转化成一种纸上演算:数组名====
2.*与&是一对逆操作:&--取地址、*--按地址取值,所以有*&对象====对象,&*地址====地址
3.地址前的*与地址(数组名)后[0] 存在互换关系
下面使用这些概念解释LZ的问题:
int a[4][4],*p=a[0];
A *(*(p+i)+j)
B *(p[i]+j)
C p[i*4+j]
D *(a[i]+j)
==================
第一行:a是二维数组,四行四列; p指向了
第二行A:p+i是地址+偏移--仍是地址,*(p+i)是取地址的值--即int数值,(*(p+i)+j)是数值,*(*(p+i)+j)则错了--不能*数值
第三行B:同A--p[i]是*(p+i)另一表述法(用上边的概念可以推演出来)
第四行C:i*4是指第 i行前共有的元素数量,j是指第i行中第j列元素(即a[i][j])前元素数量,则i*4+j是a[i][j]这个元素前的元素个数,p[i*4+j]即这个元素的值
!!!!LS有人将4理解为32位系统中sizeof(int)值,有误----这个4是“四列”
第五行D:*(a[i]+j)====*(&a[i][0]+j)====*(&a[i][j])====*&a[i][j]====a[i][j]
指针(地址)表达式是C语言的脊梁骨,立则C立