c语言中的printf函数问题

int main()
{
int arry[3][5]={
{1,2,4},
{4,5,6,7},
{6,5,3,8}
};
int (*p)[5];
p=arry;

    printf("%x\n",*(p+1)+3);
    printf("%x\n",*(*(p+1)+3));
    printf("%x\n",*(p+1)+3);
    printf("%x\n",*(p+1)+2);
    printf("%x\n",p);
    printf("%x\n",p+1);
    printf("%x\n",*p+1);
    printf("%x\n",p[0]+1);
    printf("%x\n",**p);
    printf("%x\n",&p);


    定义了一个二维数组arry,printf("%x\n",*(p+1)+3);为什么这样输出来的是一个地址?
    其中printf函数中的输出项表,到底是不是在计算表达式的左值还是右值,如果是的
    话,到底是哪个值? 谢谢解决问题

8个回答

再解决该问题之前,想讲一下,定义一个指针的语句,代表的含义.

图片说明

接下来,根据这个题来讲.

图片说明

int main()

{
int arry[3][5]={{1,2,4},{4,5,6,7},{6,5,3,8}};//数组名代表的是一块内存的首地址
int (*p)[5];//定义一个数组指针.这个指针,指向一个一维数组的首地址.该一维数组含有5个成员.可以把这条语句理解成int5;那么指针p指向的是一个int[5] 类型,p的寻址能力是sizeof(int)*5. p+1指向的地址和p指向的地址相差20. 在二维图中,(p+1)就到下一行.
//在一些参考书中,把*(星号)解释成降低维度(降维).本来p是指向int型数组的指针.用星号降维之后,(*p)就是一个int型的指针.那么(*p)+1,就是往后移动了sizeof(int)个字节,就是4个字节.记住,现在(*p)还依然是一块内存地址.
p=arry;//p指向数组arry的首地址
printf("%x\n",*(p+1)+3);//在附加的参考图中,p指向0XFFFF0002,p是一个int[5]类型的指针,所以,p+1往后移动sizeof(int)*5个字节,也就是移动到第二行,p+1就是第二行的首地址.*(p+1)就是降维,接下来如果再移动,就是移动sizeof(int)个字节.切记,这时候*(p+1)仍然是一个地址,*(p+1)并不是取(p+1)这个地址的值.因为p一开始指向的是一个数组,所以,这时候的星号只是降维.现在*(p+1)是一个地址了,也可以理解为是一个int型的指针了.如果再进行取值,那么就是一个数值.例如:*(*(p+1)+0)是第二行第一个的值, ((p+2)+4)是第三行第五个的值.
printf("%x\n",*(*(p+1)+3));//第二行第三个的值
printf("%x\n",*(p+1)+3);//第二行第四个的地址
printf("%x\n",*(p+1)+2);//第二行第三个的地址
printf("%x\n",p);//数组的首地址,也是第一行的首地址,也是第一行第一个元素的首地址.
printf("%x\n",p+1);//第一行第二个元素的首地址.p是一个int[5]类型的指针,所以你要承认,(p+1)仍然是一个int[5]类型的指针,并不是int型的指针,所以,要先用星号对它进行降维,才是int型的指针.然后才可以使用星号取这个地址的值.
printf("%x\n",*p+1);//第一行第二个元素的地址.
printf("%x\n",p[0]+1);//p[0]相当于*(p+0).所以,这个是第一行第二个元素的地址.在这里再多讲一点数组方式访问和星号方式访问的转换.*(p+0)和p[0]相同,*(p+3)+2和p[3]+2相同,p[2][3]和*(*(p+2)+3)相同.
printf("%x\n",**p);//第一行第一个元素的值.
printf("%x\n",&p);//p是一个指针变量,p在内存中也有一个存储它的空间.这句话就是输出存放变量p的内存地址.

}


我猜你可以这么想:
你如果不能理解,你可能会说:”p是一个内存地址,那么*p就该是取这块内存地址中存放的值”.那么,我们拿上面这个题为例,定义p的时候是这样定义的.int (*p)[5];然后,请你告诉我如果访问第一行第三个空间的值?是*(p+2)吗?如何访问第三行第二个空间的值?是*(p+11)吗?拜托大哥,如果你想这样访问的话,你定义指针变量p的时候,可以这样定义,int *p=arry;那么,你就可以尽情的通过*(p+11)访问到第三行第二个空间的值了.
lishulong5883
shell_shu 谢谢 您的耐心解答 学习了 ,原来有个“降维”的概念,我还想p明明是指向一个数组,为啥加个“*”就变成指向数组中的第一个int型元素了,原来这是“降维”,谢谢您了。
5 年多之前 回复

(p+1)+3)是不是应该是((p+1)+3)

*(p+1)得到的是一个指针,指针+3的结果当然是一个地址

