获取字符串并转换为double

时间:2016-04-08 10:53:54

标签: c fgets strtod

我尝试创建一个函数,可以确定输入是否可以完美转换为double,然后能够将其存储到双精度数组中。例如,输入" 12.3a"是无效的。据我所知,strtod仍然可以将其转换为12.3,其余的将存储到指针。在我的函数doubleable中,它过滤输入字符串是否只包含数字。但是,我知道double有"。"比如" 12.3",我的功能将返回' X' (无效)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



char doubleable (char unsure[], int length){
int i;
int flag;
for (i=0; i<length; i++ ){
    if(isdigit(unsure[i]==0)){
        printf("You have invalid input.\n");
        flag=1;
        break;
    }
}
//check for '.' (?)
if(flag==1)
    return 'X';
else
    return 'A';



}

int main(){
char input [10];
double converted[5];
char *ptr;
int i;

for(i=0; i<5; i++){
    fgets(input, 10, stdin);
    //some code here to replace '\n' to '\0' in input
    if(doubleable(input, strlen(input))=='X'){ 
        break;
    }

    converted[i]=strtod(input, &ptr);
    //printf("%lf", converted[i]); 
}
    return 0;
} 

我正在考虑检查&#34;的发生情况。&#34;在输入中,以及输入多少(对于像12.3.12这样的输入,可以认为是无效的)。我是在正确的轨道上吗?或者有更简单的方法来解决这个问题吗?我也读过关于strtok函数的内容,它会在这里有用吗?不过,这个功能对我来说仍然很模糊。

编辑:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double HUGE_VAL= 1000000;

void string_cleaner (char *dirty){
int i=0;
while(1){
    if (dirty[i]=='\n'){
        dirty[i]='\0';
        break;
    }
    i++;
}
}

int doubleable2(const char *str)
{
char *end_ptr;
double result;

result = strtod(str, &end_ptr);

if (result == HUGE_VAL || result == 0 && end_ptr == str)
    return 0;  // Could not be converted

if (end_ptr < str + strlen(str))
    return 0;  // Other input in the string after the number

return 1;  // All of the string is part of the number
}

int main(){
char input [10];
double converted[10];
char *ptr;
int i;

for(i=0; i<5; i++){
    while (1){
    printf("Please enter:");
    fgets(input, 10, stdin);
    string_cleaner(input);
    if (doubleable2(input)==0)
        continue;
    else if (doubleable2(input)==1)
        break;
    }
    converted[i]=strtod(input, &ptr);
    printf("%lf\n", converted[i]);
    }
     return 0;
    }
谢谢你!它工作得很好!我有一个跟进问题。如果我输入的字符串太长,程序会中断。如果我要限制输入,让我们说输入[]中最多9个字符,我该怎么做?

根据我对fgets(xx,size,stdin)的理解,它只能达到大小字符(包括\ n,\ 0),然后将它存储到xx。在我的程序中,我想如果我将它设置为10,那么超过10的任何东西都不会被考虑。但是,如果我输入的字符串太长,我的程序会中断。

3 个答案:

答案 0 :(得分:1)

你确实可以使用strtod并检查返回的值和作为第二个参数给出的指针:

int doubleable(const char *str)
{
    const char *end_ptr;
    double result;

    result = strtod(str, &end_ptr);

    if (result == HUGE_VAL || result == 0 && end_ptr == str)
        return 0;  // Could not be converted

    if (end_ptr < str + strlen(str))
        return 0;  // Other input in the string after the number

    return 1;  // All of the string is part of the number
}

请注意,在调用此函数之前,您需要删除fgets大部分时间添加到字符串的换行符。

答案 1 :(得分:0)

  

据我所知,strtod仍然可以将其转换为12.3,其余的将存储到指针。

这是正确的 - 请参阅man page

  

如果 endptr 不为NULL,则转换中使用的最后一个字符后面的字符指针存储在 endptr 引用的位置。

所以请使用这些信息!

#include <stdio.h>
#include <stdbool.h>
#include <errno.h>

bool doable (const char *buf)
{
    char *endptr;

    errno = 0;
    if (!buf || (strtod (buf, &endptr) == 0 && errno))
        return 0;
    if (*endptr)
        return 0;
    return 1;
}

int main (void)
{
    printf ("doable: %d\n", doable ("12.3"));
    printf ("doable: %d\n", doable ("12.3a"));
    printf ("doable: %d\n", doable ("abc"));
    printf ("doable: %d\n", doable (NULL));
    return 0;
}

结果

doable: 1
doable: 0
doable: 0
doable: 0

答案 2 :(得分:0)

接受回答后

使用strtod()是正确的方法,但它有一些挑战

#include <ctype.h>
#include <stdlib.h>

int doubleable3(const char *str) {
  if (str == NULL) {
    return 0;  // Test against NULL if desired.
  }

  char *end_ptr;  // const char *end_ptr here is a problem in C for strtod()
  double result = strtod(str, &end_ptr);

  if (str == end_ptr) {
    return 0;  // No conversion
  }

  // Add this if code should accept trailing white-space like a \n
  while (isspace((unsigned char) *endptr)) {
    endptr++;
  }

  if (*end_ptr) {
    return 0;  // Text after the last converted character
  }

  // Result overflowed or maybe underflowed
  // The underflow case is not defined to set errno - implementation defined.
  // So let code accept all underflow cases
  if (errno) {
    if (fabs(result) == HUGE_VAL) {
      return 0;  // value too large
    }
  }

  return 1; // Success
}

OP的代码

result == 0中的result == 0 && end_ptr == str没有价值。简化为end_ptr == str

而不是if (end_ptr < str + strlen(str)),简单的if (*end_ptr)就足够了。

出于两个原因,

if (result == HUGE_VAL ...是一个问题。 1)result == HUGE_VAL在两种情况下发生:合法转换和溢出转换。需要测试errno来区分它们。 2)测试应if (fabs(result) == HUGE_VAL ...来处理负数。