一个关于C语言的指针与二维数组的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个关于C语言的指针与二维数组的问题相关的知识,希望对你有一定的参考价值。

自己写了段简短的代码来验证数组地址,数组内容和指针之间的关系。。
如下:
#include<stdio.h>

void main()

int zippo[4][3]= 2,4,1, 6,8,1, 1,3,1, 5,7,1;

printf(" zippo=%p, zippo+1=%p \n", zippo , zippo+1 );

printf(" *zippo=%p, *zippo+1=%p\n" , *zippo, *zippo+1);


输出结果如下:
zippo=0012FF50, zippo+1=0012FF5C
*zippo=0012FF50, *zippo+1=0012FF54
Press any key to continue

对于第一行的输出结果我有点不理解。我把zippo和zippo+1都理解成一个二级指针,那么它们分别指向一个一级指针,而一个指针本身所占的内存是4个字节,那zippo和zippo+1的地址之差不应该是一个指针所占有的内存值,也就是4吗?但是我从结果推回去相差的是12,也就是说相差了第一组数据2,4,1三个整形常量的内存值……哪位高人指点下迷津?
我要的不是答案……我想知道我那么想怎么错了。。。我的意思是,按照程序的运行结果,那不是把指针本身的地址和指针所指向的对象的地址等同起来了么?二级指针指向的应该是一级指针的地址呀,也就是4个字节……那二级指针加1为什么地址不是加了4呢?……

呵呵,厉害!也就是说应该把数组的首地址理解成一种特殊的地址类型吧,即zippo的长度是4*3*sizeof(int),*(zippo+1)的长度是3*sizeof(int),而zippo+1的长度才应该是一个普通地址长度,即4

C语言中,数组和指针是两类不同的类型——前者的定义需要明确被指向的类型,后者的定义需要明确元素类型和数组的长度。
这样定义的原因是两者本身的语义不同。引用一个表示数组的标识符(数组名)具有两重含义,一是指整个数组,二是指指向数组首个元素(而不是整个数组)的指针。具体取两种含义是上下文相关的。在定义数组、作为sizeof或一元&操作符的操作数这些左值语义上下文中,数组名表示第一种含义;其它情况下,取第二种含义。因此,C语言中在某些场合(例如参数传递)数组可以丢失长度信息,退化为对应的指针(这里的退化是指隐式地类型转换,保持数组元素和指针指向的对象的类型相同)。(如果不考虑类型,两种含义得到的值都是相等的,即数组首个元素的第一个字节在存储器地址空间中对应的整数值——地址(值),因此编译器一般以此实现数组,同时在目标代码中完全不保留数组的类型信息。)但反之无法实现。
作为以下内容的前提,LZ必须明确,被一个指针指向的是对象——即具有确定地址的一个的实体(作为一个表达式,可以是左值),而不是作为一种整数的“地址”(尽管指针的值等于被指向对象的地址)。要点在于,指针是有类型(而且和被指向的类型对应)的,类型会影响操作的具体行为。
C语言的核心语言特性没有直接支持多维数组,所谓的多维数组,只不过是元素为数组的数组。由于元素类型是数组类型的必要组成部分,因此指针类型元素的数组和一维数组类型元素的数组(通常所说的“二维数组”)是不同的(所以不是像LS说的——你“可以”,而是“必须”把二维数组看成数组的数组)。而二维数组更不是二级指针。二级指针指向的是一级指针,它的值是一级指针的地址——由于是两个不同的对象(左值),二级指针的地址和这个值自然不同(如果因为指向自身而导致值相同,则至少需要一次显式类型转换,因为一级和二级指针之间不会隐式地转换);而因为以上的数组语义的关系,二维数组可以退化成不同的指针,类型不同,但地址值相同。结合LZ的例子来讲,二维数组zippo可以退化为&zippo[0](zippo[0]是一个一维数组,&zippo[0]是指向它的指针),或者继续退化为&zippo[0][0](指向一维数组zippo[0]的首个元素zippo[0][0]的指针)这两个指针右值,而三者的值都是同一个地址。
然后是“+”的问题。这里又有一个陷阱:数组作为additivate operator(二元+和-)算术操作的操作数,它的类型会影响+和-的具体行为,满足“下标移动”的语义。从实现上来说,同指针+、-操作一样,对于一个整数,地址值的改变值是除了指针/数组外另一个整数操作数乘以sizeof(被指向的类型或元素类型)。例如,i是一个正整数,zippo是表示一个数组或者指针标识符,那么zippo + i按下标移动应该等价于&zippo[i],从实现上来看相当于(zippo的类型)((intptr_t)zippo + (intptr_t)(sizeof(*zippo) * i))(其中intptr_t是标准库定义的和在该平台下指针大小相同的整数类型)。LZ的问题中,如果zippo是二级指针,那么zippo和zippo+1的地址之差确实应该是一个(一级)指针所占存储器空间的大小(等于sizeof(intptr_t),32位平台也就是4)。但是这里zippo是二维数组,那么sizeof(*zippo)等于它的元素——一维数组的sizeof值,自然可以不是4。
====
[原创回答团]

参考资料:原创

参考技术A #include <stdio.h>

int main()

int array[4][3];
int *p1 = array[0];/*一级指针*/
int (*p2)[3] = array;/*二级指针*/
printf("%d,%d\n", array,array+1);
printf("%d,%d\n", p1,p1+1);
printf("%d,%d\n", p2,p2+1);
return 0;


//int array[4][3];可以看做int (*p[4])[3];即一个数组,每个数组元素指向某一个三int元素数组
参考技术B 二维数组啊,当然就是输出这样的结果的啊
zippo是第一行的地址
zippo+1第二行的地址
*zippo第一个元素的地址
*zippo+1第一行第二个也是整个数组第二个元素的地址
绝对是正解
参考技术C zippo是二维指针
所以 zippo+1 则zippo后移一个元素的长度 即 一维数组的长度
int [3] = 4 * 3 = 12
参考技术D 1个n*m二维数组,你可以看成是n个长度为m的一维数组组成的。
假设数组a[100][100].
a[0]表示的是数组的第零行的首地址,也即是整个二维数组的首地址。
a[1]表示的是数组的第一行的首地址。
你那程序里的加1就已经是到数组的下一行了,肯定地址需要加上整一行打大小了。
第5个回答  2010-08-05 zippo的是zippo[0][0],zippo+1 的是zippo[1][0]

关于c语言二维数组列指针初始化

关于c语言二维数组列指针初始化下图关于那个列指针的初始化有不懂。p=a[0],p=*a,p=&a[0][0]。书上说这三者等价,但是我有点不懂。
1.按照指针初始化的定义,int *p=&a[0][0];这一点,完全没问题,就算传了二维数组的首地址给指针。
2.但是,p=*a怎么会和上面等价呢 我记得*a不是去这个数组的第一个值吗,怎么能用值传给一个指针,或者说一个指针指向一个值。
3.p=a[0],这个不是传的是第一行的地址吗,和第三个具体的首地址能等价?
恳求各位前辈学长能够解惑(。ò ∀ ó。)感激~

参考技术A 你可以把二维数组a看成一个一维的指针数组,*a与a[0]等价,这样是不是好理解了?本回答被提问者和网友采纳 参考技术B Hubby and

以上是关于一个关于C语言的指针与二维数组的问题的主要内容,如果未能解决你的问题,请参考以下文章

C语言中关于二维数据指针的问题?

C语言中二维数组行指针是啥

C语言指针指向一维数组与二维数组?

C语言 指针初始化二维数组

C语言 如何定义一个二维指针数组?

c语言中如何通过二级指针来操作二维数组