int **matrix, i, j;
matrix = malloc(5 * sizeof(int*));
*matrix = malloc(20 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
我只是不明白双指针的概念以及它如何转换为二维数组(即如果它是真的)在此先感谢.
这里创建的是技术上不是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)
一些图片可能有帮助.
让我们开始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 *. matrix点matrix[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)
表达式ptr有类型int **.表达式matrix将从类型"衰减" int [ROWS][COLS]到类型int (*)[COLS](指向COLS-element数组的指针int);
sizeof ptr给出指针本身的大小(4,8或其他一些字节数). sizeof matrix以字节(ROW * COLS * sizeof (int))给出整个数组的大小.
表达式&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 *.