繁体   English   中英

字符串长度有限的字符串

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM