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

时间:2021-02-16 19:58:44

I am new to C and got stuck on "How to pass multidimensional array to a function". I do understand that you have to pass column size so that if you want to go from a[0][0] to a[1][0] it can calculate the size of 1-D array and can jump over it.

我是C的新手,被“如何将多维数组传递给函数”困住了。我知道你必须传递列的大小如果你想要从[0][0]到[1][0]它可以计算一维数组的大小并可以跳过它。

I have written a small program:

我写了一个小程序:

#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);
}

I expected that this code will print the letter c, since temp initially points to 'a' and once we increment it, it will skip over first 1-d array and go to first element of second 1-d array which is 'c'. But it does not work that way I guess.

我原以为这段代码会输出字母c,因为temp最初指向a,一旦我们对它进行递增,它就会跳过第一个1-d数组,转到第二个1-d数组的第一个元素,即c。但我猜它不是这样的。

Please explain the how compiler computes these addresses.

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

3 个解决方案

#1


3  

For function argument char temp[][2], temp decays to a pointer. But only for the first (outer) dimension. So it is effectively a pointer to array [2] of char.

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

Incrementing the pointer will advance it to the next outer index, as you already assumed.

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

So, you either have to use (*temp)[0] or **temp to get the first element. **temp works, because *temp is an array itself, so it decays to a pointer to the first element of the inner array. The second (left) * then dereferences this pointer: c.

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

Note that, allthough it uses the same syntax like char **temp, they are fundamentally different. A pointer is not an array and here, incrementing temp will only advance by the size of a pointer, which is not what you want.

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

Note that the initializer would better be according to the 2-simensional nature:

注意,初始化器最好是根据2-simensional特性:

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

This ensures you get the correct values for the inner arrays and is good practice. Omitting a value in the non-nested form will result in wrong sequence for the inner array. When having enabled the recommended warnings (-Wall) at least, gcc warns about missing braces.

这将确保您获得内部数组的正确值,并且是良好的实践。在非嵌套格式中省略一个值将导致内部数组的错误序列。至少在启用了建议的警告(-Wall)之后,gcc会警告说缺少括号。

#2


6  

The pointer arithmetic is good. You just forgot to dereference *temp, which has type char[2].

指针算法很好。您刚刚忘记取消引用*temp,它的类型是char[2]。

Change it to **temp, and you'll get an output c.

将它更改为**temp,将得到输出c。

#3


3  

Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.

除非是运算符的操作数或一元&操作符,或者是一个字符串文字被用来初始化一个数组的声明,一个“T n元数组”类型的表达式将转换(“衰变”)一个“T”指针类型的表达式,和表达式的值将数组中第一个元素的地址。

In main, the type of the expression arr in the function call foo(arr) is "2-element array of 2-element array of char"; since it isn't the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to 2-element array of char", or char (*)[2].

函数调用foo(arr)中的表达式arr的类型主要是“char的2元素数组”;由于它不是sizeof或unary &运算符的操作数,它“decays”表示类型“指向char”的类型“指针”,或char(*)[2]。

Thus, the parameter temp is type char (*)[2], and it points to the first element of arr. The parameter declaration char temp[][2] is equivalent to char (*temp)[2]. The expression *temp is equivalent to temp[0], and both have type "2-element array of char" (char [2]). The expression temp + 1 gives you the address of the next 2-element array of char, so *(temp + 1) is equivalent to temp[1].

因此,参数temp是char(*)[2]类型,它指向arr的第一个元素。参数声明char temp[][2]等价于char (*temp)[2]。表达式*temp等价于temp[0],它们都具有“char的2元素数组”(char[2])。表达式temp + 1给出了char下一个2元素数组的地址,因此*(temp + 1)等价于temp[1]。

Here's a table to summarize all of that:

这里有一张表格来总结所有这些:

    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'

So, in your print statement, you would write either

所以,在你的打印语句中,你要么写要么写

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

or

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

or

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

The expressions arr, &arr, *arr, arr[0], &arr[0], *arr[0], and &arr[0][0] all yield the same value - the address of the first element of arr (remember that the address of the array and the address of the first element of the array are the same). They just differ in type.

表达式arr、&arr、*arr、arr[0]、&arr[0]、*arr[0]和&arr[0][0]都产生相同的值——arr的第一个元素的地址(记住数组的地址和数组的第一个元素的地址是相同的)。它们只是类型不同。

Note that &temp gives us a different value than &arr. Since temp was declared as a pointer, not an array, &temp gives us the address of the pointer variable.

注意&temp给我们的值与&arr不同。因为temp声明为指针,而不是数组,&temp给出了指针变量的地址。

