C 二维数组变量指针混淆

C 二维数组变量指针混淆,c,arrays,multidimensional-array,C,Arrays,Multidimensional Array,我对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],第一个printf指向数组[1][0]。

我对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],第一个printf指向数组[1][0]。这是怎么回事?数组是指向什么的指针


提前感谢

您可以这样理解:

数组指向3行,每行5列

当您执行数组+1时,行会发生变化,所以您可以转到第1行。您应该尝试使用*(数组+1)进行访问


当您使用*(数组)时,您指向第0行,*(数组)+1在列中向前移动,所以元素是数组[0][1]

C中的2D数组令人困惑。
array和*array都是相同的指针,但类型不同。
数组的类型为int[3][5](这是一个大小为5的int[3]数组的数组)。
*数组是数组的第一行,类型为int[3]。
数组+1表示数组加一个元素。数组的一个元素是int[3],因此它向前移动了12个字节。

*数组+1表示*数组加一个元素。*数组的一个元素是int,因此向前4字节。
指针的单位增量取决于数据类型的大小。

我将尝试给您一个技术上正确的解释,以便您知道发生了什么。不是很复杂,但确实违反直觉

简介:

在C语言中,有些“左值”基本上表示在内存中某处有位置的“可分配”对象,有些“右值”则表示“概念”值(不需要特别放在任何地方)

例如,如果定义
inta=5
,则
a
是int类型的左值,值为5。还可以将其解释为(或者更确切地说,转换为)int类型的右值。这样的右值仍然等于5,但它不再包含有关
a
在内存中位置的信息

有些表达式需要左值(例如运算符=的左侧,因为必须指定给对象),有些表达式需要右值(例如运算符+因为在添加时只需要整数值,或者运算符=)的右侧)。如果表达式需要右值,但传递了左值,则会将其转换为右值

此外,只有右值传递给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+1
  • *(数组)+1
array
int[3][5]
类型的左值(3个int的数组,5个int)。当您尝试将其传递给函数时,它将接收类型为
int(*)[5]
(指向5个int数组的指针),因为这是左值到右值转换后剩下的指针

*(数组)
是个骗子。首先执行从左值到右值的操作,得到类型为
int(*)[5]
,然后
运算符*
获取该右值并返回类型为
int[5]
的左值,然后尝试传递给函数。因此,它再次被转换为右值,结果是
int*

array+1
导致数组转换为
int(*)[5]
类型的右值,并且该右值增加1,因此(根据指针算术规则)指针向前移动
1*sizeof(int[5])
字节

*(数组)+1
:请参见前面的两点,但类型为
int*
的最后一个右值会根据指针算术规则和
1*sizeof(int)
增加


这里没有神秘

数组不是指针。忽略任何试图告诉你其他情况的答案、书籍或教程

在大多数上下文中,数组类型的表达式(在编译时)转换为指向数组第一个元素的指针。例外情况如下:

  • sizeof
    的操作数(
    sizeof arr
    产生数组的大小,而不是指针的大小)
  • 一元
    &
    的操作数(
    &arr
    产生数组的地址,而不是它的第一个元素的地址——相同的内存位置,不同的类型)。这与您的示例特别相关
  • 初始化器中用于初始化数组对象的字符串文字(
    char s[6]=“hello”;
    不复制字符串文字的地址,而是复制其值)
二维数组就是数组的数组。还有其他数据结构可以使用相同的
x[y][z]
语法,但它们不是真正的二维数组。你的是

[]
索引运算符是根据指针算法定义的<代码>x[y]表示
*(x+y)

代码的行为遵循这些规则

请阅读本手册第6节。这是我见过的最好的解释

不要使用
“%u”
打印指针值;转换为
void*
并使用
“%p”


那么b/w数组+1和*(数组+1)的区别是什么呢?当我把它们都打印出来时,我得到了相同的内存位置非常好的解释,但对于第二种情况,我有一个查询*(
printf("%p\n", (void*)array);
printf("%p\n", (void*)*(array));