二维数组变量指针混淆

时间:2011-12-25 14:35:25

标签: c arrays multidimensional-array

我对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是指向什么的指针?

提前致谢

5 个答案:

答案 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

arrayint[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)

指针中的单位增量符合数据类型的大小。