字符串长度有限的字符串

时间:2013-05-07 06:46:51

标签: c strtod

如果我想将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

4 个答案:

答案 0 :(得分: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)。作为参考,这里是宽度说明符的文档:

  

可选的十进制整数,指定最大字段宽度。   当达到此最大值或a时,读取字符会停止   找到不匹配的字符,以先发生者为准。大多数转换   丢弃最初的空白字符(以下说明例外情况),   并且这些丢弃的字符不计入最大字段宽度。   字符串输入转换存储终止空字节(&#39; \ 0&#39;)以标记结尾   输入;最大字段宽度不包括此终结符。

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

strtod的签名就像这样

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

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

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

答案 3 :(得分:0)

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

但推出一个人自己很有趣:

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