每天一小时的C编程有这样的引用:
与一维数组一样,多维数组的名称是指向第一个数组元素的指针。
#include <stdio.h>
int m[2][4];
int main() {
printf("%p\n", m); // 1
printf("%p\n", &(m[0])); // 2
printf("%p\n", m[0]); // 3
printf("%p\n", &m[0][0]); // 4
}
这会为所有语句打印相同的值。根据引用,1 == 2和3 == 4是有意义的。但我不明白2 == 3.如何m[0]
的地址与m[0]
相同?
答案 0 :(得分:4)
当分配二维(或任何维度)数组时,它只占用其元素的内存(内存未分配给数组名称或任何其他数组元素,如{{1}在你的情况下,m[0]
和const指针一样。)
因为没有任何物理内存分配给那些(实际上甚至不需要),所以在尝试打印时会得到相同的地址。在你的情况下,
因为它是一个二维数组,因为m[1]
指向m
,而m[0]
又指向m[0][0]
,所有这些的提取地址将提供相同的值(同样适用于m[1]
和m[1][0]
)。
**为了更好地理解,请看这个(如果你打印它们会是这样的)
_____ _____ _____
|0x100| --> |0x100| --> |value|
0x100|_____| 0x100|_____| 0x100|_____|
m m[0] m[0][0]
* value
是m [0] [0]
下面,
m
和m[0]
就像指针一样,但没有物理实现(不占用内存),编译器处理如何处理它们。
*虽然我已向0x100
和0x100
显示m
包含m[0]
,但0x100
实际上包含m[0][0]
的数据/值,但是如果你做任何编译器处理它们的操作。
**正因为如此,int *p = malloc(n * sizeof(int))
这是可能的,因为p
现在占用了指向数组起始地址的内存。如果您将p
视为int const *p
,则可以将其视为没有动态分配的普通数组。
答案 1 :(得分:3)
数组仅包含数据,它不包含任何其他内容。这个数据有一个地址,从它开始 - 这是第一个元素的地址。
&#34;多维数组的名称是指向第一个数组元素的指针&#34;是过度简化而不是真的正确。数组不是指针,指针不是数组。
但是,只要在表达式中使用,数组的名称(任何维度)都会生成一个指向数组第一个元素的临时指针。这通常被称为&#34;数组衰减成指针&#34;。
现在,这些行之间唯一不同的是指针的类型:
类型int[2][4]
的数组衰减为指向第一个元素的指针。 2D数组中的第一个元素是int [4]
类型的一维数组。指向此类数组的指针是数组指针,int (*)[4]
。
&m[0]
给出第一个元素的地址,即第一个1D数组的地址。所以这完全相当于1)。
m[0]
给出了第一个元素,仍然是一维数组。哪个衰变成指向其第一个元素的指针。 int [4]
的第一个元素是int
,因此我们得到一个指向int*
的指针。
&m[0][0]
给出指向第一个数组的第一个元素int*
的指针。相当于3)。
所有这些指针类型都具有相同的地址,因为2D数组从与第一个项目1D数组相同的地址开始。而这又从与第一个项目相同的地址开始,即第一个整数。
各种不同的指针类型只是高级语言语法。这些类型不会持续存在于机器代码中,其中一切都只是原始地址。
答案 2 :(得分:0)
第一维将存储子阵列(行)的地址。
E.g。您有m[2][4]
,因此m[0]
评估包含从m[0][0]
到m[0][3]
的元素的第一行的地址,m[1]
评估第二行的地址包含来自{的元素{1}}至m[1][0]
。
如果您尝试打印m[1][3]
和m[0]
,您会看到地址差异是m[1]
字节之间行的总大小。