A picture may help:

一幅画可以帮助:

      +---+    
 arr: |'a'|  arr[0][0] <------------------+ before temp++
      +---+                               |
      |'b'|  arr[0][1]                    |
      +---+                               |
      |'c'|  arr[1][0] <--+ after temp++  |   
      +---+               |               |
      |'d'|  arr[1][1]    |               |
      +---+               |               |
       ...                |               |
      +---+               |               |
temp: |   |---------------+---------------+
      +---+

#1


3  

For function argument char temp[][2], temp decays to a pointer. But only for the first (outer) dimension. So it is effectively a pointer to array [2] of char.

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

Incrementing the pointer will advance it to the next outer index, as you already assumed.

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

So, you either have to use (*temp)[0] or **temp to get the first element. **temp works, because *temp is an array itself, so it decays to a pointer to the first element of the inner array. The second (left) * then dereferences this pointer: c.

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

Note that, allthough it uses the same syntax like char **temp, they are fundamentally different. A pointer is not an array and here, incrementing temp will only advance by the size of a pointer, which is not what you want.

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

Note that the initializer would better be according to the 2-simensional nature:

注意,初始化器最好是根据2-simensional特性:

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

This ensures you get the correct values for the inner arrays and is good practice. Omitting a value in the non-nested form will result in wrong sequence for the inner array. When having enabled the recommended warnings (-Wall) at least, gcc warns about missing braces.

这将确保您获得内部数组的正确值,并且是良好的实践。在非嵌套格式中省略一个值将导致内部数组的错误序列。至少在启用了建议的警告(-Wall)之后,gcc会警告说缺少括号。

#2


6  

The pointer arithmetic is good. You just forgot to dereference *temp, which has type char[2].

指针算法很好。您刚刚忘记取消引用*temp,它的类型是char[2]。

Change it to **temp, and you'll get an output c.

将它更改为**temp,将得到输出c。

#3


3  

Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array.

除非是运算符的操作数或一元&操作符,或者是一个字符串文字被用来初始化一个数组的声明,一个“T n元数组”类型的表达式将转换(“衰变”)一个“T”指针类型的表达式,和表达式的值将数组中第一个元素的地址。

In main, the type of the expression arr in the function call foo(arr) is "2-element array of 2-element array of char"; since it isn't the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to 2-element array of char", or char (*)[2].

函数调用foo(arr)中的表达式arr的类型主要是“char的2元素数组”;由于它不是sizeof或unary &运算符的操作数,它“decays”表示类型“指向char”的类型“指针”,或char(*)[2]。

Thus, the parameter temp is type char (*)[2], and it points to the first element of arr. The parameter declaration char temp[][2] is equivalent to char (*temp)[2]. The expression *temp is equivalent to temp[0], and both have type "2-element array of char" (char [2]). The expression temp + 1 gives you the address of the next 2-element array of char, so *(temp + 1) is equivalent to temp[1].

因此,参数temp是char(*)[2]类型,它指向arr的第一个元素。参数声明char temp[][2]等价于char (*temp)[2]。表达式*temp等价于temp[0],它们都具有“char的2元素数组”(char[2])。表达式temp + 1给出了char下一个2元素数组的地址,因此*(temp + 1)等价于temp[1]。

Here's a table to summarize all of that:

这里有一张表格来总结所有这些:

    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'

So, in your print statement, you would write either

所以,在你的打印语句中,你要么写要么写

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

or

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

or

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

The expressions arr, &arr, *arr, arr[0], &arr[0], *arr[0], and &arr[0][0] all yield the same value - the address of the first element of arr (remember that the address of the array and the address of the first element of the array are the same). They just differ in type.

表达式arr、&arr、*arr、arr[0]、&arr[0]、*arr[0]和&arr[0][0]都产生相同的值——arr的第一个元素的地址(记住数组的地址和数组的第一个元素的地址是相同的)。它们只是类型不同。

Note that &temp gives us a different value than &arr. Since temp was declared as a pointer, not an array, &temp gives us the address of the pointer variable.

注意&temp给我们的值与&arr不同。因为temp声明为指针,而不是数组,&temp给出了指针变量的地址。

A picture may help:

一幅画可以帮助:

      +---+    
 arr: |'a'|  arr[0][0] <------------------+ before temp++
      +---+                               |
      |'b'|  arr[0][1]                    |
      +---+                               |
      |'c'|  arr[1][0] <--+ after temp++  |   
      +---+               |               |
      |'d'|  arr[1][1]    |               |
      +---+               |               |
       ...                |               |
      +---+               |               |
temp: |   |---------------+---------------+
      +---+