cfgetsstrtod

fetching string and converting to double


I'm trying to create a function which can determine if an input can be converted perfectly into a double and then be able to store it into an array of doubles. For example, an input of "12.3a" is invalid. From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. In my function doubleable, it filters whether the input string consists only of digits. However, I'm aware that double has "." like in "12.3", and my function will return 'X' (invalid).

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

I'm thinking of something like checking for the occurrence of "." in input, and by how much (for inputs like 12.3.12, which can be considered invalid). Am I on the right track? or are there easier ways to get through this? I've also read about the strtok function, will it be helpful here? That function is still quite vague to me, though.

EDIT:

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

thank you! It works just fine! I have a follow up question. If I enter a string that is too long, the program breaks. If I am to limit the input to, let's say, a maximum of 9 characters in input[], how am I to do that?

from what I understand about fgets(xx, size, stdin), it only gets up to size characters (including \n, \0), and then stores it to xx. In my program, I thought if I set it to 10, anything beyond 10 will not be considered. However, if I input a string that is too long, my program breaks.


Solution

  • You can indeed use strtod and check the returned value and the pointer given as the second argument:

    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
    }
    

    Note that you need to remove the newline that fgets most of the time adds to the string before calling this function.