为什么我们不能使用双指针来表示二维数组?

时间:2010-12-17 13:37:20

标签: c

为什么我们不能使用双指针来表示二维数组?

arr[2][5] = {"hello","hai"};
**ptr = arr;

为什么双指针(** ptr)不能在此示例中起作用?

6 个答案:

答案 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