我对2D数组(C语言)有一个基本的疑问。考虑如下的二维数组声明
int array[3][5];
现在,当我执行以下操作时,printf下面的两个输出都是相同的:
printf("%u\n", array);
printf("%u\n", *(array));
现在尝试以下内容:
printf("%u\n", array+1);
printf("%u\n", *(array)+1);
输出不同。我得到第二个printf引用数组[0] [1]而第一个引用数组[1] [0]。这是如何运作的? array是指向什么的指针?
提前致谢
答案 0 :(得分:5)
我会尝试给你一个技术上正确的解释,这样你就会知道发生了什么。不是很复杂,但确实是反直觉的。
<强>说明:强>
在C中有“左值”,它基本上代表在内存中某处有“可分配”的对象,“rvalues”代表“概念”值(不需要特别放在任何地方)。 / p>
例如,如果定义int a = 5;
,则a
是类型为int且值为5的左值。此外,它可以解释为(或者更确切地说,转换为)int类型的右值。这样的rvalue仍然会等于5,但它不再包含有关a
在内存中位置的信息。
有些表达式需要左值(比如运算符的左侧=因为你必须分配给一个对象),有些需要rvalues(比如operator +,因为你只需要添加时的积分值,或者右边的操作员=)。如果表达式需要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`
从左值到右值的转换通常是微不足道的,不可察觉的(就像从标有a
的架子中取出数字5)。数组基本上是例外。
重要的是: C 中没有数组类型的右值。有指针左值和右值,整数左值和右值,结构左值和右值等......但只有左值数组。当您尝试将数组类型的左值转换为右值时,您不再拥有数组,您有一个指向该数组的第一个成员的指针。这是C(和C ++)中数组混淆的根源。
<强>解释强>
array
*(array)
array+1
*(array)+1
array
是int[3][5]
类型的左值(5个整数的3个整数的数组)。当您尝试将其传递给函数时,它会收到类型为int (*)[5]
的指针(指向5个整数的数组),因为这是在左值到右值转换后剩下的内容。
*(array)
很诡异。首先执行左值到右值,得到类型为int(*)[5]
的右值,然后operator*
获取该值,并返回类型为int[5]
的左值,然后您尝试传递给功能。因此,它再次转换为右值,产生int*
。
array+1
导致数组转换为类型int(*)[5]
的右值,并且rvalue增加1,因此(根据指针算术的规则)指针移动1 * sizeof(int[5])
字节转发。
*(array)+1
:之前看到2点,但类型int*
的最终右值再次由指针算术规则增加1 * sizeof(int)
。
这里没有神秘感!
答案 1 :(得分:2)
C中的2D数组令人困惑
array和* array都是相同的指针,但类型不同
数组的类型为int [3] [5](这是一个数组,大小为5,int [3]数组)。
* array是数组的第一行,类型为int [3]
array + 1表示数组加一个元素。数组的元素是int [3],因此前进了12个字节
* array + 1表示*数组加一个元素。 *数组的元素是int,所以前进4个字节。
答案 2 :(得分:1)
数组不是指针。忽略任何试图告诉您的答案,书籍或教程。
在大多数情况下,数组类型的表达式是转换(在编译时)到指向数组第一个元素的指针。例外情况是:
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));
答案 3 :(得分:0)
你可以这样理解:
数组指向3行,每行5列
当您执行数组+ 1时,行会更改,因此您将转到第1行。您应该尝试使用*(array + 1)进行访问。
执行*(数组)时,指向第0行,*(数组)+1在列中向前移动,因此元素为数组[0] [1]
答案 4 :(得分:0)
指针中的单位增量符合数据类型的大小。