数组到指针衰减和传递多维数组到函数

时间:2021-08-16 21:31:23

I know that an array decays to a pointer, such that if one declared

我知道一个数组会衰减到一个指针,如果一个声明了

char things[8];

and then later on used things somewhere else, things is a pointer to the first element in the array.

之后在其他地方使用的东西,是指向数组中第一个元素的指针。

Also, from my understanding, if one declares

而且,据我的理解,如果有人宣布

char moreThings[8][8];

then moreThings is not of type pointer to char but of type "array of pointers to char," because the decay only occurs once.

此外,more不是指向char的类型指针,而是指向char的指针数组,因为衰减只发生一次。

When moreThings is passed to a function (say with prototype void doThings(char thingsGoHere[8][8]) what is actually going on with the stack?

当更多的东西被传递给一个函数时(比如使用原型void doThings(char thingsGoHere[8][8])),堆栈实际上发生了什么?

If moreThings is not of pointer type, then is this really still a pass-by-reference? I guess I always thought that moreThings still represented the base address of the multidimensional array. What if doThings took input thingsGoHere and itself passed it to another function?

如果moreThings不是指针类型,那么这真的是一个引用传递吗?我想我一直认为更多的东西仍然是多维数组的基本地址。如果doThings接收输入内容并将其传递给另一个函数呢?

Is the rule pretty much that unless one specifies an array input as const then the array will always be modifiable?

规则是,除非将数组输入指定为const,否则数组始终是可修改的吗?

I know that the type checking stuff only happens at compile time, but I'm still confused about what technically counts as a pass by reference (i.e. is it only when arguments of type pointer are passed, or would array of pointers be a pass-by-reference as well?)

我知道类型检查只在编译时发生,但是我仍然搞不清楚什么技术上被认为是传递引用(也就是说,它只在传递类型指针的参数时发生,或者指针的数组也会被传递引用吗?)

Sorry to be a little all over the place with this question, but because of my difficulty in understanding this it is hard to articulate a precise inquiry.

很抱歉在这个问题上有点跑题了,但是由于我在理解这个问题上有困难,所以很难给出一个精确的问题。

3 个解决方案

#1


22  

You got it slightly wrong: moreThings also decays to a pointer to the first element, but since it is an array of an array of chars, the first element is an "array of 8 chars". So the decayed pointer is of this type:

你可能会觉得有点不对:moreThings也会衰减到指向第一个元素的指针,但是因为它是一个chars数组的数组,所以第一个元素是一个“8 chars数组”。衰减指针是这样的

char (*p)[8] = moreThings;

The value of the pointer is of course the same as the value of &moreThings[0][0], i.e. of the first element of the first element, and also the same of &a, but the type is a different one in each case.

指针的值当然与&moreThings[0][0]的值相同,即第一个元素的第一个元素的值,也与&a的值相同,但是类型在每种情况下都是不同的。

Here's an example if char a[N][3]:

这里有一个例子,如果char [N][3]:

+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
|            a[0]           |            a[1]           |
+===========================+===========================+====
                                    a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
  • &a: address of the entire array of arrays of chars, which is a char[N][3]

    &: chars数组的整个数组的地址,即char[N][3]

  • &a[0], same as a: address of the first element, which is itself a char[3]

    bb&a b1,与第一个元素的地址相同,它本身就是一个char[3]

  • &a[0][0]: address of the first element of the first element, which is a char

    [0][0]:第一个元素的第一个元素的地址,它是一个char。

This demonstrates that different objects may have the same address, but if two objects have the same address and the same type, then they are the same object.

这说明不同的对象可能有相同的地址,但是如果两个对象有相同的地址和相同的类型,那么它们就是相同的对象。

#2


12  

"ARRAY ADDRESS AND POINTERS TO MULTIDIMENSIONAL ARRAYS"

Lets we start with 1-D array first:

我们先从一维数组开始:

  • Declaration char a[8]; creates an array of 8 elements.
    And here a is address of fist element but not address of array.

    声明char[8];创建一个包含8个元素的数组。这里a是第一个元素的地址,不是数组的地址。

  • char* ptr = a; is correct expression as ptr is pointer to char and can address first element.

    char * ptr =一个;是正确的表达式,因为ptr是指向char的指针,可以处理第一个元素。

  • But the expression ptr = &a is wrong! Because ptr can't address an array.

    但是“ptr = &a”的表达是错误的!因为ptr不能处理数组。

  • &a means address of array. Really Value of a and &a are same but semantically both are different, One is address of char other is address of array of 8 chars.

    &a是指数组的地址。a和&a的值其实是一样的,但在语义上都是不同的,一个是char的地址,另一个是8 chars数组的地址。

  • char (*ptr2)[8]; Here ptr2 is pointer to an array of 8 chars, And this time ptr2=&a is a valid expression.

    char(* ptr2)[8];这里ptr2是指向一个8字符数组的指针,而这次ptr2=&a是一个有效的表达式。

  • Data-type of &a is char(*)[8] and type of a is char[8] that simply decays into char* in most operation e.g. char* ptr = a;

    数据类型的&a是char(*)[8],类型a是char[8],在大多数操作中都只是衰变为char*,例如char* ptr = a;

    To understand better read: Difference between char *str and char str[] and how both stores in memory?

    要更好地理解:char *str和char str[]之间的区别以及两者如何存储在内存中?

Second case,

第二个案例,

  • Declaration char aa[8][8]; creates a 2-D array of 8x8 size.

    声明字符aa[8][8];创建一个8x8大小的二维数组。

  • Any 2-D array can also be viewed as 1-D array in which each array element is a 1-D array.

    任何二维数组也可以看作一维数组,其中每个数组元素都是一维数组。

  • aa is address of first element that is an array of 8 chars. Expression ptr2 = aa is valid and correct.

    aa是第一个元素的地址,它是一个包含8个字符的数组。表达式ptr2 = aa有效且正确。

  • If we declare as follows:

    如果我们声明如下:

    char (*ptr3)[8][8];    
    char ptr3 = &aa;  //is a correct expression
    

    Similarly,
    moreThings in your declaration char moreThings[8][8]; contain address of fist element that is char array of 8 elements.

    类似地,在你的声明中还有更多的东西[8][8];包含第一个元素的地址,它是8个元素的char数组。

    To understand better read: Difference between char* str[] and char str[][] and how both stores in memory?

    要更好地理解:char* str[]和char str[][]之间的区别以及这两者如何存储在内存中?


It would be interesting to know:

如果知道:

  • morething is an address of 8 char array .

    morething是8字符数组的地址。

  • *morething is an address of first element that is &morething[0][0].

    更多的东西是第一个元素的地址,它是[0][0]。

  • &morething is an address of 2-D array of 8 x 8.

    更重要的是一个2-D数组的地址,8 x 8。

    And address values of all above three are same but semantically all different.

    这三者的地址值是相同的,但在语义上是完全不同的。

  • **morething is value of first element that is morething[0][0].

    *more是第一个元素的值也就是[0][0]。

    To understand better read: Difference between &str and str, when str is declared as char str[10]?

    为了更好地理解阅读:当str被声明为char str[10]时,与str和str之间的区别?

Further more,

此外,

  • void doThings(char thingsGoHere[8][8]) is nothing but void doThings(char (*thingsGoHere)[8]) and thus accepts any array that is two dimensional with the second dimension being 8.
  • void doThings(char thingsGoHere[8][8])只是void doThings(char (*thingsGoHere)[8]),因此它接受任何二维数组,而二维数组的第二个维度是8。

About type of variables in C and C++: (I would like to add in answer)

关于C和c++中的变量类型:(我想补充一下)

  • Nothing is pass by reference in C its C++ concept. If its used in C that means author talking about pointer variable.
  • 在c++概念中,没有什么是通过引用来传递的。如果它在C中使用,那意味着作者在谈论指针变量。
  • C supports pass by Address and pass by value.
  • C支持按地址和值传递。
  • C++ supports Pass by address, pass by value and also pass by Reference.

    c++支持按地址传递、按值传递和按引用传递。

    Read: pointer variables and reference variables

    读取:指针变量和引用变量。

At the end,

最后,

  • Name Of an array is constant identifier not variable.
  • 数组的名称是常量标识符而不是变量。

#3


4  

Nicely explained by Kerrek,

很好地解释为Kerrek,

In addition to that, we can prove it by the following example:

除此之外,我们可以用下面的例子来证明:

#include <stdio.h>

int main ()
{
 int a[10][10];

 printf (".. %p  %p\n", &a, &a+1);
 printf (".. %p  %p \n ", &a[0], &a[0]+1);
printf (".. %p   %p \n ", &a[0][0], &a[0][0] +1);
}

The Output is :

的输出是:

.. 0x7fff6ae2ca5c  0x7fff6ae2cbec    = 400 bytes difference
.. 0x7fff6ae2ca5c  0x7fff6ae2ca84    = 40 bytes difference
 .. 0x7fff6ae2ca5c   0x7fff6ae2ca60  = 4 bytes difference. 

&a +1 -> Moves the pointer by adding whole array size. ie: 400 bytes

>通过增加整个数组大小来移动指针。即:400字节

&a[0] + 1 -> Moves the pointer by adding the size of column. ie: 40 bytes.

[0] + 1 ->通过增加列的大小来移动指针。即:40个字节。

&a[0][0] +1 -> Moves the pointer by adding the size of element ie: 4 bytes.

[0][0] +1 ->通过增加元素ie: 4字节的大小来移动指针。

[ int size is 4 bytes ]

[int大小为4字节]

Hope this helps. :)

