二维数组和指针

时间:2014-05-24 03:01:54

标签: c arrays pointers

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本身是一个指针数组数组。第三个语句也打印相同的值。

5 个答案:

答案 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)评估为相同的地址,但它们的类型不同。

同样,&studstud会衰减到相同的地址,但它们是不同的类型。 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数组的地址。因此,他们打印相同的地址。

类似的解释适用于其他情况。