为啥 char** 不能成为 C++ 中以下函数的返回类型?

Posted

技术标签:

【中文标题】为啥 char** 不能成为 C++ 中以下函数的返回类型?【英文标题】:Why can't char** be the return type of the following function in C++?为什么 char** 不能成为 C++ 中以下函数的返回类型? 【发布时间】:2011-10-31 14:38:00 【问题描述】:

我在 C++ 中有以下函数:

char** f()

    char (*v)[10] = new char[5][10];
    return v;

Visual Studio 2008 说明如下:

error C2440: 'return' : cannot convert from 'char (*)[10]' to 'char **'

为了让这个函数工作,返回类型应该是什么?

【问题讨论】:

你能不能只做 char** v = new char[5][10];? 要返回函数指针数组还是char的多维数组? 因为指向指针的指针与指向数组的指针不同。 @Nobody:函数指针和它有什么关系? @Tomalak:哦,我觉得我看到了太多的括号^^ 【参考方案1】:

char**char (*)[10] 的类型不同。这两种类型都是不兼容的类型,因此char (*)[10] 不能隐式转换为char**。因此编译错误。

函数的返回类型看起来很丑。你必须把它写成:

char (*f())[10]

    char (*v)[10] = new char[5][10];
    return v;

现在是compiles。

或者你可以使用typedef作为:

typedef char carr[10];

carr* f()

    char (*v)[10] = new char[5][10];
    return v;

Ideone.


基本上,char (*v)[10] 定义了一个指向大小为 10 的 char 数组的指针。它与以下相同:

 typedef char carr[10]; //carr is a char array of size 10

 carr *v; //v is a pointer to array of size 10

所以你的代码就变成这样了:

carr* f()

    carr *v = new carr[5];
    return v;


cdecl.org 在这里提供帮助:

char v[10] 读作 declare v as array 10 of char char (*v)[10] 读作 declare v as pointer to array 10 of char

【讨论】:

你没有回答问题。 @Tomalak:问题是What exactly should the return type to be, in order for this function to work?。那么帖子怎么可能没有回答问题呢? @Codo:你有没有看到 ideone 代码的链接,它编译得很好?此外,没有 function 指针。 如果你看标题,你会发现OP也想知道为什么char**不正确,这只是明智的。 我是 OP。我想回答这两个问题。然而,我承认我写这篇文章的方式可能会误导一些人认为第二个问题才是真正重要的,而标题中的问题并不那么重要。 @Nawaz 你的解释对我来说很清楚。谢谢。【参考方案2】:

指向指针的指针与指向数组的指针不同。

(特别注意sizeof(*ptr1)sizeof(char)*6,而sizeof(*ptr3)sizeof(char*)——这对指针运算有严重的影响。)


new char[5][10] 给你一个char (*)[10](顺便说一句,它与函数指针完全无关),因为指针和字符在内存中以这种方式布局(我的第二个例子)。

char**(代表不同的布局)相同,所以两者之间的转换没有意义;因此,它是不允许的。

所以你的函数的返回类型必须是char (*)[10]:

char (*f())[10] 
    char (*v)[10] = new char[5][10];
    return v;

当然,这真的很丑,所以你最好用std::vector<std::string>


This FAQ entry 解释得最好,标题为“Conversions”。

【讨论】:

可视化是理解差异的关键。请注意,我会支持std::vector<std::string> 的建议,因为如果处理一组字符串,这可能是您的意思。 +1 用于说明为什么指针衰减在这里的工作方式与 char[N] 不同 -> char* 第一个 "[一个或多个]" 都不正确 - ptr1ptr2 都是单个指针。 ptr2“指向一个或多个包含六个字符的数组的指针”ptr1“指向一个或多个指向一个或多个字符的指针的指针” . @Tomalak Gerek'kal:这种递增适用于它指向的对象。在这两个示例中仍然只有一个根指针 - 在ptr1 的情况下,只有两个级别的“一个或多个”,而不是三个。在ptr2 的情况下,只有一层,但它附加到数组而不是基指针。第二个示例中的数组本身也应按顺序排列,因为它们必须引用为ptr2[n] @Tomalak Geret'kal:简单地声明为char ** 的对象始终是一个单指针对象。如果您想要其中 N 个,则必须将其声明为数组:char **[N].【参考方案3】:

因为char**char (*)[10] 是两种不同的类型。 char** 是指向指针的指针(指向 char),而 char (*)[10] 是指向 char 的数组(大小为 10)的指针。结果char**移动步骤sizeof(void *)字节,在win32平台上是4字节,char (*)[10]移动步骤sizeof(char) * 10字节。

示例

   char *c = NULL;
   char **v = &c;
   cout << typeid(v).name() << endl;
   cout << (void*)v << endl;
   v += 1;
   cout << (void*)v << endl;

   char d[10];
   char (*u)[10] = &d;
   cout << typeid(u).name() << endl;
   cout << (void*)u << endl;
   u += 1;
   cout << (void*)u << endl;

输出

char * *
0034FB1C
0034FB20
char (*)[10]
001AFC50
001AFC5A

要将char (*)[10]用作函数的返回类型(或作为函数的输入/输出参数),最简单且最易读的方法是使用typedef

// read from inside-out: PTRTARR is a pointer, and, it points to an array, of chars.
typedef char (*PTRTARR)[10];

请注意,如果不小心,它很容易与 指针数组typedef 混淆:

// operator[] has higher precedence than operator*,
// PTRARR is an array of pointers to char.
typedef char *PTRARR[10];

参考

Arrays and Pointers

【讨论】:

你的答案似乎比它需要的复杂一点,@Eric Z,但我有点明白你在说什么。谢谢。 没问题,只希望你不仅了解什么,而且了解为什么和如何;) 这与正在讨论的主题一样复杂,@conectionist。值得研究所有答案!

以上是关于为啥 char** 不能成为 C++ 中以下函数的返回类型?的主要内容,如果未能解决你的问题,请参考以下文章

c++: strcpy 不能使用 char 数组

为啥我不能在 C++ 中用 new 调用参数化构造函数?

为啥在 c++ 中分配 char 数组元素时,分配的字符被破坏?

c++程序 我为啥不能将string类的变量赋给char数组,我按书上打的?

为啥 atoi 函数不能将 const char * 转换为 int?

QML和C++混合编程中,在qml中向C++的char* 函数传递一个char*的字符串参数,qml不能识别char*的参数类型