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

8
我有一个 char[][]
  char c[2][2]={
    {'a','b'},
    {'c','d'}
  };

如何将它转换为char **

这里的目标是将转换后的char **用作主函数的输入,该函数只接受char **作为其输入。 C/C++两种解决方案均可接受。


这是用于C还是C++?您想要一个char [][]的副本,转换为char** 或者 转换为指向字符串char**指针数组?(例如,您最终是否尝试使用printf("%s\n", array[i]);打印字符串?)我们必须知道您的main函数如何处理char**,否则我们只能猜测... - David C. Rankin
4个回答

8

虽然您可以轻松地从char[]切换到char*,但无法使用char[][]char**进行相同的操作:

  • char[2][2]是一个二维数组,所有元素都存储在连续的空间中。编译器通过计算每行的大小来访问一个元素的偏移量。
  • char**指向一个包含指向char的指针的数组。要访问一个元素,编译器需要计算最左侧指针的偏移量,加载该指针,然后访问元素。

解决方法:

char *pc[2]={c[0],c[1]}; 
cout << pc[1][1]<<endl;   // prints out the same as c[1][1]
// you can pass `pc` when a `char**` is needed

备注:这段代码可以完美编译。然而,某些带有参数 char **av 的函数实际上希望 av[i] 是一个以 null 结尾的 c 字符串。在这种情况下,虽然您的代码可以编译,但结果可能与您预期的不同(缓冲区溢出)。


1
请再次阅读问题,他可能想要使用以空字符结尾的字符串。 - Karoly Horvath
@KarolyHorvath 是的!我刚刚意识到并添加了额外的备注。 - Christophe
@KarolyHorvath 好观点!如果意图是调用execvp()/execvpe(),那绝对是的。顺便说一下,main()函数不应该从程序内部调用(标准,3.6.1)。在所有其他情况下,当然取决于函数以及是否有一个计数器来识别最后一个元素。 - Christophe
@KarolyHorvath 不,我不是指空终止字符串。无论如何,在原始问题中没有说明。谢谢。 - zell
@zell:是的,但不是直接的。它是“主函数的输入”。 - Karoly Horvath

2
您不能将char[2][2]转换为char**,您只能将其转换为char(*)[2]
char (*p)[2] = c;

上面是指向字符数组的指针。请注意,您需要这个 "2",而不能只写 "char ** p",因为在后一种情况下,您将无法执行指针算术运算(指针不知道在增加时要“跳过”多少个元素),也无法访问数组的元素(在本例中,即行)。

2
您可以像这样将数组传递到函数中:
char c[2][2] = {
    {'a','b'},
    {'c','d'}
};

char* x[] { c[0], c[1] };
func(x); // Assuming something like: void func(char** p);

1

注意:虽然这个答案可能很好地解释了问题,但是推荐创建一个自动变量char*[2];而不是像这个答案一样使用new进行分配。

原始答案:

问题在于char c[2][2]是一个连续的char块。编译器只分配了4个char对象。

当您构建一个数组的数组char** c)时,您需要手动分配一个char指针的数组,然后为每个指针分配(或赋值)一个char数组。

因此,要将您的数组char c[2][2]转换为数组的数组,您首先必须创建指针数组,然后将每个char数组的第一个元素的数组分配给该指针。

像这样:

void func(char** c)
{
    for(int x = 0; x < 2; ++x)
        for(int y = 0; y < 2; ++y)
            std::cout << c[x][y] << ' ';
    std::cout << '\n';
}

int main(int, char* argv[])
{
    // one contiguous block of 4 chars
    char c[2][2]={
        {'a','b'},
        {'c','d'}
      };

    char** param = new char*[2]; // create your own pointer array
    param[0] = &c[0][0]; // assign the first element of each char array
    param[1] = &c[1][0];

    func(param); // call your func

    delete[] param; // cleanup
}

如果你使用的是 C++11,你可以使用智能指针来防止内存泄漏,即使出现异常或者有人忘记执行 delete
int main(int, char* argv[])
{
    // one contiguous block of 4 chars
    char c[2][2]={
        {'a','b'},
        {'c','d'}
      };

    // use a smart pointer
    std::unique_ptr<char*[]> param(new char*[2]);
    param[0] = &c[0][0];
    param[1] = &c[1][0];

    func(param.get()); // now if this throws, no memory leak

    // delete[] param; // NO NEED TO DELETE
}

char *param[2];char **param = new char *[2]; 要好得多。 - M.M
@MattMcNabb 是的,我同意。我会把这个删除。 - Galik
@MattMcNabb 好的,现在我无法删除这个,可以指向其他答案。 - Galik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接