4

这是我的老师向我们展示的关于“如何在 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()条线也让我很困惑......

4

7 回答 7

17

根据声明int** test;test指向指针的指针,并且代码 pice 使用 malloc 函数为 int 值矩阵动态分配内存。

陈述:

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

k 为指向 int ( int*)的指针分配 continue 内存。所以假设如果k = 4你得到类似的东西:

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

我假设地址是四个字节,?意味着垃圾值。

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

在 for 循环中,您为kint 分配内存并将返回的地址分配给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 中您应该避免它。阅读我是否会转换 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 分配检查这个答案:字符串矩阵或/ 3D char 数组

于 2013-10-08T06:48:00.867 回答
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)项。

指针也是如此,它们可以与指针算术一起使用,也可以与数组索引一起使用。

从上面,您可以指向指针的指针类型视为类型数组。但这不是全部事实,因为它们在内存中的存储方式不同。因此,您不能将数组数组作为参数传递给需要指针的函数。但是,您可以在初始化它之后,像普通指针一样使用带有数组索引的指针。

于 2013-10-08T06:27:49.610 回答
2

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

于 2013-10-08T06:28:16.113 回答
2

是的,这完全没问题。test是指向指针的指针,所以test[i]相当于写test + i的将是一个指针。为了更好地理解,请查看此c-FAQ

于 2013-10-08T06:28:51.620 回答
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 开始分配的数组:

+------------+------------+
| 偏移量 | 指针 |
+------------+------------+
| 0x10000000 | 0x20000000 | 测试[0]
+------------+------------+
| 0x10000004 | 0x30000000 | 测试[1]
+------------+------------+
| ... | ...

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

+------------+------------+
| 偏移量 | 价值 |
+------------+------------+
| 0x20000000 | 0x00000001 | *(测试[0]) = 1
+------------+------------+
| ...
+------------+------------+
| 0x30000000 | 0x00000002 | *(测试[1]) = 2
+------------+------------+
| ...

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

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

于 2013-10-08T06:32:47.270 回答
2

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

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

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

所以int**test 声明了一个指向“int数组”的指针数组

在该行 中为 k 个 ( ) 的test = (int **)malloc(k*sizeof(int*));数量留出足够的内存int*

所以有k个指针,每个指向...

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

概括...

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

于 2013-10-08T06:45:55.140 回答
1

int** 是指向 int 指针的指针。看看“左右”规则

于 2013-10-08T06:29:27.480 回答