指针地址在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式zippo从int [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 , *zippo , zippo[0] , &zippo[0]和&zippo[0][0]都具有相同的值; 它们都指向数组的底部(数组的地址与数组的第一个元素的地址相同)。 各种expression式的types都不同。
zippo不是一个指针。 这是一个数组值的数组。 zippo和zippo[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; 这是完全有效的,因为在这种情况下, pt是T *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个元素。