qq_26746015
qq_26746015 回复shell_shu: p已经是一个指针了 *(p+1)也应该是一个指针了
5 年多之前 回复
lishulong5883
shell_shu p是个指针呀,为啥*(p+1)得到的是一个指针?
5 年多之前 回复

printf函数可以显示输出,,也可以打印值 ,后面的是打印的值

p 的类型是:int (*)[5]
p 的类型是:int
**p 的类型才是 : int

你们都乱猜什么

JOE_OC
JOE_OC *p 的类型是:int
5 年多之前 回复

图片说明

根据Ollydbg调试得到:

图片说明
图片说明

图片说明

运行结果:

图片说明

Allblues57
Allblues57 回复shell_shu: 应该说,一个指向数组的指针加一个“*”,得到的是它所指向的那个对象的值。
5 年多之前 回复
lishulong5883
shell_shu 若是个一维数组,数组名指向数组的第一个元素。若是个二维数组,则数组名指向的是第一个一维数组,问题中的arry是个二维数组,那么p=arry则p指向的是arry二维数组中的第一个数组,则*(p+1)+3指向的是第二个一维数组的第4个元素,所以printf("%x\n",*(p+1)+3); 输出的是*(p+1)+3这个指针的内容,也就是第二个一维数组中第四个元素的地址? 我不明白的是,一个指向数组的指针为什么加一个"*" 就变成了指向数组中第一个元素了,这个过程是怎么来的,请老师讲一讲
5 年多之前 回复
Allblues57
Allblues57 回复shell_shu: 这个和转换指示符有关。%s的参数必须是一个指向字符串的指针或者说是一个字符串的起始地址,数组名本身就是该数组的起始地址,所以会输出数组里的内容直到遇见空字符为止。而%x,%n之类的输出的都是参数的值。
5 年多之前 回复
Allblues57
Allblues57 回复Allblues57:p是指向arry[0]的,那么p+1指向arry[1],因为arry是二维数组,所以arry[1]存放的是arry[1][0]的地址。则*(p+1)指向arry[1][0]。*(p+1)+3指向arry[1][3].
5 年多之前 回复
Allblues57
Allblues57 回复shell_shu: p=arry <=> p=&arry[0] ;
5 年多之前 回复
lishulong5883
shell_shu 回复Allblues57: 为什么*(p+1)+3 也是一个指针?
5 年多之前 回复
lishulong5883
shell_shu 从字符串的第一个字符直到\0的字符串,这应该是因为C中没有专门的字符类型吧,printf函数应该是输出内存中的内容吧,那么假如用指针的话,直接用指针的间接访问就可以输出内存中的内容,我搞不明白的是,p就是一个指向数组的指针,为啥printf函数中的*(p+1)输出的也是一个地址?
5 年多之前 回复
lishulong5883
shell_shu 回复Allblues57: C语言中在printf函数输出字符串的时候,假如是用的是字符串数组的话,printf里面用%s,数组名就可以
5 年多之前 回复
Allblues57
Allblues57 我觉得。。。我好像搞错问题跑错片场了= = 不用理我。。"%x"是以十六进制输出参数的值。比如指针变量里存的是地址,所以输出的就是地址。。
5 年多之前 回复

(p+1)+3),这样 加一个*号就好了。详情见 高级程序语言c版

更正Allblues57的长篇回答。。

p[1]指向arry[1][0]而不是arry[1]。

求解**p时,p指向arry[0],即p=&arry[0];*p=arry[0]; **p=arry[0][0];

lishulong5883
shell_shu 有位老师讲了,如果p指向的是一个数组,那么加上“*”后,这个指针就“降维”了,变成是指向数组中的第一个int型的元素。
5 年多之前 回复
lishulong5883
shell_shu 回复Allblues57: 我说错了p[1]指向的是arry[1][0]。谢谢您的耐心解答
5 年多之前 回复
Allblues57
Allblues57 回复shell_shu: 第一,在我理解,p[1]指向的是arry[1][0],p[1]与arry[1]是等价的;第二printf函数输出的是什么与转换指示符有关;第三,p=arry;这句理解为将arry赋值给p,所以p=&arry[0];p指向了arry数组的第一个元素;第四,你再重新提这个问题吧,让更多人来帮你,我觉得我表述不清。
5 年多之前 回复
lishulong5883
shell_shu p指向的是数组,P[1]指向的是arry[1],printf函数输出的是一个内存中的值吧,像您说的那样,printf("%d\n",*p)输出来的是指向对象的值,但是p指向的是一个int型的一维数组,不能这样输出呀,实际上printf("%x",*p)这样输出的结果是和printf("%x",arry)与printf("%x",&arry)与printf("%x",p)的值是一样的,所以我的理解是如果一个指针指向的是一个数组,那么“*数组”指向的是数组中的第一个元素。
5 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问