2013-05-07 125 views
3

如果我想将字符数组中的前3个字符解析为double,忽略下列字符,我真的需要这样做吗?字符串长度有限的strtod

 
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

回答

1

如果你总是只想从给定的字符串考虑前三个字符,可以使用下面的代码:

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

我没有想要的精度,我希望它受字符串大小的限制,所以''1.23“=> 1.2','”1234“=> 123.0'&'”0.09“=> 0.0' – Tyilo 2013-05-07 07:11:37

+0

@Tyilo :''1234“=> 123.0' ??? – alk 2013-05-07 09:53:41

+0

@alk您首先获取字符串的三个**字符**:'“1234”=>“123”',然后将其转换为双“123”=> 123.0'。 – Tyilo 2013-05-07 10:51:22

0

strtod签名是这样

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

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

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

+0

我已经知道了。我问是否有另一个功能,它提供了我想要的功能。 – Tyilo 2013-05-07 07:03:50

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

虽然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')以标记输入的末尾 ;最大字段宽度不包含此终止符。

+0

不错,除了2分。 1)用'str ==“1.3”', - >'numCharsRead == 4'和'val == 123'。 '%3lf%n'中的'3'限制了最多3次扫描的charters数量,并在conversion_中使用。 '%n'报告扫描的数字,用于转换或不转换。 2)'val'没有在失败路径上定义。尝试'printf(“%lf \ n”,parseDouble(“xyz”));'第一。 – chux 2015-07-14 22:22:50

+0

是的,第一个是非常好的一点。我没有提出它,但它吸引了我的注意力在文档中;唯一的解决方案是可能手动跳过字符串中的任何空格。至于'val'是未定义的,你是对的,但这只是一个简单的例子。实际上,你可能想要以不同的方式构造该函数,如果解析失败,则设置或返回一个错误标志。 – sevko 2015-07-14 23:06:08

+1

不是说确定'val'数对于OP的目标很重要,但是代码可以使用''%n%3lf%n',&之前,&val和之后' – chux 2015-07-15 01:12:54