【问题标题】:Converting char * to char * const *将 char * 转换为 char * const *
【发布时间】:2011-11-10 02:33:43
【问题描述】:

请原谅我这个问题的基本“本质”。我有时会不知所措。我有一个char *,但我需要将其转换为char * const * 才能在 fts() 函数中正确使用它。我该怎么做?

谢谢

【问题讨论】:

  • 您是否清楚即使const 不存在,这些东西也不等同?第一个是指向字符的指针,节是指向字符指针的 const 指针。第二个中还有一个间接级别。第一次你跳到你的角色,第二次你跳两次。
  • @DeepYellow 是的,我知道,因此不敢直接选角。这样的事情会做吗?声明一个 char * const * 变量说 x 。设 char * 变量为 p。然后 x = &p。
  • 我的评论在下面的类似答案之后几秒钟
  • 你这样做是在自找麻烦。

标签: c linux pointers


【解决方案1】:

您不应该进行这种转换,因为类型不兼容。

关于指针和指向指针的指针

char * 是指向字符串的指针,而char ** 是指向字符串指针的指针。 ( const 是奖金)。这可能意味着您应该提供一个字符串数组,而不是提供一个字符串。

这两件事显然是不相容的。不要将它们与演员表混合。

关于 fts_* API

要找到您的问题的解决方案,我们需要阅读 fts_* 函数 API(例如 http://linux.die.net/man/3/fts),我看到了:

FTS *fts_open(char * const *path_argv, int options,
          int (*compar)(const FTSENT **, const FTSENT **));

使用您的char * const * 参数path_argv,说明说明:

[...] 如果 compar() 参数为 NULL,则目录遍历顺序为 path_argv 中列出的根路径顺序 [...]

这证实了fts_open 函数确实是一组路径,而不是一个唯一的路径。

所以我猜你需要向它传递如下内容:

char *p[] = { "/my/path", "/my/other/path", "/another/path", NULL } ;

关于const

C 和 C++ 中的类型从右到左读取。所以如果你有:

  • char * : 指向字符的指针
  • char const * :指向 const char 的指针(即不能修改指向的字符串,但可以修改指针)
  • const char * :与char const * 相同
  • char * const : 指向 char 的 const 指针(即可以修改指向的字符串,但不能修改指针)
  • char ** : 指向 char 的指针
  • char * const *:const指针指向char指针(即可以修改指针,也可以修改char的字符串,但不能修改中间指针

这可能会令人困惑,但是一旦您对指针更加熟悉(并且如果您使用 C 或 C++ 编程,您想要成为熟悉指针)。

如果我们回到最初的例子(使用 C99 在 gcc 上发送一堆警告):

char ** p = { "/my/path", "/my/other/path", "/another/path", NULL } ;

我使用过 API,您可以通过两种方式为其提供路径:

    char * p0 = "/my/path" ;
    char * p1 = "/my/other/path" ;
    char * p2 = "/another/path" ;

    /* with a fixed-size array */
    char * pp[] = {p0, p1, p2, NULL} ;

    FTS * fts_result = fts_open(pp, 0, NULL);

Edit 2011-11-10: snogglethorpe 正确评论此解决方案不是 C89 有效解决方案,即使它使用 gcc 成功编译(不包括悬垂 + C89 标志)。有关更多信息,请参阅Error: initializer element is not computable at load time

或:

    /* with a malloc-ed array */
    char ** pp = malloc(4 * sizeof(char *)) ;
    pp[0] = p0 ;
    pp[1] = p1 ;
    pp[2] = p2 ;
    pp[3] = NULL ;

    FTS * fts_result2 = fts_open(pp, 0, NULL);
    free(pp) ;

编辑

阅读其他人的答案后,只有其中两个(mkbmoshbear)避免了“just cast the data”错误。

在我自己的回答中,我忘记了数组的 NULL 终止符(但是我不知道 Linux API,也不知道 fts_* 函数类,所以......)

【讨论】:

  • 它有点隐藏在手册页中,但是“数组必须由 NULL 指针终止。”所以你应该在末尾有一个额外的NULL 指针,类似于你如何调用execv()execvp()
  • 请注意,char *p[]p 将计算为 char **char ** 可以隐式转换为 char * const *
  • 感谢您的详细解释。真的很感激
  • @Juggler : 是的...花了一些时间,我有一些由 mkb 和 caf 纠正的错误...这些类型声明可能会令人困惑,但不要害怕它们。你会习惯它们(当你像我一样写了几个月的 C# 代码时很容易不使用它们......)
  • @caf 和@mkb:感谢您的更正。在我在 gcc 上测试代码之前,我非常专注于解释 const 以及我错过的所有 char * p[]
【解决方案2】:

我假设你说的是fts_open

FTS *fts_open(char * const *path_argv, int options,
                 int (*compar)(const FTSENT **, const FTSENT **));

它想要的是一个const char* 指针的数组,即。一个字符串数组。 const 只是告诉您它不会修改您的字符串,并让您有机会传递 const 字符串。

const 变量可以被视为const,但通常不应该反过来处理它们。

第一个参数就像argv 传递给main,你可以这样:

char *path_argv[] = { "/first_path/", "/second_path/", NULL };

最后一个元素很重要,NULL 表示数组的结尾。

还要注意path_argv 也可以声明为:

char **path_argv

或*

char * const *path_argv

其中任何一个都是适合作为第一个参数传递给fts_open 的类型。但是,您显然必须以不同于上述方式对其进行初始化,但这些是您可以声明 path_argv 的其他方式。我之前说不清楚。

然后只是fts_open(path_argv, options, compar),其中options 是您的选项,compar 是您的比较函数。

【讨论】:

  • @mkb 哎呀,我的错,感谢您接听。复制、粘贴失败。
  • char *path_argv[] 不能 如果您使用该初始化程序,则可以将其重写为其他两种形式之一。多元素初始化器仅对初始化数组或结构有用,而不是标量(有人甚至尝试编译他们的答案吗?)
  • @caf 抱歉,我不是这个意思,我的意思是 path_argv 可以声明为其中任何一个,然后传递给 fts_open。让我改正我的错误措辞。
【解决方案3】:

你需要创建第二个数组,它是NULL-terminated(因为fts()的第一个参数是argv)。

例如

char *const buf2[2] = { buf, NULL };
fts(buf2);

【讨论】:

  • 这并不像你认为的那样; buf2 只是一个标量,所以只有buf 用于初始化它,NULL 被忽略。
  • 现在你有另一个问题,虽然很小 - const char * const * 不能在 C 中隐式转换为 char *const *(尽管它可以在 C++ 中)。
  • @caf 再次修复。在 C++ 中,我认为仍然需要 const_cast
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多