双指针是什么意思和指针日期类型大小的malloc

You*_*ein 1 c malloc pointers

int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
*matrix = malloc(20 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

我只是不明白双指针的概念以及它如何转换为二维数组(即如果它是真的)在此先感谢.

dbu*_*ush 6

这里创建的是技术上不是2D数组而是指针数组,每个指针都包含数组的起始地址.然后可以将其编入索引,就像它是"真正的"2D阵列一样.

这一行创建了一个包含5个指针的数组int:

matrix = malloc(5 * sizeof(int*));
Run Code Online (Sandbox Code Playgroud)

下一行创建一个数组20 int:

*matrix = malloc(20 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

然而,就2D阵列而言,这是不完整的,因为仅分配了一行.您需要遍历matrix指向的每个元素以创建每一行:

int **matrix, i;

matrix = malloc(5 * sizeof(int*));
for (i=0; i<5; i++) {
    matrix[i] = malloc(20 * sizeof(int));
}
Run Code Online (Sandbox Code Playgroud)

当您使用此动态2D阵列时,您需要以相反的顺序释放内存:

for (i=0; i<5; i++) {
    free(matrix[i]);
}
free(matrix);
Run Code Online (Sandbox Code Playgroud)

这在某些方面不同于真正的2D阵列.首先,在真正的2D数组中,所有元素在内存中都是连续的,在这种情况下,指针数组和每个行数组都不是.

另一个区别是当传递给函数时,您无法以传递真实2D数组的方式传递它.

对于简单的1D数组,无论是在编译时还是动态分配:

int a1[5];
int *a2 = malloc(5 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

两者都可以传递给这样的函数:

void f(int *a);
Run Code Online (Sandbox Code Playgroud)

但在2D阵列的情况下:

int a[5][20];
Run Code Online (Sandbox Code Playgroud)

它需要传递给这样的函数:

void f(int a[5][20]);
Run Code Online (Sandbox Code Playgroud)

或等效地:

void f(int (*a)[20]);
Run Code Online (Sandbox Code Playgroud)

而动态2D数组需要传递给这样的函数:

void f(int **a);
Run Code Online (Sandbox Code Playgroud)


Joh*_*ode 6

一些图片可能有帮助.

让我们开始matrix,这是一个指向指针的指针int:

  int **
+--------+
| matrix |---???
+--------+
Run Code Online (Sandbox Code Playgroud)

第一次通话后malloc,您有以下内容:

  int **        int *
+--------+    +-----------+
| matrix |--->| matrix[0] |
+--------+    +-----------+
              | matrix[1] |
              +-----------+
              | matrix[2] |
              +-----------+
              | matrix[3] |
              +-----------+
              | matrix[4] |
              +-----------+
Run Code Online (Sandbox Code Playgroud)

您已为5个int *对象动态分配空间,并matrix指向第一个对象.在第二次调用之后malloc,你有了这个(表达式*matrix相当于matrix[0]- 更多关于下面的内容):

  int **        int *            int
+--------+    +-----------+    +---------------+
| matrix |--->| matrix[0] |--->| matrix[0][0]  | 
+--------+    +-----------+    +---------------+
              | matrix[1] |    | matrix[0][1]  |
              +-----------+    +---------------+
              | matrix[2] |    | matrix[0][2]  |
              +-----------+    +---------------+
              | matrix[3] |           ...
              +-----------+    +---------------+
              | matrix[4] |    | matrix[0][19] |
              +-----------+    +---------------+
Run Code Online (Sandbox Code Playgroud)

您已为20个int对象动态分配空间,并matrix[0]指向第一个对象.

所以,总之 - 每个matrix[i][j]都是int.每个matrix[i]指向matrix[i][0],所以每个matrix[i]必须是指针int,或int *. matrixmatrix[0],意思matrix必须是指针int *,或int **.

请记住,数组下标表达式a[i]定义*(a + i)- 给定一个地址a,偏移i 元素(不是字节!)来自该地址并遵循结果.因此,*matrix相当于*(matrix + 0),相当于matrix[0].

现在,你在这里所拥有的并不是一个真正的2D数组 - 你有一系列指针,每个指针都可以指向一系列int对象中的第一个(或者根本不指向任何对象).数组的"行"(很可能)在内存中不相邻.在真正的2D数组中,所有数组元素都是连续的.特定

int matrix[5][20];
Run Code Online (Sandbox Code Playgroud)

元素将如下所示:

+---------------+
| matrix[0][0]  |
+---------------+
| matrix[0][1]  |
+---------------+
      ...
+---------------+
| matrix[0][19] |
+---------------+
| matrix[1][0]  |
+---------------+
| matrix[1][1]  |
+---------------+
       ...
+---------------+
| matrix[4][19] |
+---------------+
Run Code Online (Sandbox Code Playgroud)

编辑

指针指针和2D数组之间的一些其他关键差异.首先,假设以下定义:

int **ptr;
int matrix[ROWS][COLS];
Run Code Online (Sandbox Code Playgroud)
  1. 表达式ptr有类型int **.表达式matrix将从类型"衰减" int [ROWS][COLS]到类型int (*)[COLS](指向COLS-element数组的指针int);

  2. sizeof ptr给出指针本身的大小(4,8或其他一些字节数). sizeof matrix以字节(ROW * COLS * sizeof (int))给出整个数组的大小.

  3. 表达式&matrix,matrix,&matrix[0],和&matrix[0][0]将所有产生相同的(所述阵列的所述第一元素的地址),尽管类型的表达式将是不同的- ,int (*)[ROWS][COLS],int (*)[COLS],int (*)[COLS]int *,分别.表达&ptr,ptr,&ptr[0],并&ptr[0][0]不会都产生相同的价值观- &ptr&ptr[0][0]将比不同的价值观ptr&ptr[0]和类型的表达式会int ***,int **,int **,和int *.