【问题标题】:Converting char[][] to a char**?将 char[][] 转换为 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++)。

标签: c++ string compiler-errors c-strings


【解决方案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
    猜你喜欢
    • 2010-10-12
    • 2021-04-29
    • 2013-10-18
    • 2012-01-15
    • 2020-11-25
    • 1970-01-01
    • 2011-06-08
    • 2012-07-01
    • 2011-10-19
    相关资源
    最近更新 更多