Kau*_*ain 5 c arrays multidimensional-array
我对2D数组(C语言)有一个基本的疑问.考虑如下的2D数组的声明
int array[3][5];
Run Code Online (Sandbox Code Playgroud)
现在,当我执行以下操作时,两个printf的输出都是相同的:
printf("%u\n", array);
printf("%u\n", *(array));
Run Code Online (Sandbox Code Playgroud)
现在尝试以下内容:
printf("%u\n", array+1);
printf("%u\n", *(array)+1);
Run Code Online (Sandbox Code Playgroud)
输出是不同的.我得到第二个printf引用数组[0] [1]而第一个引用数组[1] [0].这是如何运作的?数组是什么指针?
提前致谢
我会尝试给你一个技术上正确的解释,这样你就会知道发生了什么.不是很复杂,但确实是反直觉的.
介绍:
在C中,存在"左值",其基本上表示在存储器中具有位置的"可分配"对象,以及"右值",其表示"概念"值(不需要特别放置在任何地方).
例如,如果你定义int a = 5;,则a是int类型和值5的左值.此外,它可以被解释为(或者更确切地说,转换为)int类型的右值.仍然知道这样的rvalue等于5,但它将不再包含有关a内存中位置的信息.
有些表达式需要左值(比如运算符的左侧=因为你必须分配给一个对象),有些需要rvalues(比如operator +因为你只需要添加时的积分值,或者运算符的右侧=) .如果表达式需要rvalue但是传递左值,则它将转换为rvalue.
此外,只有rvalues传递给C中的函数(这意味着C严格按值调用,而不是按引用调用).
一些例子:
int a = 1;
a; // a is an lvalue of type int and value 1
a = a+3; // here the `a` is converted to an rvalue of type int and value 1, then after the addition there's an assignment, on the lhs there's an lvalue `a` and an rvalue `4`
Run Code Online (Sandbox Code Playgroud)
从左值到左值的转换通常是微不足道的,并且是不可察觉的(就像从标记的架子上取5号a).数组基本上是例外.
重要的是:C中没有数组类型的右值.有指针左值和右值,整数左值和右值,结构左值和右值等......但只有左值数组.当您尝试将数组类型的左值转换为右值时,您不再拥有数组,您有一个指向该数组的第一个成员的指针.这是C(和C++)中数组混淆的根源.
说明:
array*(array)array+1*(array)+1array是一个左值类型int[3][5](3个整数的5个整数的数组).当你尝试将它传递给一个函数时,它会收到一个类型的指针int (*)[5](指向5个整数的数组的指针),因为这是在左值到右值转换后剩下的.
*(array)很狡猾.首先执行左值到右值,得到一个rvalue类型int(*)[5],然后operator*取rvalue并返回一个类型的左值int[5],然后你尝试传递给函数.因此,它又被转换为右值,从而产生了一个int*.
array+1导致数组转换为类型的右值,int(*)[5]并且rvalue增加1,因此(根据指针算术的规则)指针向前移动1 * sizeof(int[5])字节.
*(array)+1:看到之前的2点,但是类型的最终rvalue int*再次增加,再次通过指针算术的规则,by 1 * sizeof(int).
这里没有神秘感!
数组不是指针。忽略任何试图告诉你相反的答案、书籍或教程。
在大多数情况下,数组类型的表达式会(在编译时)转换为指向数组第一个元素的指针。例外情况是:
sizeof(的操作数sizeof arr产生数组的大小,而不是指针的大小)&(&arr产生数组的地址,而不是其第一个元素的地址 - 相同的内存位置,不同的类型)。这与您的示例特别相关。char s[6] = "hello";不复制字符串文字的地址,而是复制其值)二维数组只不过是数组的数组。还有其他数据结构可以使用相同的x[y][z]语法,但它们不是真正的二维数组。你的是。
索引运算符[]是根据指针算术定义的。 x[y]方法*(x+y)。
您的代码的行为遵循这些规则。
阅读comp.lang.c FAQ的第 6 部分。这是我见过的对这个东西最好的解释。
并且不要用于"%u"打印指针值;转换为void*并使用"%p".
printf("%p\n", (void*)array);
printf("%p\n", (void*)*(array));
Run Code Online (Sandbox Code Playgroud)