[英]2D array variable pointer confusion
我对2D数组(C语言)有一个基本的疑问。 考虑如下的2D数组的声明
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]。 这是如何运作的? 数组是什么指针?
提前致谢
我会尝试给你一个技术上正确的解释,这样你就会知道发生了什么。 不是很复杂,但确实是反直觉的。
介绍:
在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`
从左值到左值的转换通常是微不足道的,并且是不可察觉的(就像从标a
a的架子上取5号)。 数组基本上是例外。
重要的是: C中没有数组类型的右值 。 有指针左值和右值,整数左值和右值,结构左值和右值等......但只有左值数组。 当您尝试将数组类型的左值转换为右值时,您不再拥有数组,您有一个指向该数组的第一个成员的指针。 这是C(和C ++)中数组混淆的根源。
说明:
array
*(array)
array+1
*(array)+1
array
是int[3][5]
类型的左值(5个整数的3个整数的数组)。 当你试图将它传递给一个函数时,它会收到一个类型为int (*)[5]
指针(指向5个整数的数组),因为这是在左值到右值转换后剩下的。
*(array)
是tricker。 首先执行左值到右值,得到一个类型为int(*)[5]
rvalue,然后operator*
取该rvalue并返回一个类型为int[5]
的左值,然后你尝试传递给该函数。 因此它再次转换为右值,产生一个int*
。
array+1
导致数组转换为int(*)[5]
类型的rvalue,并且rvalue增加1,所以(根据指针算术的规则)指针移动1 * sizeof(int[5])
字节转发。
*(array)+1
:之前看到2个点,但int*
类型的最终rvalue再次通过指针算术规则增加1 * sizeof(int)
。
这里没有神秘感!
C中的2D数组令人困惑。
array和* array都是相同的指针,但类型不同。
array的类型为int [3] [5](这是一个大小为5的int [3]数组的数组)。
* array是数组的第一行,类型为int [3]。
array + 1表示数组加一个元素。 数组的元素是int [3],所以前进了12个字节。
* array + 1表示*数组加一个元素。 *数组的元素是int,因此前进了4个字节。
数组不是指针。 忽略任何试图告诉您的答案,书籍或教程。
阵列型的表达,在大多数情况下,被转换 (在编译时)到一个指针数组的第一个元素。 例外情况是:
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行,每行5列
当你做数组+ 1时,行改变,所以你去第1行。 您应该尝试使用*(array + 1)进行访问。
当你执行*(数组)时,你指向第0行,*(数组)+1在列中向前移动,因此元素是数组[0] [1]
指针中的单位增量与数据类型的大小一致。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.