繁体   English   中英

二维数组变量指针混淆

[英]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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM