3

如果我正在从标准输入读取double类型的数字,我如何检查正在读取的数字是否实际上有效(这些数字实际上是 double)?

4

4 回答 4

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);
}

编辑标准和手册页之间似乎有些差异。手册页说,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);
}

另外,不要忘记检查 for 的返回值fgetsNULL以防它失败!

于 2013-10-29T23:30:59.017 回答
2

既不简单strtodsscanf不足以区分诸如1,51blah与期望1.0的情况 - 所有这些都将导致1.0. 原因是

strtod()和函数将nptr 指向的字符串的初始部分分别转换为 double、float 和 long double 表示strtof()形式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(stderr, "the value could not be represented as a double exactly\n");
}

errno如果无法表示该值,则将设置 ( ) ERANGE。此外,end将指向未转换的第一个字符。如果没有设置语言环境,在解析1,5or时1blahendptr将指向第二个字符。如果整个字符串被成功解析为双精度常量,*endptr将指向终止的 '\0'

请注意,在errno调用函数之前必须将其设置为零,否则它将保留先前失败的函数调用的值。

于 2017-10-15T15:11:15.787 回答
0

我们如何检查输入字符串是否是有效的双精度?


strtod()for double
strtof()forfloat
strtold()for开始long double

double strtod(const char * restrict nptr, char ** restrict endptr);

, strtod... 函数将指向的字符串的初始部分转换nptrdouble....

指向最终字符串的指针存储在 指向的对象中endptr,前提是endptr它不是空指针。

C11dr §7.22.1.3 2&5

简化代码以松散地检查有效性。不抱怨上溢/下溢或多余的文字。

// Return true on valid
bool valid_string_to_double(const char *s) {
  char *end;
  strtod(s, &end);
  return s != end;
}

使用的挑战strto*()包括:errno == RANGE算术上溢和 。溢出时的返回值仅在默认舍入模式下指定。该值可能是无穷大或很大的数字。下溢的返回值是实现定义的。 已知在 C 规范未指定的条件下设置为其他非零值。允许使用前导空格,不考虑尾随空格。HUGE_VALerrno


查找 1) 转换、2) 额外空间、3) 上溢/下溢的示例函数。它不仅返回一个有效的指示,它还处理转换的值和errno之后的状态。

// 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
}

如果结果下溢 (7.12.1),则函数返回一个值,其大小不大于返回类型中的最小归一化正数;是否errno获取值ERANGE是实现定义的。C11dr §7.22.1.3 10


一个考虑因素包括errno这个函数完成后的值。C 规范仅errno == ERANGE用于strtod(),但已知各种实现会errno出于其他原因(包括“无转换”)设置为其他值。errno除非ERANGE为了高一致性,否则代码可以清晰。

于 2017-10-27T16:07:32.487 回答
-1

您可以使用标准的 atof 功能。它在失败时返回 0 - 您可以预先测试字符串是否为 0。

http://www.cplusplus.com/reference/cstdlib/atof/

于 2013-10-29T23:27:23.567 回答