理解C中半动态数组的声明

n6lpvg4x  于 2023-06-28  发布在  其他
关注(0)|答案(3)|浏览(85)

我们学习了2D数组和左右规则来理解复杂的声明。
我有一个半动态数组的声明:

int * array[2];

对于右-左规则,我将其理解为:array是指向int * 的2个指针的 * 数组。因此当我画一个图表时,我得到这个:

但是在课堂上他们给我们看了下面的图表:

我哪里错了?当涉及到2D数组的声明时,我怎么能不再次出错呢?

lsmepo6l

lsmepo6l1#

除了@chqrlie的答案,请注意,第二张“半动态”的图片相当令人困惑,你在顶部的图片可以说是更正确的(在任何情况下都没有错)-只需注意,你必须执行array[n]才能访问指针,但*(array[n])首先获得正确的指针,然后取消引用指针并访问实际的项。*(array[n])等于array[n][0]
int* array[2]是一个2指针数组。此数组在堆栈上分配。每个指针可以被分配为指向单个int项。如果您愿意,这个int可以在堆上分配。它可以是单个项,也可以是int数组中的第一个int,在这种情况下,您需要以某种方式跟踪这些数组的大小。
因此,在int* array[2]的情况下,array[0][1]很可能是越界访问。或者至少访问该项目并不比说array[0][42]更正确或更不正确-这取决于上下文。
“半动态”的图片更正确地说明了一些奇怪的憎恶类型,如
int (*arr[2])[2]; -“An array of pointers to arrays of int with size 2”。不是一个很有帮助的类型为大多数目的和种可笑的难以阅读。
一般来说,我们应该尽可能使用真正的2D数组,即使是在堆上。唯一一次使用指针数组或指向指针数组的指针,是当你有一个特殊的容器,它不是一个真正的多维数组,而是具有单独维度大小的东西(有时称为“锯齿数组”)。一个例子是在堆上分配的字符串数组--使用char**malloc来实现它是非常有意义的。
指针数组/指针查找表等的缺点是我们得到分段分配,这比真实的的多维数组访问和分配慢得多。而且在某些情况下也不必要地复杂。查看Correctly allocating multi-dimensional arrays了解详细信息。

cxfofazt

cxfofazt2#

您的理解是正确的,并且确实对应于一个指向int的指针数组,该数组是用自动存储(在堆栈上)定义的,在类图中被描述为一个 * 半动态 * 数组。
类中显示的图表描述了具有不同布局的2种其他类型的数组:

  • 一个 true 2D数组,即:一个2个2int的阵列的阵列。这个维度不需要进一步的分配,并且两个维度都在编译时固定。
  • 一个 fully dynamic 数组,其中定义array作为指向int的指针,int **array;。要使用这种类型的存储,您需要分配指针数组和每个指针指向的数组。这两个维度都可以在运行时确定,但是访问的开销稍微高一些,因为需要2个间接访问int值。取决于实际实现,编译器可能能够优化若干连续访问,从而分解出一些冗余代码。

请注意,上述对象具有不同的布局,虽然您可以使用相同的语法array[row][col]访问元素进行阅读和写入,但您不能将这些数组作为参数传递给相同的函数。

57hvy0tb

57hvy0tb3#

你被一些非传统的术语引入歧途了。2D数组总是 * 声明为

T arr[M][N];  // for some arbitrary type T and size expressions
              // M and N

并且该声明可以读作“arrNM元素数组TM元素数组”。
你的“半动态”数组是一个一维数组 * 指针 *:

int *arr[M];

每个元素 * 可以 * 指向另一个数组的第一个元素(无论是否动态分配)

for ( size_t i = 0; i < M; i++ )
  arr[i] = malloc( sizeof *arr[i] * N ); // allocates space for N ints

和你的“全动态”数组

int **arr;

不是一个数组。只是个指针。它 * 可能 * 指向指针数组的第一个元素(动态分配或非动态分配),其中每个元素 * 可能 * 指向数组的第一个元素(动态分配或非动态分配):

arr = malloc( sizeof *arr * M ); // Allocates space for M pointers to int
for ( size_t i = 0; i < M; i++ )
  arr[i] = malloc( sizeof *arr[i] * N );  // Allocates space for N ints.

假设MN2,则您的2D阵列将布局为

+---+
arr: |   | arr[0][0]
     +---+
     |   | arr[0][1]
     +---+
     |   | arr[1][0]
     +---+
     |   | arr[1][1]
     +---+

而您的1D指针数组将被布局为

+---+                                +---+
arr: |   | arr[0] ----------------------> |   | arr[0][0]
     +---+                                +---+
     |   | arr[1] -----------+            |   | arr[0][1]
     +---+                   |            +---+
                             |  
                             |            +---+
                             +----------> |   | arr[1][0]
                                          +---+
                                          |   | arr[1][1]
                                          +---+

而你的指针到指针版本看起来就像

+---+     +---+                       +---+
arr: |   | --> |   | arr[0] -------------> |   | arr[0][0]
     +---+     +---+                       +---+
               |   | arr[1] -------+       |   | arr[0][1]
               +---+               |       +---+
                                   |
                                   |       +---+
                                   +-----> |   | arr[1][0]
                                           +---+
                                           |   | arr[1][1]
                                           +---+

同样,没有任何规则要求指针必须指向动态分配的内存。以下也是有效的(尽管我目前没有一个很好的用例):

int x[2];
int y[4];

int *arr[2] = {x, y};

这就给了我们

+---+                           +---+ 
arr: |   | arr[0] --------------> x: |   | x[0] (arr[0][0])
     +---+                           +---+
     |   | arr[1] -------+           |   | x[1] (arr[0][1])
     +---+               |           +---+
                         |
                         |           +---+
                         +------> y: |   | y[0] (arr[1][0])
                                     +---+
                                     |   | y[1] (arr[1][1])
                                     +---+
                                     |   | y[2] (arr[1][2])
                                     +---+
                                     |   | y[3] (arr[1][3])
                                     +---+

xy不是动态分配的;它们是与arr相同的存储类。

相关问题