如果我从stdin读取 double 类型的数字,我如何检查正在读取的数字是否实际上有效(这些数字实际上是双数)?
答案 0 :(得分:3)
您可以使用strtod
。根据手册页:
endptr == nptr
如果没有执行转换,则返回零,并且nptr的值存储在endptr引用的位置。
这样的事情:
char input[50];
char * end;
double result = 0;
fgets(input, sizeof input, stdin);
errno = 0;
result = strtod(input, &end);
if(result == 0 && (errno != 0 || end == input)){
fprintf(stderr, "Error: input is not a valid double\n");
exit(EXIT_FAILURE);
}
编辑 the standard与手册页之间似乎存在一些差异。当没有执行转换时,手册页说endptr == nptr
,而标准似乎暗示这不一定是这种情况。更糟糕的是它表示如果没有转换errno
可能设置为EINVAL
。编辑了示例代码以检查errno
。
或者,可以使用sscanf
(首选scanf
),与fgets
结合使用:
/* just fgetsed input */
if(sscanf(input, "%lf", &result) != 1){
fprintf(stderr, "Error: input is not a valid double\n");
exit(EXIT_FAILURE);
}
此外,如果失败,请不要忘记检查fgets
的{{1}}的返回值!
答案 1 :(得分:1)
简单的strtod
和sscanf
都不足以将1,5
或1blah
等案例与所需的1.0
区分开来 - 所有这些都会导致{{ 1}}。原因是
1.0
,strtod()
和strtof()
函数将nptr指向的字符串的初始部分转换为double,float和long double表示分别。
要确保整个字符串是有效的双字符,请使用strtold()
,如下所示:
strtod
如果无法表示值#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
...
char *endptr;
errno = 0;
double result = strtod(input, &endptr);
if (errno != 0 || *endptr != '\0') {
fprintf("the value could not be represented as a double exactly\n");
}
,则会设置errno
。此外,ERANGE
将指向未转换的第一个字符。如果区域设置尚未设置,则在解析end
或1,5
时,1blah
将指向第二个字符。 Iff 整个字符串已成功解析为双常量,endptr
将指向终止'\ 0'。
请注意,在调用函数之前必须将*endptr
设置为零,否则它将保留先前失败函数调用的值。
答案 2 :(得分:0)
我们如何检查输入字符串是否为有效的双精度数?
以
开头
strtod()
的{{1}},
double
和strtof()
float
strtold()
的{{1}}。
long double
double strtod(const char * restrict nptr, char ** restrict endptr);
,...函数将strtod
指向的字符串的初始部分转换为nptr
....指向最终字符串的指针存储在
double
指向的对象中,前提是endptr
不是空指针。C11dr§7.22.1.32&amp; 5
简化代码以便有效地检查。不抱怨过度/下溢或额外的文本。
endptr
使用// Return true on valid
bool valid_string_to_double(const char *s) {
char *end;
strtod(s, &end);
return s != end;
}
的挑战包括:strto*()
算术溢出和可能 underflow。溢出时的返回值仅在默认舍入模式中指定。该值为errno == RANGE
,可能是无穷大或大数。下溢的返回值是实现定义的。已知{C}规范未指定的条件下,HUGE_VAL
被设置为其他非零值。允许使用前导空白区域,不考虑尾随空白区域。
寻找1)转换,2)额外空间,3)上/下溢的样本函数。它不仅返回有效的指示,还会在之后解决转换的值和errno
的状态。
errno
如果结果下溢(7.12.1),则函数返回一个值,该值的大小不大于返回类型中的最小归一化正数;
// Return 0 on success // Return non-0 on error, adjust these values as needed - maybe as an `enum`? int convert_string_to_double(double *y, const char *s) { char *end; errno = 0; *y = strtod(s, &end); if (s == end) { return 1; // Failed: No conversion, *y will be 0 } // This may/may not constitute an error - adjust per coding goals // Too great or too small (yet not exactly 0.0) if (errno == ERANGE) { if (fabs(*y) > 1.0) { return 2; // Overflow } // In the case of too small, errno _may_ be set. See §7.22.1.3 10. // For high consistency, return 0.0 and/or clear errno and/or return success. // *y = 0.0; errno = 0; } // What to do if the remainder of the string is not \0? // Since leading whitespace is allowed, // let code be generous and tolerate trailing whitespace too. while (isspace((unsigned char) *end)) { end++; } if (*end) { return 3; // Failed: Extra non-white-space junk at the end. } return 0; // success }
获取值errno
是否是实现定义的。 C11dr§7.22.1.310
在此功能完成后,考虑因素包括ERANGE
的值。 {c}仅针对errno
的C spec errno == ERANGE
种,但由于其他原因(包括“无转换”),已知各种实现将strtod()
设置为其他值。代码可以清除errno
,除非errno
具有高一致性。
答案 3 :(得分:-1)
您可以使用标准atof功能。失败时返回0 - 您可以预先测试字符串是否为0。