C多维数组中的指针地址

Ich*_*i10 28 c memory arrays pointers multidimensional-array

我正在搞乱多维数组和指针.我一直在看一个程序,它打印出一个简单数组的内容和地址.这是我的数组声明:

int zippo[4][2] = { {2,4},
            {6,8},
            {1,3},
            {5,7}   };
Run Code Online (Sandbox Code Playgroud)

我目前的理解是它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);
Run Code Online (Sandbox Code Playgroud)

在我的机器上,它提供以下输出:

zippo[0] = 0x7fff170e2230
  *zippo = 0x7fff170e2230
   zippo = 0x7fff170e2230
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*ode 34

当数组表达式出现在大多数上下文中时,其类型将从"N元素数组T"隐式转换为"指向T",其值设置为指向数组中的第一个元素.此规则的例外情况是,数组表达式是sizeof或者address(of &)运算符的操作数,或者数组是在声明中用作初始值设定项的字符串文字.

因此,表达式zippo"衰变"从类型int [4][2](int的2元素数组的4元素数组)到int (*)[2](指向int的2元素数组的指针).类似地,zippo[0]is 的类型int [2]被隐式转换为int *.

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

Expression    Type            Implicitly converted to  Equivalent 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]  invalid

需要注意的是zippo,&zippo,*zippo,zippo[0],&zippo[0],并且&zippo[0][0]都具有相同的价值; 它们都指向数组的基数(数组的地址与数组的第一个元素的地址相同).但是,各种表达的类型都不同.


Ree*_*sey 32

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

在你的情况下,做:

int zippo[4][2]
Run Code Online (Sandbox Code Playgroud)

真的和做的一样

int zippo[8]
Run Code Online (Sandbox Code Playgroud)

使用编译器为您处理的2D寻址所需的数学运算.

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

这与做的非常不同:

int** zippo
Run Code Online (Sandbox Code Playgroud)

要么

int* zippo[4]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将创建一个包含四个指针的数组,这些指针可以分配给其他数组.


Alo*_*hal 5

zippo不是指针.这是一个数组值数组. zippozippo[i]用于i在0..4可以"衰变"在某些情况下一个指针(具体地说,在值上下文).尝试打印sizeof zippo以获取zippo在非值上下文中使用的示例.在这种情况下,sizeof将报告数组的大小,而不是指针的大小.

在值上下文中,数组的名称衰减为指向其第一个元素的指针.因此,在值上下文中,zippo是相同的&zippo[0],因此具有"指向数组[2]的指针int"; *zippo,在值上下文中&zippo[0][0],即"指向int".它们具有相同的值,但具有不同的类型.

我建议阅读数组和指针来回答你的第二个问题.指针具有相同的"值",但指向不同的空间量.尝试打印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;
}
Run Code Online (Sandbox Code Playgroud)

对于我的运行,它打印:

32
0xbffede7c
0xbffede78
Run Code Online (Sandbox Code Playgroud)

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

此外,"%p"格式说明需要void **printf()功能,所以你应该投你的指针,void *在您的printf()电话(printf()是一个可变参数函数,所以编译器不能为你做自动转换这里).

编辑:当我说数组"衰减"到指针时,我的意思是值上下文中数组的名称等同于指针.因此,如果我有 T pt[100];某种类型T,那么名称ptT *值上下文中的类型.对于sizeof和一元运算&符,名称pt不会缩减为指针.但你可以做T *p = pt;- 这是完全有效的,因为在这种情况下,pt是类型T *.

请注意,这种"腐朽"只发生一次.所以,假设我们有:

int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
Run Code Online (Sandbox Code Playgroud)

然后,zippo在值上下文衰减到类型的指针:指向数组[2]的指针int.在代码中:

int (*p1)[2] = zippo;
Run Code Online (Sandbox Code Playgroud)

是有效的,而

int **p2 = zippo;
Run Code Online (Sandbox Code Playgroud)

将触发"不兼容的指针分配"警告.

zippo如上述所定义,

int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];
Run Code Online (Sandbox Code Playgroud)

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