指针算术和c中的二维数组?

时间:2015-10-02 13:36:45

标签: c arrays multidimensional-array

我是C的新手并且坚持“如何将多维数组传递给函数”。我明白你必须传递列大小,这样如果你想从a[0][0]转到a[1][0]它可以计算一维数组的大小并且可以跳过它。

我写了一个小程序:

#include<stdio.h>
void foo(char[][2]);
int main()
{
     char arr[2][2] = {'a','b','c','d'};

     foo(arr);
     return 0;
}

void foo(char temp[][2])
{
      temp++;
      printf("%c",*temp);
}

我希望此代码会打印字母c,因为temp最初指向'a',一旦我们递增它,它将跳过第一个1-d数组并转到第二个1-d数组的第一个元素是'c'。但是我觉得这种方式不起作用。

请解释编译器如何计算这些地址。

3 个答案:

答案 0 :(得分:6)

指针算术很好。您忘记取消引用*temp,其类型为char[2]

将其更改为**temp,您将获得输出c

答案 1 :(得分:3)

对于函数参数char temp[][2]temp衰减到指针。但仅限于第一(外)维度。所以它实际上是指向[2] 的数组char指针。

增加指针会将其推进到下一个外部索引,正如您已经假设的那样。

因此,您必须使用(*temp)[0]**temp来获取第一个元素。 **temp有效,因为*temp本身就是一个数组,所以它衰减到指向内部数组的第一个元素的指针。第二个(左)*然后取消引用此指针:c

请注意,虽然它使用与char **temp相同的语法,但它们根本不同。指针不是数组,在这里,递增temp只会增加指针的大小,这不是你想要的。

请注意,初始化程序最好是根据2维性质:

{ { 'a', 'b' } , { 'c', 'd' } }

这可确保您获得内部数组的正确值,这是一种很好的做法。省略非嵌套表单中的值将导致内部数组的序列错误。启用推荐警告(-Wall至少后,gcc会警告错误的大括号。

答案 2 :(得分:3)

除非它是sizeof或一元&运算符的操作数,或者是用于初始化声明中的另一个数组的字符串文字,否则表达式为类型&#34; T&#34;的N元素数组;将被转换(&#34;衰减&#34;)到类型为#34的表达式;指向T&#34;的指针,并且表达式的值将是该表达式中第一个元素的地址阵列。

main中,函数调用arr中的表达式foo(arr)的类型为&#34;包含char&的2元素数组的2元素数组#34 ;;因为它不是sizeof或一元&运算符的操作数,所以&#34;衰变&#34;表达式为&#34;指向char&#34;或char (*)[2]的2元素数组的指针。

因此,参数tempchar (*)[2]类型,它指向arr的第一个元素。参数声明char temp[][2]等同于char (*temp)[2]。表达式*temp等同于temp[0],并且两者都具有char&#34;的类型&#34; 2元素数组; (char [2])。表达式temp + 1为您提供char的下一个2元素数组的地址,因此*(temp + 1)相当于temp[1]

这是一张总结所有内容的表格:

    Expression        Type            Decays To         Value
    ----------        ----            ---------         -----
           arr        char [2][2]     char (*)[2]       &arr[0][0]
          *arr        char [2]        char *            arr[0]
          &arr        char (*)[2][2]  n/a               &arr[0][0]
        arr[i]        char [2]        char *            &arr[i][0]
       *arr[i]        char            n/a               arr[i][0]
       &arr[i]        char (*)[2]     n/a               &arr[i][0]
     arr[i][j]        char            n/a               arr[i][j]

          temp        char (*)[2]     n/a               &arr[0][0]
         *temp        char [2]        char *            arr[0]
         &temp        char (**)[2]    n/a               addr of temp variable
       temp[i]        char [2]        char *            &arr[i][0]
      *temp[i]        char            n/a               arr[i][0]
      &temp[i]        char (*)[2]     n/a               &arr[i][0]
    temp[i][j]        char            n/a               arr[i][j]

       arr + 1        char [2][2]     char (*)[2]       &arr[1][0]
    *(arr + 1)        char [2]        char *            arr[1]
      temp + 1        char (*)[2]     n/a               &arr[1][0]
   *(temp + 1)        char [2]        char *            arr[1]

     arr[0][0]        char            n/a               'a'
     arr[0][1]        char            n/a               'b'
     arr[1][0]        char            n/a               'c'
     arr[1][1]        char            n/a               'd'

        **temp        char            n/a               'a'
      *temp[0]        char            n/a               'a'
    temp[0][0]        char            n/a               'a'

  **(temp + 1)        char            n/a               'c'
      *temp[1]        char            n/a               'c'
    temp[1][0]        char            n/a               'c'

所以,在你的print语句中,你会写

printf("%c", **temp); // temp == &arr[1][0] after temp++

printf("%c", *temp[0]); // temp[0] == arr[1] after temp++

printf("%c", temp[0][0]); // temp[0][0] == arr[1][0] after temp++

表达式arr&arr*arrarr[0]&arr[0]*arr[0]&arr[0][0]都会产生相同的 - arr的第一个元素的地址(请记住,数组的地址和数组的第一个元素的地址是相同的)。他们的类型不同。

请注意,&temp为我们提供了与<{1}}不同的值。由于temp被声明为指针而不是数组,&arr为我们提供了指针变量的地址。

图片可能会有所帮助:

&temp