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寻址所需的数学运算.
这与做的非常不同:
int** zippo
Run Code Online (Sandbox Code Playgroud)
要么
int* zippo[4]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将创建一个包含四个指针的数组,这些指针可以分配给其他数组.
zippo
不是指针.这是一个数组值数组. zippo
和zippo[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
,那么名称pt
是T *
值上下文中的类型.对于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);
,但指针的不同之处在于它们分别指向整个矩阵,一行和一个整数.