希望这个有帮助。:)

#1


22  

You got it slightly wrong: moreThings also decays to a pointer to the first element, but since it is an array of an array of chars, the first element is an "array of 8 chars". So the decayed pointer is of this type:

你可能会觉得有点不对:moreThings也会衰减到指向第一个元素的指针,但是因为它是一个chars数组的数组,所以第一个元素是一个“8 chars数组”。衰减指针是这样的

char (*p)[8] = moreThings;

The value of the pointer is of course the same as the value of &moreThings[0][0], i.e. of the first element of the first element, and also the same of &a, but the type is a different one in each case.

指针的值当然与&moreThings[0][0]的值相同,即第一个元素的第一个元素的值,也与&a的值相同,但是类型在每种情况下都是不同的。

Here's an example if char a[N][3]:

这里有一个例子,如果char [N][3]:

+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
|            a[0]           |            a[1]           |
+===========================+===========================+====
                                    a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
  • &a: address of the entire array of arrays of chars, which is a char[N][3]

    &: chars数组的整个数组的地址,即char[N][3]

  • &a[0], same as a: address of the first element, which is itself a char[3]

    bb&a b1,与第一个元素的地址相同,它本身就是一个char[3]

  • &a[0][0]: address of the first element of the first element, which is a char

    [0][0]:第一个元素的第一个元素的地址,它是一个char。

