动态分配数组解释

时间:2013-10-08 06:23:14

标签: c arrays pointers dynamic-arrays

这是我的老师向我们展示的示例代码“如何在C中动态分配数组?”。但我不完全理解这一点。这是代码:

int k;
int** test;
printf("Enter a value for k: ");
scanf("%d", &k);
test = (int **)malloc(k * sizeof(int*));
for (i = 0; i < k; i++) {
    test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values
}

我想在C中定义一个数组,你必须将[]放在名字之后,那么究竟是什么int** test;它不仅仅是一个指针指针吗? malloc()行也让我感到困惑.....

7 个答案:

答案 0 :(得分:14)

根据声明int** test;testpointer to pointer,并且代码pice使用malloc函数动态地为int值矩阵分配内存。

声明:

test = (int **)malloc(k * sizeof(int*));
    //                ^^------^^-------
    //  allocate for  k  int*  values    

k指向int(int*)的指针分配继续内存。因此,如果k = 4,那么你会得到类似的东西:

 temp      343  347  351  355
+----+    +----+----+----+----+
|343 |---►| ?  | ?  | ?  |  ? |
+----+    +----+----+----+----+

我假设地址是四个字节,?表示垃圾值。

temp变量由malloc分配返回的地址,malloc分配大小= k * sizeof(int**)的继续内存块,在我的示例中= 16字节。

在for循环中,为k int分配内存,并将返回的地址分配给temp[i](先前分配的数组的位置)。

test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values
//                     ^^-----^^----------
//       allocate for  k   int  values    

注意:表达式temp[i] == *(temp + i)。因此,在每次迭代中的for循环中,为k int值数组分配内存,如下所示:

   First malloc                     For loop   
  ---------------                  ------------------
       temp
      +-----+
      | 343 |--+
      +-----+  |
               ▼                    201   205   209    213  
        +--------+                +-----+-----+-----+-----+
 343    |        |= *(temp + 0)   |  ?  |  ?  |  ?  | ?   |  //for i = 0
        |temp[0] |-------|        +-----+-----+-----+-----+
        | 201    |       +-----------▲
        +--------+                  502   506  510    514
        |        |                +-----+-----+-----+-----+
 347    |temp[1] |= *(temp + 1)   |  ?  |  ?  |  ?  | ?   |  //for i = 1
        | 502    |-------|        +-----+-----+-----+-----+
        +--------+       +-----------▲
        |        |                  43    48    52    56
 351    | 43     |                +-----+-----+-----+-----+
        |temp[2] |= *(temp + 2)   |  ?  |  ?  |  ?  | ?   |  //for i = 2
        |        |-------|        +-----+-----+-----+-----+
        +--------+       +-----------▲
 355    |        |
        | 9002   |                 9002  9006   9010 9014
        |temp[3] |                +-----+-----+-----+-----+
        |        |= *(temp + 3)   |  ?  |  ?  |  ?  | ?   |  //for i = 3
        +--------+       |        +-----+-----+-----+-----+
                         +-----------▲

再次?表示垃圾值。

其他要点:

1)您正在通过malloc转换返回的地址,但在C中您应该避免它。阅读Do I cast the result of malloc?,只需执行以下操作:

test = malloc(k* sizeof(int*));
for (i = 0; i < k; i++){
    test[i] = malloc(k * sizeof(int));
}

2)如果要动态分配内存,则需要在完成工作后明确释放内存(释放动态分配的内存后,无法访问该内存)。释放test内存的步骤如下:

for (i = 0; i < k; i++){
    free(test[i]);
}
free(test);

3)如果你想为所有数组分配完全连续的内存,这是为2D矩阵分配内存作为数组的一种方法检查这个答案:Allocate memory 2d array in function C

4)如果描述有帮助并且您想学习3D分配请检查以下答案:Matrix of String or/ 3D char array

答案 1 :(得分:4)

请记住,数组会衰减为指针,并且可以用作指针。并且该指针可以用作数组。实际上,索引数组可以看作是一个表单或指针算术。例如

int a[3] = { 1, 2, 3 };  /* Define and initialize an array */
printf("a[1] = %d\n", a[1]);  /* Use array indexing */
printf("*(a + 1) = %d\n", *(a + 1));  /* Use pointer arithmetic */

上面的两个输出都将打印数组中的第二个(索引1)项。

关于指针也是如此,它们可以与指针算法一起使用,或者与数组索引一起使用。

从上面的内容中,您可以认为指向指针指向.type作为数组数组。但这不是全部真相,因为它们在内存中的存储方式不同。所以你不能将一个数组数组作为参数传递给一个需要一个指向指针的函数。但是,在初始化之后,可以使用带有数组索引的指针指针,就像普通指针一样。

答案 2 :(得分:2)

malloc用于动态地将内存分配给测试变量,将*视为数组,将**视为数组数组,但不是通过值传递,而是使用指针来引用变量的内存地址。当调用malloc时,你通过获取整数的大小并乘以用户提供的int数来为测试变量分配内存,因为在用户输入之前不知道这一点。

答案 3 :(得分:2)

是的,完全没问题。 test是指向指针的指针,因此test[i]等同于写test + i将成为指针。为了更好地理解,请查看c - FAQ

答案 4 :(得分:2)

确实如此,int**是指向指针的指针。我们也可以说它是一个指针数组。

test = (int **) malloc(k * sizeof(int*));

这将首先分配一个k指针数组。 malloc动态分配内存。

test[i] = (int*) malloc(k * sizeof(int));

这不是必需的,因为它足够

test[i] = (int*) malloc(sizeof(int*));

这里我们分配每个数组位置以指向有效的内存。但是对于像int这样的基类型,这种分配没有任何意义。它适用于较大的类型(结构)。

每个指针都可以像数组一样访问,反之亦然,例如,以下是等效的。

int a;
test[i] = &a;
(test + i) = &a;

这可能是内存中的数组test,从偏移量0x10000000开始分配:

+------------+------------+
|   OFFSET   |  POINTER   |
+------------+------------+
| 0x10000000 | 0x20000000 | test[0]
+------------+------------+
| 0x10000004 | 0x30000000 | test[1]
+------------+------------+
| ...        | ...

每个元素(在此示例中为0x2000000和0x30000000)是指向另一个已分配内存的指针。

+------------+------------+
|   OFFSET   |    VALUE   |
+------------+------------+
| 0x20000000 | 0x00000001 | *(test[0]) = 1
+------------+------------+
| ...
+------------+------------+
| 0x30000000 | 0x00000002 | *(test[1]) = 2
+------------+------------+
| ...

每个值仅包含sizeof(int)的空格。

在此示例中,test[0][0]将等同于*(test[0]),但test[0][1]无效,因为它将访问未分配的内存。

答案 5 :(得分:2)

对于每个类型T,都存在一个类型“指向T的指针”。

可以通过*类型声明符将变量声明为指向各种类型值的指针。要将变量声明为指针,请在其名称前面加上星号。

因此“对于每个类型T”也适用于指针类型,存在多个间接指针,如char **或int ***等。还存在“指向数组的指针”类型,但它们不如“指针数组”(http://en.wikipedia.org/wiki/C_data_types

所以int** test声明了一个指向“int arrays”

的指针数组 行test = (int **)malloc(k*sizeof(int*));中的

为k量(int*)提供了足够的内存

所以有指定数量的指针,每个都指向...

test[i] = (int*)malloc(k * sizeof(int));(每个指针指向一个大小为k个int的数组)

...摘要

int** test;由k个指针组成,每个指针指向k个量。

答案 6 :(得分:1)

int **是指向int指针的指针。看看"right-left" rule