指针地址在Cmultidimensional array中

我搞乱了multidimensional array和指针。 我一直在看一个程序,打印出一个简单的数组的内容和地址。 这是我的数组声明:

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

我目前的理解是, zippo是一个指针,它可以保存一些其他指针的地址。 默认情况下, zippo保存指针zippo[0]的地址,也可以保存指针zippo[1]zippo[2]zippo[3]

现在,采取以下声明:

 printf("zippo[0] = %p\n", zippo[0]); printf(" *zippo = %p\n", *zippo); printf(" zippo = %p\n", zippo); 

在我的机器上,输出如下:

 zippo[0] = 0x7fff170e2230 *zippo = 0x7fff170e2230 zippo = 0x7fff170e2230 

我完全理解为什么zippo[0]*zippo具有相同的值。 它们都是指针,它们都存储整数2的地址(默认值),或者zippo[0][0] 。 但是zippo什么共享相同的内存地址? zippo不应该存储指针zippo[0]的地址吗? Whaaaat?

当你声明一个multidimensional array时,编译器将它视为一个单维数组。 multidimensional array只是一个抽象,让我们的生活更轻松。 你有一个误解:这不是一个指向4个数组的数组,它总是只有一个连续的内存块。

在你的情况下,做:

 int zippo[4][2] 

真的和做一样

 int zippo[8] 

由编译器为您处理2D寻址所需的math。

有关详细信息,请参阅C ++中的数组本教程 。

这和做的很不一样:

 int** zippo 

要么

 int* zippo[4] 

在这种情况下,你正在创build一个四个指针的数组,这个指针可以被分配给其他数组。

当数组expression式出现在大多数上下文中时,它的types被隐式地从“T的N元素数组”转换为“指向T的指针”,并且它的值被设置为指向数组中的第一个元素。 这个规则的例外是当数组expression式是sizeof或者( & )操作符的地址的操作数,或者当数组是一个string文字被用作声明中的初始化器时。

因此,expression式zippoint [4][2]int [4][2]元素数组的4元素数组)到int (*)[2] (指向2元素数组的int)的“衰变”。 类似地, zippo[0]的types是int [2] ,隐式转换为int *

给定int zippo[4][2]的声明,下表显示了涉及zippo和任何隐式转换的各种数组expression式的types:

expression式types隐式转换为等效expression式
 ---------- ---- ----------------------- ------------- --------
 zippo int [4] [2] int(*)[2]               
 &zippo int(*)[4] [2]       
 * zippo int [2] int * zippo [0]
 zippo [i] int [2] int *
 &zippo [i] int(*)[2]                               
 * zippo [i] int zippo [i] [0]
 zippo [i] [j] int
 &zippo [i] [j] int *
 * zippo [i] [j]无效

请注意, zippo&zippo*zippozippo[0]&zippo[0]&zippo[0][0]都具有相同的值; 它们都指向数组的底部(数组的地址与数组的第一个元素的地址相同)。 各种expression式的types都不同。

zippo不是一个指针。 这是一个数组值的数组。 zippozippo[i] for i in 0..4在某些情况下(特别是在值上下文中)可以“衰减”到指针。 尝试打印sizeof zippo作为在非值上下文中使用sizeof zippo的示例。 在这种情况下, sizeof将报告数组的大小,而不是指针的大小。

在值上下文中 ,数组的名称衰减为指向其第一个元素的指针。 所以,在值上下文中, zippo&zippo[0]是一样的,因此它的types是“指向int的数组[2]”。 *zippo在值上下文中与&zippo[0][0] ,即“指向int指针”。 他们有相同的价值,但不同的types。

我build议阅读数组和指针来回答你的第二个问题。 指针具有相同的“值”,但指向不同的空间量。 尝试打印zippo+1*zippo+1更清楚地看到:

 #include <stdio.h> int main(void) { int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} }; printf("%lu\n", (unsigned long) (sizeof zippo)); printf("%p\n", (void *)(zippo+1)); printf("%p\n", (void *)(*zippo+1)); return 0; } 

对于我的跑步,它打印:

 32 0xbffede7c 0xbffede78 

告诉我,我的机器上的sizeof(int)是4,并且第二个和第三个指针的值不同(如预期的那样)。

另外, "%p"格式说明符在*printf()函数中需要void * ,因此您应该在printf()调用中将指针转换为void *printf()是可变参数函数,因此编译器无法执行自动转换为你在这里)。

编辑 :当我说一个数组“衰变”的指针,我的意思是在值上下文中的数组的名称相当于一个指针。 因此,如果我有T pt[100]; 对于某些typesT ,那么名称pt在值上下文中是T *types的。 对于sizeof和一元&运算符,名称pt不会减less到指针。 但是你可以做T *p = pt; 这是完全有效的,因为在这种情况下, ptT *types的。

请注意,这个“衰减”只发生一次。 所以,假设我们有:

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

然后,值上下文中的zippo衰变为types指针:指向int数组[2]的指针。 在代码中:

 int (*p1)[2] = zippo; 

是有效的,而

 int **p2 = zippo; 

会触发“不兼容的指针分配”警告。

用上面定义的zippo

 int (*p0)[4][2] = &zippo; int (*p1)[2] = zippo; int *p2 = zippo[0]; 

都是有效的。 当使用printf("%p\n", (void *)name);打印时,它们应该打印相同的值printf("%p\n", (void *)name); ,但指针是不同的,它们分别指向整个matrix,一行和一个整数。

这里最重要的是int zippy[4][2]int **zippo不是同一types的对象。

就像int zippi[5]zippy是一块内存的地址。 但是编译器知道你想要用zippy从二维语法开始寻址八个内存位置,但是要用一维语法来解决从zippi开始的五个内存位置。

zippo是完全不同的东西。 保存了一个足够大的内存块的地址,以包含两个指针,如果使它们指向某些整数数组,则可以使用二维数组访问语法对它们进行解引用。

Reed解释得很好,我们再加几点来简化一下,当我们引用zippo或者zippo[0]或者zippo[0][0] ,我们仍然指向zippo数组的相同的基地址。 原因是数组总是连续的内存块,而multidimensional array是连续放置的多个单维数组。

当你必须增加每一行时,你需要一个指针int *p = &zippo[0][0] ,并且通过每一行p++增加指针。 在你的示例id中它是一个4×2的数组,在做p++的时候,指针指向的是第二组4个元素。