This demonstrates that different objects may have the same address, but if two objects have the same address and the same type, then they are the same object.

这说明不同的对象可能有相同的地址,但是如果两个对象有相同的地址和相同的类型,那么它们就是相同的对象。

#2


12  

"ARRAY ADDRESS AND POINTERS TO MULTIDIMENSIONAL ARRAYS"

Lets we start with 1-D array first:

我们先从一维数组开始:

  • Declaration char a[8]; creates an array of 8 elements.
    And here a is address of fist element but not address of array.

    声明char[8];创建一个包含8个元素的数组。这里a是第一个元素的地址,不是数组的地址。

  • char* ptr = a; is correct expression as ptr is pointer to char and can address first element.

    char * ptr =一个;是正确的表达式,因为ptr是指向char的指针,可以处理第一个元素。

  • But the expression ptr = &a is wrong! Because ptr can't address an array.

    但是“ptr = &a”的表达是错误的!因为ptr不能处理数组。

  • &a means address of array. Really Value of a and &a are same but semantically both are different, One is address of char other is address of array of 8 chars.

    &a是指数组的地址。a和&a的值其实是一样的,但在语义上都是不同的,一个是char的地址,另一个是8 chars数组的地址。

  • char (*ptr2)[8]; Here ptr2 is pointer to an array of 8 chars, And this time ptr2=&a is a valid expression.

    char(* ptr2)[8];这里ptr2是指向一个8字符数组的指针,而这次ptr2=&a是一个有效的表达式。

  • Data-type of &a is char(*)[8] and type of a is char[8] that simply decays into char* in most operation e.g. char* ptr = a;

    数据类型的&a是char(*)[8],类型a是char[8],在大多数操作中都只是衰变为char*,例如char* ptr = a;

    To understand better read: Difference between char *str and char str[] and how both stores in memory?

    要更好地理解:char *str和char str[]之间的区别以及两者如何存储在内存中?

Second case,

