C语言最基础的指针问题

daviddivad 2014-08-08 05:15:41
#include <stdio.h>

void main()
{
int a[5]={1,2,3,4,5};
int *ptr = (int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}


这段程序调试出来的结果是2,5
2比较好理解,这个5的结果,能否详细讲解一下?谢谢
...全文
393 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2014-08-14
  • 打赏
  • 举报
回复
引用 19 楼 dongbaoxiong 的回复:
@zhao4zhong1 这是人吗?我觉得就是水!
电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息…… 水能载舟,也能覆舟。 水能孕育万物,也能毁灭万物。
dongbaoxiong 2014-08-14
  • 打赏
  • 举报
回复
@zhao4zhong1 这是人吗?我觉得就是水!
dongbaoxiong 2014-08-14
  • 打赏
  • 举报
回复
你对数组取地址了,然后加了1,就是说这时候你的指针是当做指向数组的指针来解释的,就是 地址变化量是这个数组的大小。后来你的指针又当int * 来解释的,就是你减1, 就是地址变化量是int 大小。也就指向你数组最后一个位置。
ARGeek 2014-08-13
  • 打赏
  • 举报
回复
1楼正解....
赵4老师 2014-08-11
  • 打赏
  • 举报
回复
很多情况下,听别人解释是怎么也比不上自己亲身去观察和领悟的。 搜“盲人摸太阳”
cdcjk 2014-08-11
  • 打赏
  • 举报
回复
a已经是地址了,对地址再取地址
707wk 2014-08-11
  • 打赏
  • 举报
回复
引用 1 楼 lovesmiles 的回复:
void main() { int a[5]={1,2,3,4,5}; int *ptr = (int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); } 问题出在红色的地方,a已经是地址了,对地址再取地址,你觉得得到什么东西?得到int**类型,即二维数组,将这二维数组+1,就是a[1][0]的地址,将这个地址减1,就是a[0][5],转化回来就是a[5]
+1
tixisong 2014-08-11
  • 打赏
  • 举报
回复
引用 楼主 daviddivad 的回复:
#include <stdio.h> void main() { int a[5]={1,2,3,4,5}; int *ptr = (int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); } 这段程序调试出来的结果是2,5 2比较好理解,这个5的结果,能否详细讲解一下?谢谢
&a之后是int (*p)[5],是一个指向5个int的数组指针,int * ptr = (int*)(&a + 1)用(int*)强制类型转换,本来是a[6],若不强制转换,ptr-1又会变成a[0],强制转换后再减1,就变成了a[5]
tixisong 2014-08-11
  • 打赏
  • 举报
回复
引用 10 楼 lin5161678 的回复:
[quote=引用 8 楼 lovesmiles 的回复:] int** 这个说法可能过于随意,改成int[][]可能合适一点。将代码改成下面这样子你可能看得清晰一些
不是过于随意了 完全是说错了 a是一个数组 &a 得到的是指向数组的指针 就是 int(*)[5] 这个指针 +1 才有 +sizeof(int[5]) 的效果 [/quote] ++
njustlihao 2014-08-10
  • 打赏
  • 举报
回复
a是一个数组,同时a是该数组第一个元素的地址,而&a是该数组的地址,这两个地址值相同,但是类型不同,一个是int*型,一个是int(*)[5]型。 这个问题在C Primer Plus上有明确的解释。
yingzijuntuan 2014-08-09
  • 打赏
  • 举报
回复
1楼讲的很好
我看你有戏 2014-08-09
  • 打赏
  • 举报
回复
ptr指向a[6]了
lin5161678 2014-08-09
  • 打赏
  • 举报
回复
引用 8 楼 lovesmiles 的回复:
int** 这个说法可能过于随意,改成int[][]可能合适一点。将代码改成下面这样子你可能看得清晰一些
不是过于随意了 完全是说错了 a是一个数组 &a 得到的是指向数组的指针 就是 int(*)[5] 这个指针 +1 才有 +sizeof(int[5]) 的效果
勤奋的小游侠 2014-08-09
  • 打赏
  • 举报
回复
引用 6 楼 daviddivad 的回复:
一楼的解答,我想了解下,一维数组和二维数组的对应关系,我这个一维数组,为什么是那样的对应关系?
用typedef就可以清楚地看出它们的关系, # include <iostream> typedef int A[5]; void main() {      A a ={1,2,3,4,5}; A* p =&a; p++;//这个p++,你认为它应该指向那里?是指a+1还是指向a+sizeof(A)? }
勤奋的小游侠 2014-08-09
  • 打赏
  • 举报
回复
引用 7 楼 lin5161678 的回复:
[quote=引用 1 楼 lovesmiles 的回复:] a已经是地址了,对地址再取地址,你觉得得到什么东西?得到int**类型,即二维数组,将这二维数组+1,就是a[1][0]的地址,将这个地址减1,就是a[0][5],转化回来就是a[5]
错了 对a进行&操作 得到的不是int** 而且对int** 进行 +1 操作也得不到a[1][0] int** + 1 纯粹做指针算术考虑 +的是sizeof(int*) 假设int* 和 int大小刚刚好一样是4个字节 这里也只是后移4个字节 刚刚好指向 a[0]+1[/quote] int** 这个说法可能过于随意,改成int[][]可能合适一点。将代码改成下面这样子你可能看得清晰一些
# include <iostream>
typedef int A[5];
void main()
{ 
	A a ={1,2,3,4,5};
	int *ptr = (int *)(&a+1);
	printf("%d,%d\n",*(a+1),*(ptr-1));

	cout<<"&a="<<&a<<endl;//
	cout<<"&a+1="<<&a+1;//你认为这里面输出的值是比上面的输出多4而已吗?
}
lin5161678 2014-08-09
  • 打赏
  • 举报
回复
引用 1 楼 lovesmiles 的回复:
a已经是地址了,对地址再取地址,你觉得得到什么东西?得到int**类型,即二维数组,将这二维数组+1,就是a[1][0]的地址,将这个地址减1,就是a[0][5],转化回来就是a[5]
错了 对a进行&操作 得到的不是int** 而且对int** 进行 +1 操作也得不到a[1][0] int** + 1 纯粹做指针算术考虑 +的是sizeof(int*) 假设int* 和 int大小刚刚好一样是4个字节 这里也只是后移4个字节 刚刚好指向 a[0]+1
daviddivad 2014-08-09
  • 打赏
  • 举报
回复
一楼的解答,我想了解下,一维数组和二维数组的对应关系,我这个一维数组,为什么是那样的对应关系?
赵4老师 2014-08-08
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察
赵4老师 2014-08-08
  • 打赏
  • 举报
回复
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单! 指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认: 有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物; 而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。 不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);】来理解指针的本质, 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。 这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑! 这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!! 提醒: “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 (Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。) 想要从本质上理解C指针,必须学习C和汇编的对应关系。” 不是一回事! 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码! 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息…… 十字链表交换任意两个节点C源代码(C指针应用终极挑战)http://download.csdn.net/detail/zhao4zhong1/5532495
勤奋的小游侠 2014-08-08
  • 打赏
  • 举报
回复
void main() { int a[5]={1,2,3,4,5}; int *ptr = (int *)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); } 问题出在红色的地方,a已经是地址了,对地址再取地址,你觉得得到什么东西?得到int**类型,即二维数组,将这二维数组+1,就是a[1][0]的地址,将这个地址减1,就是a[0][5],转化回来就是a[5]

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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