非常抱歉这个问题比较基础。我有时候在使用指针时会感到困惑。我有一个char *
,但我需要将它转换为char * const *
,以便能够在fts()函数中正确使用它。我该怎么做呢?
谢谢。
由于类型不兼容,您不应该进行这种类型的转换。
char*
是指向字符字符串的指针,而char**
是指向字符字符串的指针的指针。(const是一个奖励)。这意味着您应该提供一个字符字符串的数组,而不是提供一个字符字符串。
那两个东西显然是不兼容的。不要使用强制转换混合它们。
要找到解决问题的方法,我们需要阅读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 *
:与 char const *
相同char * const
:指向字符的常量指针(即您可以修改所指向的字符串,但不能修改指针)char **
:指向指向字符的指针char * const *
:指向指向常量字符的指针(即您可以修改字符指针,同时可以修改 char 的字符串,但不能修改中间的指针)这可能会令人困惑,但按照从右到左的顺序阅读它们将在您更熟悉指针时变得清晰明了(而如果您编程使用C或C ++,您希望熟悉指针)。
如果我们回到最初的例子(在 C99 上发送一堆警告):
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);
编辑于2011年11月10日:snogglethorpe 指出这个解决方案不是C89有效的解决方案,即使它在gcc下编译成功(不包括pendantic + 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) ;
在阅读其他答案后,只有两个答案(mkb和moshbear)避免了“只是强制转换数据”的错误。
在我的回答中,我忘记了数组的NULL终止符(但我不知道Linux API,也不知道fts_*类函数,所以...)
char *p[]
时,p
将被评估为char **
,而char **
可以隐式转换为char * const *
。 - caf{p1, p2, p3, NULL}
)只在C99中有效,可能不被所有编译器支持,例如,微软已经宣布他们不支持C99... - snogglethorpep1
、p2
、p3
)的初始化程序。默认情况下,即使在C89模式下,gcc也支持此扩展,但如果您像这样编译gcc -std=c89 -pedantic-errors
,它将失败。我认为这在C++中是有效的,所以如果您的朋友尝试将其作为C++程序运行,它应该可以工作... - snogglethorpeNULL
结尾(因为fts()
的第一个参数是argv)。char *const buf2[2] = { buf, NULL };
fts(buf2);
buf2
只是一个标量,因此只有 buf
被用来初始化它,而 NULL
被忽略了。 - cafconst char * const *
隐式转换为char *const *
(尽管在C++中可以)。 - cafconst_cast
。 - moshbear我假设你说的是 fts_open
:
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
const char*
指针,也就是一组字符串。 const
只是告诉你它不会修改你的字符串,并为你提供传递const
字符串的机会。const
变量可以被视为const
,但通常不应反过来处理。main
的argv
一样,你可以这样写:char *path_argv[] = { "/first_path/", "/second_path/", NULL };
为了表示数组的结尾,最后一个元素必须是NULL
。
请注意,path_argv
也可以声明为:
char **path_argv
OR*
char * const *path_argv
fts_open
的合适类型。然而,显然你需要与上面不同的方式初始化它,但那是你可以“声明”path_argv
的其他方法。我之前表述不够清晰。fts_open(path_argv,options,compar)
,其中options
是您的选项,compar
是您的比较函数。char *path_argv[]
不能被重写为其他两种形式之一。多元素初始化程序仅适用于初始化数组或结构,而不适用于标量(是否有人尝试编译他们的答案?)。 - cafpath_argv
可以被声明为其中任何一个,然后传递给 fts_open
。让我修正一下我的措辞。 - AusCBloke
const
也不等价吗?第一个是指向字符的指针,第二个是指向字符指针的常量指针。第二个有更深的间接层级。第一个需要一次跳转到达字符,而第二个需要两次。 - Codie CodeMonkey