标准C库函数strtof
和strtod
具有以下签名:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
它们将输入字符串str
分解为三个部分:
如果endptr
不是NULL
,则*endptr
被设置为指向紧跟在转换的最后一个字符之后的字符的指针(换句话说,尾随序列)。
我想知道:为什么endptr
是指向非const
char
指针的指针? *endptr
不是指向const
char
字符串(输入字符串str
)的指针吗?
答案 0 :(得分:11)
原因仅仅是可用性。 char *
可以自动转换为const char *
,但char **
无法自动转换为const char **
,并且调用函数使用的指针(其地址已通过)的实际类型为更有可能是char *
而不是const char *
。这种自动转换不可能的原因是,有一种非显而易见的方法可以通过几个步骤来删除const
限定,其中每个步骤看起来完全有效并且本身是正确的。 Steve Jessop在评论中提供了一个例子:
如果您可以自动将
char**
转换为const char**
,那么您可以char *p; char **pp = &p; const char** cp = pp; *cp = (const char*) "hello"; *p = 'j';.
对于const-safety,其中一行必须是非法的,并且由于其他行都是完全正常的操作,因此必须是
cp = pp;
更好的方法是定义这些函数,以(受损文本实际上是一个非常糟糕的主意;它不仅会阻止任何类型检查,而且C实际上禁止类型为void *
代替char **
。 char **
和const char **
都可以自动转换为void *
。char *
和const char *
的对象为别名。)或者,这些函数可能采用ptrdiff_t *
或size_t *
参数来存储偏移量最后,而不是指向它的指针。无论如何,这通常更有用。
如果您喜欢后一种方法,请随意在标准库函数周围编写这样的包装器并调用您的包装器,以便保留代码const
的其余部分 - 干净且无需转换。
答案 1 :(得分:5)
可用性。 str
参数标记为const
,因为输入参数不会被修改。如果endptr
为const
,那么会指示调用者他不应该更改输出中endptr
引用的数据,但调用者通常只想做那。例如,我可能希望在获取浮点数后终止字符串:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
在某些情况下,想做的事情非常合理。如果endptr
的类型为const char **
,则无效。
理想情况下,endptr
应该是与str
的实际输入常量匹配的常量,但C无法通过其语法指示这一点。 (Anders Hejlsberg talks about this描述为什么const
被排除在C#之外。)