第二个案例,

  • Declaration char aa[8][8]; creates a 2-D array of 8x8 size.

    声明字符aa[8][8];创建一个8x8大小的二维数组。

  • Any 2-D array can also be viewed as 1-D array in which each array element is a 1-D array.

    任何二维数组也可以看作一维数组,其中每个数组元素都是一维数组。

  • aa is address of first element that is an array of 8 chars. Expression ptr2 = aa is valid and correct.

    aa是第一个元素的地址,它是一个包含8个字符的数组。表达式ptr2 = aa有效且正确。

  • If we declare as follows:

    如果我们声明如下:

    char (*ptr3)[8][8];    
    char ptr3 = &aa;  //is a correct expression
    

    Similarly,
    moreThings in your declaration char moreThings[8][8]; contain address of fist element that is char array of 8 elements.

    类似地,在你的声明中还有更多的东西[8][8];包含第一个元素的地址,它是8个元素的char数组。

    To understand better read: Difference between char* str[] and char str[][] and how both stores in memory?

    要更好地理解:char* str[]和char str[][]之间的区别以及这两者如何存储在内存中?


It would be interesting to know:

如果知道:

  • morething is an address of 8 char array .

    morething是8字符数组的地址。

  • *morething is an address of first element that is &morething[0][0].

    更多的东西是第一个元素的地址,它是[0][0]。

  • &morething is an address of 2-D array of 8 x 8.

    更重要的是一个2-D数组的地址,8 x 8。

    And address values of all above three are same but semantically all different.

    这三者的地址值是相同的,但在语义上是完全不同的。

  • **morething is value of first element that is morething[0][0].

    *more是第一个元素的值也就是[0][0]。

    To understand better read: Difference between &str and str, when str is declared as char str[10]?

    为了更好地理解阅读:当str被声明为char str[10]时,与str和str之间的区别?

Further more,

此外,

  • void doThings(char thingsGoHere[8][8]) is nothing but void doThings(char (*thingsGoHere)[8]) and thus accepts any array that is two dimensional with the second dimension being 8.
  • void doThings(char thingsGoHere[8][8])只是void doThings(char (*thingsGoHere)[8]),因此它接受任何二维数组,而二维数组的第二个维度是8。

About type of variables in C and C++: (I would like to add in answer)

关于C和c++中的变量类型:(我想补充一下)

  • Nothing is pass by reference in C its C++ concept. If its used in C that means author talking about pointer variable.
  • 在c++概念中,没有什么是通过引用来传递的。如果它在C中使用,那意味着作者在谈论指针变量。
  • C supports pass by Address and pass by value.
  • C支持按地址和值传递。
  • C++ supports Pass by address, pass by value and also pass by Reference.

    c++支持按地址传递、按值传递和按引用传递。

    Read: pointer variables and reference variables

    读取:指针变量和引用变量。

At the end,

最后,

  • Name Of an array is constant identifier not variable.
  • 数组的名称是常量标识符而不是变量。

#3


4  

Nicely explained by Kerrek,

很好地解释为Kerrek,

In addition to that, we can prove it by the following example:

除此之外,我们可以用下面的例子来证明:

#include <stdio.h>

int main ()
{
 int a[10][10];

 printf (".. %p  %p\n", &a, &a+1);
 printf (".. %p  %p \n ", &a[0], &a[0]+1);
printf (".. %p   %p \n ", &a[0][0], &a[0][0] +1);
}

The Output is :

的输出是:

.. 0x7fff6ae2ca5c  0x7fff6ae2cbec    = 400 bytes difference
.. 0x7fff6ae2ca5c  0x7fff6ae2ca84    = 40 bytes difference
 .. 0x7fff6ae2ca5c   0x7fff6ae2ca60  = 4 bytes difference. 

&a +1 -> Moves the pointer by adding whole array size. ie: 400 bytes

>通过增加整个数组大小来移动指针。即:400字节

&a[0] + 1 -> Moves the pointer by adding the size of column. ie: 40 bytes.

[0] + 1 ->通过增加列的大小来移动指针。即:40个字节。

&a[0][0] +1 -> Moves the pointer by adding the size of element ie: 4 bytes.

[0][0] +1 ->通过增加元素ie: 4字节的大小来移动指针。

[ int size is 4 bytes ]

[int大小为4字节]

Hope this helps. :)

希望这个有帮助。:)