4

如果我想将 char 数组中的前 3 个字符解析为双精度字符,忽略以下字符,我真的需要这样做吗?

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)); // 打印 1.20000,这是我想要的

    免费(乙);
}

难道没有这样的函数strtod允许您指定它应该搜索数字的最大字符串长度吗?

编辑:我希望它打印1.2(它目前正在打印),而不是 1.23

4

4 回答 4

5

虽然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')来标记输入的结束;最大字段宽度不包括此终止符。

于 2015-07-14T21:58:20.260 回答
3

如果您始终只想考虑给定字符串中的前三个字符,则可以使用以下代码:

#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;
}
于 2013-05-07T07:05:20.057 回答
1

不,标准库中没有这样的功能。

但是自己动手很有趣:

/*
 * 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;
}
于 2013-05-07T09:52:55.280 回答
1

的签名strtod是这样的

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

该函数将返回 指向的字符串的初始部分nptr。如果endptr不是NULL,则将指向转换中使用的最后一个字符之后的字符的指针存储在 引用的位置endptr

所以它不允许你指定需要转换的字符数。因此,您必须自己修改输入并将其传递给strtod.

于 2013-05-07T07:02:03.347 回答