将 char[][] 转换为 char**?

Converting char[][] to a char**?

我正在根除 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); 
}

编译器无法从 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);
} 

您创建了一个多维数组,而不是指针数组。通常一个数组可以说等同于一个指针,但是在这种情况下,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;
}

由于您现在使用的是动态内存,因此您需要释放内存,这是最后一个循环所要做的。正如您所看到的那样,使用所有这些动态内存非常费力,使用经过优化的字符串库会比您可以更容易地完成更好的工作。如果您仍然不相信,您至少应该创建自己的字符串 class 来处理包含 char * 作为其私有成员的动态内存。在任何一种情况下,您都可以避免这种混乱,只需创建一个 zed class 对象数组,而根本不处理多维废话。没有人喜欢段错误和内存泄漏。

给定任何类型 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);

解决一些问题

正如评论中所指出的,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