我一直在做各种关于c中的2D数组的问题,每个问题都像在我的头上撞另一个椰子,因为每个问题使用不同的方法。例如,有些人使用"取二维数组(如a[2][4]),现在这会创建两个数组,其中一个数组的大小为2,包含二维数组的每一行的地址(如有两行,每一行有四个值)"。而其他方法将其视为连续的1D数组表示。现在用哪种方法。一个合适的内存映射将是一个很大的帮助。下面是练习的示例问题。
int main()
{
unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6},
{7, 8, 9}, {10, 11, 12}};
printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3);
}
output:2036,2036,2036
现在,如果它是第一个方法,为什么x+3和*(x+3)的地址是相同的?
C语言中的内置数组总是使用"second"方法(根据您的编号),没有例外。每次当你声明1D, 2D, 3D或任何d数组时,就像在你的示例代码中一样,该数组作为一个连续的内存块在内存中布局-作为一个"组合"大小的1D数组(即所有大小的倍数)。
"first"方法只能用于"手动"组装数组(即所谓的"锯齿"或"粗糙"数组)。该语言不会使用这种方法来表示显式声明的多维数组。
但是,使用%u
格式说明符打印指针值是未定义的行为。别再这样了。功能printf
提供%p
格式的指针打印。
在x + 3
表达式中,unsigned [4][3]
类型的对象x
隐式衰减为指向x[0]
子数组的指针unsigned (*)[3]
类型的值。根据指针算术规则,x + 3
是一个unsigned (*)[3]
类型的值,它指向x[3]
子数组。
同样的事情最初发生在*(x + 3)
表达式中,除了x + 3
(同样指向x[3]
子数组)被*
操作符解引用并成为x[3]
子数组本身。在print
参数的上下文中,该子数组立即衰减为指向x[3][0]
的unsigned *
类型的值。
所以,即使x + 3
和*(x + 3)
的结果类型不同,它们仍然指向内存中完全相同的位置。这就是为什么指针的数值看起来是一样的。
下面这个简单的例子
也会发生同样的事情int main()
{
int a[10];
printf("%p %pn", (void *) &a, (void *) &a[0]);
}
输出将显示两个指针的相同数值。您的示例有点复杂,但本质上是一样的。