int main(){
int a[][3]={1,2,3,4,5,6};
int (*ptr)[3]=a;
printf(" %d",(*ptr)[1]) ;
}
我知道变量ptr
是int
类型的第一个一维数组的指针,换句话说,变量ptr
将存储前3个整数的地址,首先让我们假设a
的基址是1000
,因此我认为这个二维数组将以如下形式存储在内存中:
elements: | 1 | 2 | 3 || 4 | 5 | 6 |
addressed of each element: | 1000 | 1004 | 1008 || 1012 | 1016 | 1020 |
---------------------------------||---------------------------------
addressed of each array: 1000 1012
所以ptr
会存储1000
,也就是第一个数组的地址,这意味着*ptr
或(*ptr)[0]
会给予我第一个元素的地址,*ptr+1
或((*ptr)[1])
会给我第二个元素的地址,以此类推。
因此,据我所知,*ptr[1]
将给予第二个元素的地址,而不是它的值。
但是从输出来看,我好像错了。所以我想知道我的过程中出了什么问题。
3条答案
按热度按时间0md85ypi1#
在此部分之前,您是正确的:
这意味着
*ptr
或(*ptr)[0]
会给出第一个元素的地址(*ptr)[0]
将取消引用数组指针,然后取消引用结果数组,给出第一项的值1
。类似地,
(*ptr)[1])
将首先为您提供一个数组,然后是该数组中的第二项2
。因此,据我所知,* ptr [1]将给出第二个元素的地址,而不是其值。
不,因为
[]
的优先级比*
高,ptr[1]
会先给你第二个数组(的地址),然后你解引用它,你会得到第二个数组中第一项的值4
。这里的关键是,一旦你取消引用一个指向数组的指针,你就得到了一个数组--在"数组衰减"等方面就像任何数组一样。
最佳做法:
*
解引用数组指针。ptr[0][0]
没有那么多歧义。在本例中,使用数组指针的全部意义就在于此语法。int a[][3]={1,2,3,4,5,6};
这样草率的初始化器列表。C允许这样做,但这是一种糟糕的风格,并屏蔽了一些诊断的可能性。相反,这应该是int a[][3]={ {1,2,3}, {4,5,6} };
,作为奖励,它也是可读的,自文档化的代码。pod7payv2#
让我们考虑调用
printf
时使用的表达式首先,指针
ptr
指向二维数组中int[3]
类型的第一个元素。这是由于初始化器列表
二维数组具有两个类型为
int[3]
的元素。所以解引用指针
*ptr
得到一个int[3]
类型的左值,它是一个一维数组,然后对这个数组应用下标运算符( *ptr )[1]
,得到一维数组的第二个元素。因此将输出值
2
。这意味着 * ptr或(* ptr)[0]将提供第一个元素的地址
表达式
*ptr
和( *ptr )[0]
是两个不同类型的实体。The expression
* ptryields lvalue of the type
int [3]',使用din表达式,它可以隐式转换为指向所获得数组的第一个元素的指针。表达式
( *ptr )[0]
产生所获得的int
类型的数组的第一标量元素。因此,据我所知,* ptr [1]将给出第二个元素的地址,而不是其值。
表达式
ptr[1]
产生二维数组的类型int[3]
的第二个元素。在该表达式*ptr[1]
中,所获得的类型int[3]
的对象被隐式转换为类型int *
的指针,并且解引用该指针产生二维数组的第二个元素的类型int
的第一个元素。为了更清楚地说明这一点,请考虑如何计算下标运算符。
例如,表达式
ptr[0]
等价于*( ptr + 0 )
,而*( ptr + 0 )
又等价于*ptr
。表达式
(*ptr)[1]
等价于ptr[0][1]
。表达式
*ptr[1]
等价于*(ptr[1] )
,而*(ptr[1] )
又等价于ptr[1][0]
。一般来说,表达式
ptr[i][j]
可以用几种方法重写。0s7z1bwu3#
首先,启用编译器警告是一个好主意。然后你会被告知初始化器中缺少大括号。下面是你的程序的一个稍微清理过的版本:
如果你运行它,你会得到输出“2”,这是因为
*ptr
是数组a
的第一个元素,它本身是一个数组,因此(*ptr)[1]
是这个包含的数组的第二个元素,它是2。