[英]strtod with limited string length
如果我想将char数组中的前3个字符解析为double,忽略以下字符,我真的需要这样做吗?
int main() { const char a[] = "1.23"; char *b = malloc(sizeof(char) * 4); memcpy(b, a, sizeof(char) * 3); b[3] = '\0'; printf("%f\n", strtod(b, NULL)); // Prints 1.20000, which is what I want free(b); }
是不是像strtod
这样的函数允许你指定它应该搜索数字的最大字符串长度?
编辑:我希望它打印1.2
(它目前正在做), 而不是 1.23
!
虽然strtod()
不允许您限制字符串长度,但您可以使用具有最大字段宽度的 sscanf()
并可选地检查所消耗的字符数,如下所示:
#include <stdio.h>
double parseDouble(const char *str){
double val = 0;
int numCharsRead;
// Handle errors by setting or returning an error flag.
if(sscanf(str, "%3lf%n", &val, &numCharsRead) != 1){
puts("Failed to parse double!");
}
else if(numCharsRead != 3){
puts("Read less than three characters!");
}
return val;
}
int main(){
printf("%lf\n", parseDouble("1.3")); // 1.300000
printf("%lf\n", parseDouble("1.5999")); // 1.500000
printf("%lf\n", parseDouble(".391")); // 0.390000
printf("%lf\n", parseDouble(".3")); // Read less than three characters!\n0.300000
return 0;
}
sscanf(str, "%3lf%n", &val, &numCharsRead
是重要的部分:指定最大宽度为3,这意味着sscanf()
将为该特定字段读取最多3个字符,并且还存储数量numCharsRead
解析结束时消耗的字符。如果你每次只读3个字符就可以检查该值;如果3或更少,你可以使用sscanf(str, "%3lf", &val)
。作为参考,这里是宽度说明符的文档:
可选的十进制整数,指定最大字段宽度。 当达到此最大值或找到不匹配的字符时(无论哪个先发生),读取字符都会停止。 大多数转换都会丢弃最初的空格字符(下面会说明例外情况),这些丢弃的字符不会计入最大字段宽度。 字符串输入转换存储一个终止空字节('\\ 0')以标记输入的结尾; 最大字段宽度不包括此终止符。
如果您始终只想考虑给定字符串中的三个第一个字符,则可以使用以下代码:
#include <stdio.h>
#include <string.h>
double parse_double(const char *str) {
char *tmp = 0;
double result = 0;
asprintf(&tmp, "%.3s", str);
result = strtod(tmp, 0);
free(tmp);
return result;
}
int main(void) {
printf("%f\n", parse_double("1.23")); // 1.2
printf("%f\n", parse_double("1234")); // 123
printf("%f\n", parse_double("0.09")); // 0.0
return 0;
}
strtod
的签名是这样的
double strtod(const char *nptr, char **endptr);
该函数将返回nptr
的字符串的初始部分。 如果endptr
不为NULL
,则转换中使用的最后一个字符后面的字符指针存储在endptr
引用的位置。
因此,它不允许您指定需要转换的字符数。 因此,您必须自己修改输入并将其传递给strtod
。
不,标准库中没有这样的功能。
但滚动一个人自己很有趣:
/*
* Same as strtod() but only takes the first n characters into account.
* Additionally returns 0. and sets errno to EINVAL if 'nptr' is NULL.
*/
double strntod(const char *nptr, char **endptr, size_t n)
{
double result;
/* perform input validation */
if (!nptr)
{
errno = EINVAL;
result = 0.;
if (endptr)
{
*endptr = nptr;
}
goto lblExit;
}
if (strlen(nptr) <= n)
{
/* Nothing to truncate: fall back to standard 'strtod()' */
result = strtod(nptr, endptr);
}
else
{
/* create working copy of string */
char * ptmp = strdup(nptr);
/* Test whether 'strdup()' failed */
if (!ptmp)
{
result = 0.;
if (endptr)
{
*endptr = nptr;
}
goto lblExit;
}
/* truncate working copy to n characters */
ptmp[n] = '\0';
/* do original 'strtod()' on truncated working copy */
result = strtod(ptmp, endptr);
/* adjust '*endptr' to point to original character array, but to working copy */
if (endptr)
{
*endptr = nptr + (*endptr - ptmp);
}
/* free working copy */
free(ptmp);
}
lblExit:
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.