将 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】:

给定任何类型TT arr[N]; 声明一个类型为T[N] 的变量arr,它是数组而不是指针。当您在几乎所有上下文中使用arr 时,array to pointer conversions 就会发生,从而产生arrT* 类型的指针的错误错觉。

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**?的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中,如何将 String 转换为 char 或将 char 转换为 String?

如何将char数组转换为CString

将 const char* 转换为 char*

C 将 char 转换为 char*

如何将char类型转换成int类型?

为啥编译器试图将 char * 转换为 char? [关闭]