将 char[][] 转换为 char**?
Posted
技术标签:
【中文标题】将 char[][] 转换为 char**?【英文标题】:Converting char[][] to a char**? 【发布时间】:2017-05-31 00:24:13 【问题描述】:我正在根除 std::string
以支持 C 字符串,我是新手。如何获得以下编译? g++
抱怨:cannot convert char(*)[16] to char**
#include <iostream>
void print(char** s, int n)
for (int i = 0; i < n; ++i)
std::cout << s[i] << '\n';
int main()
constexpr int n = 3;
char s[n][16] "Hello", "Bye", "Sky";
print(s, n);
【问题讨论】:
“我正在根除 std::string 以支持 C 字符串” 但为什么 我希望您有充分的理由删除 std 字符串以支持 char 数组。会大大增加出错的可能性。char s[n][16] "Hello", "Bye", "Sky";
ojeez.
到目前为止,我认为大多数编译器都实现了小字符串优化,其中小字符串不是动态分配的。
将数组传递给函数,只会将第一级数组衰减为指针,因此数组大小 16 仍然是 s
类型的一部分,print
采用指向指针的指针.您需要在 print
的参数类型中包含数组大小才能使其正常工作。请参阅此question(但我相信主体适用于 c++)。
【参考方案1】:
您创建了一个多维数组,而不是指针数组。通常可以说数组等同于指针,但是在这种情况下,c++ 需要知道数组第二维的大小。函数如下
void print(char s[][16], int n)`
for (int i = 0; i < n; ++i)
std::cout << s[i] << std::endl;
可以理解,您可能希望使用指针传递函数,以免制作二维数组的完整副本。我看到你提到你对可变长度字符串没问题。字符串库支持该功能。您正在处理的 c 字符串根本不是字符串,而是字符类型的静态数组。当您用最简单的术语创建指针数组时,使用动态内存定义这些 c 字符串恰好可以为您提供所需的行为。
void print(char** s, int n)
for (int i = 0; i < n; ++i)
std::cout << s[i] << std::endl;
int main()
int n = 3, i;
char** s = new char*[n];
for (i = 0; i < 3; i++)
s[i] = new char[16];
s[0] = "Hello";
s[1] = "Bye";
s[2] = "Sky";
print(s, n);
for (i = 0; i < 3; i++)
delete [] s[i];
delete [] s;
s = NULL;
return 0;
由于您现在使用的是动态内存,因此您需要释放内存,这是最后一个循环的作用。正如您所看到的,使用所有这些动态内存非常费力,使用经过优化的字符串库可以更轻松地完成更好的工作。如果您仍然不相信您应该至少创建自己的字符串类来处理包含 char * 作为其私有成员的动态内存。无论哪种情况,您都可以避免这种混乱,只需创建一个 zed 类对象数组,而根本不处理多维废话。没有人喜欢 seg 错误和内存泄漏。
【讨论】:
我误解了关于“可变长度”字符串的问题。远离 std::string 的全部目的是避免动态内存。但是您的第一段代码看起来不错。那么,在第一个示例中只复制了 1 指针,对吗? 有点,这篇文章应该能解释得更好。 link 从我所看到的你的预期目的来看,第一段代码绝对是你最好的选择。【参考方案2】:给定任何类型T
,T arr[N];
声明一个类型为T[N]
的变量arr
,它是数组而不是指针。当您在几乎所有上下文中使用arr
时,array to pointer conversions 就会发生,从而产生arr
是T*
类型的指针的错误错觉。
char s[n][16] = "Hello", "Bye", "Sky" ;
将s
声明为n
类型为char[16]
的元素的数组。现在,当发生数组到指针的转换时,s
衰减为 char (*)[16]
类型的指针。因此,您的函数需要具有签名
void print(char (*s)[16], int n);
相当于
void print(char s[][16], int n);
[]
被编译器解释为指针。
为了使这些复杂类型更具可读性,可以使用类型别名。
using T = char[16];
void print(T s[], int n);
解决一些问题
正如 cmets 中所指出的,std::string
应该几乎总是优先于 char
数组。如果您有性能问题,请在执行此操作之前进行基准测试。我真的怀疑在大多数情况下能观察到多少性能提升。
声明一个长度为n
的数组是int
不是标准C++。它是您的编译器提供的扩展,它不可移植,并且在大多数情况下没有必要。
int n = 3;
char vla[n]; // this is a variable length array
char arr[3]; // this is just an array
char* darr = new char[3]; // this is a pointer pointing to dynamically allocated memory
std::string str; // but instead, this is just better
【讨论】:
【参考方案3】:编译器无法从 char ** 中提取关于 char[16] 的信息。您需要定义一个类型 char[16] 并将指向该类型的指针传递给您的打印函数。
#include <iostream>
typedef char str_t[16];
void print(str_t* s, int n)
for (int i = 0; i < n; ++i)
std::cout << s[i] << std::endl;
int main()
int n = 3;
char s[n][16] "Hello", "Bye", "Sky";
print(s, 3);
【讨论】:
所以变长char数组不打扰你? @Sir J 你能用代码说明一下吗?到时候我会把它标记为已回答。 @iehrlich 我可以使用可变长度的 c 字符串。 @AgrimPathak 你使用了错误的语言。 C++ 不支持 VLA。 类似这样的东西:typedef char str_t[16]; void print2(str_t * s, int n) for (int i = 0; i以上是关于将 char[][] 转换为 char**?的主要内容,如果未能解决你的问题,请参考以下文章