为什么我们不能使用双指针来表示二维数组?
arr[2][5] = {"hello","hai"};
**ptr = arr;
为什么双指针(** ptr)不能在此示例中起作用?
答案 0 :(得分:49)
我打算如何画出
int array[10][6];
和
int **array2 = malloc(10 * sizeof *array2);
for (int i = 0; i < 10; ++i)
array2[i] = malloc(6 * sizeof **array2);
看起来像在记忆中以及它们是如何不同的(并且它们不能相互铸造)
array
看起来像:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int)
- - - - - - - - - - - - - - - - - - - - - -
< first row >< second row> ...
array2
看起来像:
_ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | (10 elements of type int *)
- - - - - - - - - -
| | .... | _ _ _ _ _ _
| | \-->| | | | | | | (6 elements of type int)
| | - - - - - -
| |
| | _ _ _ _ _ _
| \ -->| | | | | | | (6 elements of type int)
| - - - - - -
|
|
| _ _ _ _ _ _
\ -->| | | | | | | (6 elements of type int)
- - - - - -
当您说array[x][y]
时,它会转换为*((int *)array+x*6+y)
虽然,当您说array2[x][y]
时,它会转换为*(*(array2+x)+y)
(请注意,对于array
,此公式也有效(读到帖子的末尾,然后是评论) )。
也就是说,静态2d数组实际上是一个1d数组,行放在一行中。该指数由公式row * number_of_columns_in_one_row + column
计算。
动态2d数组,但只是一个指针数组。然后,每个指针被动态分配以指向另一个1d数组。事实上,指针可以是任何东西。可以是NULL
,或指向单个变量,或指向另一个数组。并且每个指针都是单独设置的,因此它们可以具有不同的性质。
如果您需要在某处传递array
的指针,则无法将其转换为int **
(想象会发生什么。{{1}的单元格的int
值被解释为指针和解引用 - &gt; Bam!分段错误!)。但是,您可以将array
视为array
的1d数组;这是一个元素的1d数组,类型为int [6]
。要写下来,你说
int [6]
答案 1 :(得分:8)
指向指针指示每行(或列,如果您更喜欢这样想)可以与其他行/列具有不同的长度。
您还可以通过指向start元素的指针来表示2D数组,还可以指定每行/每列的元素数量的整数:
void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value)
{
first[y * row_size + x] = value;
}
答案 2 :(得分:7)
在C中,二维数组是数组。
你需要一个指向数组的指针来引用它,而不是一个双指针:
char array[2][6] = {"hello", "hai"};
char (*p)[6] = array;
//char **x = array; // doesn't compile.
对于引用“2维数据”的双指针,它必须引用指针数组的第一个元素。但是C(数组数组)中的二维数组与指针数组不同,如果只定义一个二维数组,则不存在相应的指针数组。
两者之间唯一的相似之处是用于访问数据的[][]
语法:数据本身的结构完全不同。
答案 3 :(得分:3)
为了获得一个“看起来像”一个可变大小的多维数组的对象,为每个行创建一个指针数组是一个昂贵的设计选择,为了语法糖。不要这样做。
执行可变大小多维数组的正确方法如下:
if (w > SIZE_MAX/sizeof *m/h) goto error;
m = malloc(w * h * sizeof *m);
if (!m) goto error;
...
m[y*w+x] = foo;
如果你希望它“看起来很漂亮”,那么你可以写m[y][x]
,你应该使用不同的语言,也许是C ++。
答案 4 :(得分:1)
让我们首先谈谈法律代码。您编写的内容(假设每个声明前面有一个字符)将无法编译,原因如下:您有太多的初始值设定项(arr [0]为6个字符,其大小为5),当然还有char ** p没有与char arr兼容的类型[2] [5]。纠正这些问题,我们得到:
char arr[2][6] = { "hello", "hai" };
char (*p)[6] = arr;
没有任何双指针。如果要访问上面的单个字符,则需要指定它们来自的元素:
char* pc = *arr;
如果你想访问arr中第一个元素的字符,就行了。
C ++没有二维数组。上面的第一个定义定义了char的数组[2]或数组[6]。指针转换的implicite数组导致指向char的数组[6]的指针。在那之后,当然,没有数组指针转换,因为你不再有一个数组。
答案 5 :(得分:0)
从语言到表现永远是脱钩的。
在某种程度上,C 几乎是异议。
以上面的例子为例,我们试图将二维数组赋值或转换为另一种形式,
#include <stdio.h>
int main()
{
char array[2][6] = {"hello", "hai"};
int h, i;
for (h = 0; h < 2; h++)
for (i = 0; i < 6; i++)
printf("%c\n", *(*(array+h) + i));
char (*p)[6] = array;
for (h = 0; h < 2; h++)
for (i = 0; i < 6; i++)
printf("%c\n", *(*(p+h) + i));
char **x = array;
for (h = 0; h < 2; h++)
printf("%c\n", *(x+h));
}
和输出,
h
e
l
l
o
h
a
i
h
e
l
l
o
h
a
i
h
i
现在的编译器非常聪明,他们可能只会发出警告而不是失败,即
main.c:14:13: warning: initialization from incompatible pointer type [enabled by default]
char **x = array;
此时,我们应该可以理解双指针不是双数组。
第一个 h
来自 hello
,第二个 i
来自 hai
。注意距离是 8 个字节,等于一个指针的大小。
此外,我们还可以,
char *y[2];
for (h = 0; h < 2; h++)
y[h] = array[h];
for (h = 0; h < 2; h++)
printf("%s\n", y[h]);
for (h = 0; h < 2; h++)
for (i = 0; i < 6; i++)
printf("%c\n", *(*(p+h) + i));
但是这个赋值不是单行语句。
和输出,
hello
hai
h
e
l
l
o
h
a
i