无法将数组转换为指针。

13

我有以下源代码:

#include <iostream>
using namespace std;

void main(int j)
{
    char arr[10][10];
    char** ptr;
    ptr = arr;
}

当我使用VS2010进行编译时,出现了以下错误:

(保留HTML标记)

error : a value of type "char (*)[10]" cannot be assigned to an entity of type "char **"

我曾认为C++中的数组只是指针。 所以,char[][]也可以是char**。 我错在哪里了?


C FAQ 包含了这个问题的解答:http://c-faq.com/aryptr/pass2dary.html - NPE
6
我认为C++中的数组只是指针。如果可以的话,请帮我一个忙:找到告诉你这个的人,称他为“木偶”,并让他看到这个问题。如果你是在书中读到这个观点,那么请退还这本书。如果这是一本图书馆的书,可以在该页面上插入一张纸片,写上一些相关网址和作者是“木偶”的说明。 - Steve Jessop
可能是将2D数组转换为指向指针的指针的重复问题。 - kiranpradeep
8个回答

12

谢谢。我接受Nawaz的答案,因为他提供了解决方案。 - atoMerz
1
@AtoMerZ:我没有提供解决方案,因为你没有说明你想要做什么! - Oliver Charlesworth
哦,对不起。我想要摆脱这个错误。还是点个赞吧。 - atoMerz

11
现有的答案虽然正确,但并没有很清楚地表明为什么你无法将char [10][10]强制转换为char **,除了编程语言规则之外还有一个根本原因。即使你用类似于强制转换的方式来进行转换:
char arr[2][2];
char ** ptr = (char **)arr;

它实际上不起作用。

原因是在C和C++中,二维数组在内存中是以数组的形式排列的。也就是说,在C中,二维数组在内存中是作为单个分配排列的。

arr -> arr[0][0]
       arr[0][1]
       arr[1][0]
       arr[1][1]

您会注意到,arr 指向的不是一个 char * ,而是指向 arr[0][0],它是一个 char;因此,虽然可以将 arr 强制转换为 char *,但不能将其强制转换为 char **

正确的强制转换应该是

char arr[2][2];
char * ptr = (char *)arr;

如果可能的话,您不想强制转换(这总是一个好主意!)

char arr[2][2];
char * ptr = arr[0];

或者,为了使结果更加清晰明了,

char arr[2][2];
char * ptr = &arr[0][0];

现在您实际上拥有一个指向包含4个字符的数组的指针。[注:我没有找到C标准中禁止实现在数组的两行之间添加填充的任何内容,但我不认为任何真实世界的实现会这样做,并且常见的编码实践依赖于这种假设不存在这样的填充。]

如果您确实需要将arr转换为char **,您必须显式创建指针数组:

char arr[2][2]
char * arr_ptrs[2];
char ** ptr;
arr_ptrs[0] = arr[0];
arr_ptrs[1] = arr[1];
ptr = arr_ptrs;

如果您尝试将二维数组强制转换为指向指针的指针,C语言原则上可以自动完成此操作,但这将违反程序员的期望,即强制转换不会具有诸如分配内存之类的副作用。

相比之下,在Java中,二维数组始终是指向数组的指针数组,因此该数组

char arr[][] = { {'a', 'b'}, {'c', 'd'} };

在内存中,它被分为三个单独的分配,以任意顺序和不一定相邻的方式进行布置。

arr -> arr[0]
       arr[1]

arr[0] -> arr[0][0]
          arr[0][1]

arr[1] -> arr[1][0]
          arr[1][1]

你会立即注意到,这需要比相当的C数组更多的内存,并且在运行时评估速度较慢。另一方面,它确实允许数组的行具有不同的长度。


6

类型 char[10][10]char**char (*)[10] 都是不同的类型。然而,第一个无法转换成第二个,但它可以转换成第三个。

因此,请尝试以下操作:

char arr[10][10];
char (*ptr)[10];
ptr = arr; //ok

这将会起作用,因为正如我所说,类型为char[10][10]的对象可以转换为类型为char (*)[10]的对象。它们是兼容的类型。


1
一个问题:char(*ptr)[10]不是指向一维字符数组的指针吗?如果是这样,那么一维字符数组不就等同于 char* 吗?如果这也是正确的,那么我就有一个指向字符指针的指针 -> char** - atoMerz
1
@AtoMerZ:不是所有的1D数组都是char*1D数组可以转换为char*,但在C++中不允许链式转换。只有一种从char[10][10]char (*)[10]的转换方式,没有进一步的转换。如果A可以转换为BB可以转换为C,那么你不能写C=A,这是链式转换,是不允许的。 - Nawaz
“char(*ptr)[10]不是指向一维字符数组的指针吗?”——它比那更具体。它特别是指向一个由10个字符组成的一维数组的指针,不多也不少。 - Benjamin Lindley

1
错误明确告诉你出了什么问题,一个双维数组可以被分配给一个数组指针而不是双重指针。所以你需要的是:
char (*ptr)[10] = arr; 

我做错了什么?
首先要明确的是,数组不是指针!但有时它们会像指针一样使用。
规则是:
一个具有数组类型的表达式(可以是数组名称)在任何情况下都会转换为指针类型,只要数组类型不合法而指针类型合法。
所以如果你有一个单维数组:
char arr[10];

那么arr会衰减为它的零号元素的地址,类型为char *

char *ptr = arr;

但是如果你有一个二维数组,它本质上是一个数组的数组。

 char arr[10][10];

然后, arr 会衰减为指向包含10个字符的数组的指针。

因此,为了将 arr 分配给某些内容,您需要确保该内容与类型匹配,即指向字符数组的指针。
因此:

char (*ptr)[10] = arr; 

1
我曾以为C++中的数组只是指针。
不,数组是一组在内存中连续排列的对象。在某些情况下,它们可以转换为指向第一个元素的指针。
所以char[][]也可以是char**吗?
不可以。它可以转换为指向第一个一维数组的指针(这是错误消息中提到的类型char (*)[10]),但该数组不是指针,因此不能转换为指向指针的指针。

0
数组不仅仅是指针——数组就是数组。但是,数组不是一级类型,因此您无法在许多地方使用它们。导致您困惑的原因是,数组名称可以隐式转换为指向数组第一个元素的指针,这意味着您可以在需要指针的许多地方使用数组,并且它会“正常工作”。然而,在这种情况下,它并不适用。

0

数组不是指针(尽管很多书籍都会让你以为是这样)。 它们是完全不同的东西。 指针是内存地址,而数组是一组连续的数据。

在某些情况下,数组可以衰减为其第一个元素的指针。 然后,您可以使用指针运算遍历连续的内存。 一个例子是将数组作为参数传递给函数时。

在这里您可能想要做的是:

char arr[10];
char * i = &arr[0];

显然在您的情况下需要使用2D数组和char**。我会留给您自己去解决 :)

0

当你将ar [10] [10]转换为指针时,你会得到一个指针数组,如上所述* ar [10]而不是** ar。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接