int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%u %u",*(stud+1),stud+1);
printf("%u, %u", &stud,stud);
为什么这个语句打印出类似的值,stud [1]或*(stud + 1)实际上是一个数组,因此必须得到基地址,即& stud [0] [0],但是stud本身是一个指针数组数组。第三个语句也打印相同的值。
答案 0 :(得分:2)
您的观察结果是正确的,表达式都是地址结果。但是每个标准的那些地址的类型是不同的。你的短语"但是stud本身是一个指向数组数组的指针"。不准确。 stud
是一个数组数组。指针不是数组。经过几十年的努力,我想出了一个描述它是如何运作的坚实的白话,并坚决拒绝走过“衰败”#34;木板(在C标准中恰好一次次出现的单词,即使在那里用作动词脚注),我能想到的最好的是:
指针不是数组。指针保存地址。数组是一个地址。
每个表达式如下所示给定int stud[5][2];
stud int (*)[2]
stud+1 int (*)[2]
*(stud+1) int *
&stud int (*)[5][2]
记住,根据标准,数组的表达值是其第一个元素的地址,而指向元素类型的指针是所述地址的类型。在两个输出中,每对表达式都具有相同的地址,但它们不同的类型。这可以通过原始代码的一些扩展来验证:
#include <stdio.h>
int main()
{
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%p %p\n", *(stud+1), stud+1);
printf("%p %p\n", &stud,stud);
int (*p1)[2] = stud+1; // OK
// int (*p2)[2] = *(stud+1); // incompatible types
int *p3 = *(stud+1); // OK
int (*p4)[5][2] = &stud; // OK
return 0;
}
答案 1 :(得分:2)
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
上述语句将stud
定义为5
个元素的数组,其中每个元素的类型为int[2]
,即2
个整数数组。它还使用初始化列表初始化数组。
现在,在表达式stud + 1
中,数组stud
衰变为指向其第一个元素的指针。因此,stud + 1
的计算结果为&stud[1]
,类型为int (*)[2]
,即指向2
整数数组的指针。然后*(stud + 1)
为*(&stud[1])
,即stud[1]
。 stud[1]
又是一个数组类型,即int[2]
,所以它再次衰减到指向其第一个元素的指针,即&stud[1][0]
(这是数组第二个元素的基址) stud[1]
来电中的printf
}。
请注意,stud + 1
和*(stud + 1)
评估为相同的地址,但它们的类型不同。
同样,&stud
和stud
会衰减到相同的地址,但它们是不同的类型。 stud
的类型为int[5][2]
,其中&stud
的类型为int (*)[5][2]
。
为什么这个语句打印出类似的值,stud [1]或*(stud + 1)实际上是一个数组,因此必须得到基地址,即&amp; stud [0] [0],但是 stud本身是指向数组数组的指针。
你错了。 stud[1]
或*(stud + 1)
的基地址为&stud[1][0]
,而非&stud[0][0]
。此外,stud
不是指针而是数组类型。在某些情况下它会衰减到指向其第一个元素的指针,但它确实意味着它是一个指针。
此外,您应该使用%p
转换说明符来打印地址。
答案 2 :(得分:1)
不使用任何衰减语法,它可能更清晰(这些地址与您的代码相同;第一行的顺序相反;我的括号是多余的,但希望它能提高此示例的清晰度):
printf( "%p %p\n", &(stud[1]), &(stud[1][0]) );
printf( "%p %p\n", &(stud), &(stud[0]) );
在这两种情况下,行上的第一个地址与第二个地址匹配,因为数组的第一个元素与数组位于同一地址。数组不能有初始填充,而在C中,对象的地址是其第一个字节的地址。
stud
的第一个元素是stud[0]
,stud[1]
的第一个元素是stud[1][0]
。
答案 3 :(得分:0)
由于您尝试显示的所有这些值都是指针,因此您应该使用%p
而不是%u
。如果你这样做,你会看到地址指向:
printf("%p, %p", &stud,stud);
不同于:
printf("%p %p",*(stud+1),stud+1);
因为正如你所说stud
是一个指向数组数组的指针。
答案 4 :(得分:0)
让我们分析一下程序
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
现在地址将是这样的(假设2字节整数)。括号表示数组中的相应元素。
1 element of 2-D array ---> 4001(1) 4003(2)
2 element of 2-D array ---> 4005(3) 4007(4)
3 element of 2-D array ---> 4009(5) 4011(6)
4 element of 2-D array ---> 4013(7) 4015(8)
5 element of 2-D array ---> 4017(9) 4019(8)
我们知道arr [i]给出了数组的第i个元素。所以当我们说stud [0]时,我们期望数组stud[5][2]
的第0个元素。
我们可以假设二维数组作为一维数组的集合。因此,对于像printf("%u",stud[0])
这样的语句,我们将删除要打印的第0个元素,以及该数组的第0个元素。它是一维数组。我们知道只需提及1-D阵列就可以得到它的基地址。因此printf
将打印第0个1-D数组的基址,依此类推。
通过这些信息,我们可以分析您的问题。
记住stud是二维数组。 stud
被视为指向2-D数组的第0个元素的指针。所以(stud + 1)
会给出2-D数组的第2个元素的地址。因此打印(stud+1)
将打印螺柱阵列的第二个元素的地址。它是什么。它将是4005以上的地址。
现在让我们看看为什么*(stud +1)也给出相同的值。
现在我们知道*(stud +1)
相当于stud[1]
。从上面我们知道stud [1]会打印第二个1-D阵列的基地址。什么是第二个位置的1-d数组,它是(3,4)地址(4005,4007)。那么什么是基地址。它是4005.因此*(stud+1)
也打印4005。
现在你说stud[0] and &stud[0]
打印相同的值。
从上面stud [0]是1-d数组并打印它给出它的基地址。现在这样&amp; stud [0]应该给出与其基地址相同的1-D数组的地址。因此,他们打印相同的地址。
类似的解释适用于其他情况。