1

I need to know how to convert a user input, which is a string, to a double. like if he writes in the string "23.45", it converts into double 23.45 (without any library functions).

I already got this code for integer, but don't know how to continue with double:

#include <stdio.h>

void main()
{
    char input[100];
    printf("Type a String which will be converted to an Integer: ");
    scanf("%s", input);

    int number = 0;
    int i = 0;

    if (input[i] >= 48 && input[i] <= 57)
    {
        while (input[i] >= '0' && input[i] <= '9')
        {
            number = number * 10;
            number = number + input[i] - '0';
            i++;
        }
        printf("string %s -> number %d \n", input, number);
    }
    else
    {
        printf("Enter a number! \n");
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
DeathToxic
  • 157
  • 1
  • 7
  • 1
    Why did you use the ascii value in the if and the char literals in the while? – fpg1503 Jan 18 '16 at 15:24
  • Change your code to handle the decimal point. Other than that you're largely there. Best of luck. – Bob Jarvis - Слава Україні Jan 18 '16 at 15:30
  • The 'possible duplicate' is not a good choice at all. The code in the question has problems because of a mismatch between the format specifier and the variable type. To the extent it converts a string to a double, it does so about as effectively as the integer conversion code in this question. The answers (not unreasonably) are across the map; most of them suggest using a function such as `atof()` (but `strtod()` only in comments) and `sscanf()` to do the job — which doesn't help for this question. – Jonathan Leffler Jan 18 '16 at 15:31
  • 1
    Does code need to handle 1) exponents 2) overflow 3) underflow 4) Infinities 5) Not-a-numbers 5) -0.0 6) what precision level? Voting to close as too broad. – chux - Reinstate Monica Jan 18 '16 at 15:33
  • @chux: OP specified a test case, and thus code which satisfies the test case should be considered correct. Add additional functionality to your answer if you care to. Best of luck. – Bob Jarvis - Слава Україні Jan 18 '16 at 15:35
  • 2
    @DeathToxic:This is the second time I see you asking how to do something "without any library functions". Is this homework? A job assignment? (Either way somebody is wasting your time.) Is this an attempt to learn how the standard library works? – DevSolar Jan 18 '16 at 15:40
  • 1
    @BobJarvis: So `int main() { puts( "23.45" ); }` would satisfy, as it passes the stated test case? ;-) – DevSolar Jan 18 '16 at 15:43
  • first of all thanks for all the comments etc. gotta check what you all wrote now. @DevSolar actually yes I am in an apprenticeship and the most people here want me to do this, I know it sounds so ridiculous but the quality is not really great here in switzerland if you would know how many students here hate the school system from an apprenticeship here Tbh After 2 years I still learned nothing from this school it's so useless. – DeathToxic Jan 20 '16 at 07:19
  • If this is indeed a learning exercise, the idea is to improve your problem-solving skills. Asking for the solution on SO repeatedly does teach you what a good resource SO is, but that won't help you much in the business. Hang in there. They cannot really *teach* you these things, they can only show you how to teach yourself. Don't sit back and mope, apply yourself to it. – DevSolar Jan 20 '16 at 07:23

4 Answers4

1

There's probably no reason why you'd roll out your own version of this, as strtod in stdlib.h already covers all manner of formats.

Here's a version which covers signed numbers as input and has some hints of where more suitable error handling could be placed:

#include <stdbool.h>

static void halt_and_catch_fire (void);

double strtod_homebrewn (const char* str)
{
  double result = 0;

  // handle signs:  
  bool is_negative = false;
  if(*str == '-')
  {
    is_negative = true;
    str++;
  }
  else if(*str == '+')
  {
    str++;
  }

  // handle the dot position:
  bool is_dot_found = false;
  double multiplier = 0.1;

  // the actual conversion:
  for(const char* s=str; *s!='\0'; s++)
  {
    if(*s >= '0' && *s <= '9') // ctype.h isdigit() would be preferred here
    {
      if(is_dot_found)
      {
        result += (*s - '0') * multiplier;
        multiplier /= 10;
      }
      else
      {
        result *= 10;
        result += *s - '0';
      }
    }
    else if(*s == '.')
    {
      if(is_dot_found) // two dots?
      {
        halt_and_catch_fire(); // replace this with error handling
      }

      is_dot_found = true;
    }
    else if(*s != '\0') // all cases tested, some weird unknown character found
    {
      halt_and_catch_fire(); // replace this with error handling
    }
  }


  if(is_negative)
  {
    result = -result;
  }

  return result;
}

static void halt_and_catch_fire (void)
{
  halt_and_catch_fire();
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Similar issues as [commented here](http://stackoverflow.com/questions/34858150/convert-string-user-input-to-a-double/34858967?noredirect=1#comment57457774_34858990) – chux - Reinstate Monica Jan 18 '16 at 16:25
  • 1
    @chux Yup... to write a fully functional `strtod` you'd need quite a bit more effort than the above. It also handles different base than decimal etc. – Lundin Jan 18 '16 at 16:33
0

Edit: only use this approach for small number of digits after the decimal point. Read the comments to know why it would fail for a large number of digits.

Since you mentioned without using any library functions, you could do something like this.

float number;
int decimal = 0;
int decimal_found =10;
while(input[i]!='\0')
{
    if((input[i] <='0' || input[i] >='9')&&input[i]!='.' )
    break;

    if(input[i] == '.')
    decimal = 1;

    if(decimal == 1)
    {
        number = number + (input[i] - '0')/decimal_found;
        decimal_found = decimal_found*10;
    }
    else
    {
        number =  number *10;
        number = number + input[i] - '0';
    }
    i++;
}

Simply check a decimal variable to know when decimal has been reached, then use and if else to have separate conditions for the number variable

novice
  • 545
  • 3
  • 16
  • This code fails for an input like 23asdadada.45, apart from that the check of `decimal == true` is unnecessary, and `bool`s for C [are not standard](http://stackoverflow.com/a/1921557/2305521). – fpg1503 Jan 18 '16 at 15:52
  • I hadn't put checks for non-numerical characters in the code. Why is the check of decimal unnecessary? I didn't know about the bools sorry , will edit it to work without bools – novice Jan 18 '16 at 15:55
  • 2
    This works on numbers with few enough decimal places, but the technique of adding an appropriate number of tenths, then an appropriate number of hundredths, thousandths, and so on is likely to lead to inaccuracy, I believe. – Jonathan Leffler Jan 18 '16 at 15:56
  • @JonathanLeffler - true, any way to avoid that using this method? – novice Jan 18 '16 at 15:57
  • @fpg1503: `bool` is standard in C99 and later with ``; `_Bool` is standard even without the header. – Jonathan Leffler Jan 18 '16 at 15:57
  • 3
    There are techniques to avoid that. A primary technique is to collect the tailing digits as an integer (count the digits, including the leading zeros; they matter in this context), then divide the accumulated integer by the appropriate power of ten. However, even that is not perfect. There are whole articles and probably even books on the subject — full treatment is very long. – Jonathan Leffler Jan 18 '16 at 16:00
  • @JonathanLeffler it wasn't `_Bool` that was being used and the OP does not state that C99 is being used anywhere, we should not assume that. – fpg1503 Jan 18 '16 at 16:02
  • 4
    @fpg1503: True. The current standard is C11; we should be assuming C11, not just C99. The only problem is the severely retrograde Microsoft compiler which only partially supports some of C99 and/or C11 in the most recent versions. But, in the absence of information to the contrary, assuming C11 is reasonable, and at least C99 is perfectly reasonable, and your statement that "there is no `bool` in C" is erroneous — there is `bool` in standard C (and has been for a decade and a half and some time to spare). – Jonathan Leffler Jan 18 '16 at 16:05
  • @JonathanLeffler I state they are not standard and link an answer mentioning the different alternatives for different versions of C. – fpg1503 Jan 18 '16 at 16:07
  • 1
    @fpg1503: And I'm stating that your headline assertion is incorrect (`bool` is a part of C). If your comment had said "not part of C90" or "not supported by Microsoft C" or some other such qualification, I wouldn't have needed to say anything. As it is, your headline information is wrong and linking to somewhere that qualifies your information into being right isn't helpful. OK; (more than) enough said. Let's leave the topic alone from here on, but be careful how you present assertions about what is, or is not, in the C standard. – Jonathan Leffler Jan 18 '16 at 17:03
0

Edit: As clux pointed out, this fails when the fraction starts with zeroes. Bummer. Anyway, perhaps someone conceives a simple fix? I can only think of adding a "readzeroes()" function and let that run after the dot.

You already have a function to read an int. Simply use that. Pseudo code:

float read_float()
{
    float f = read_int()
    if(next is dot) skipdot else return f;
    float frac = read_int() 
    while (frac>1) frac /= 10
    return f+frac;
}
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
0
#include <stdio.h>

void main()
{
    char input[100];
    printf("Type a String which will be converted to a double: ");
    scanf("%s", input);

    double number = 0.0;
    double divider = 1.0;
    int inFraction = 0;
    int i = 0;

    if (input[i] >= 48 && input[i] <= 57)
    {
        inFraction = 0;
        while ((input[i] >= '0' && input[i] <= '9') || input[i] == '.')
        {
            if (input[i] == '.')
            {
                i++;
                inFraction = 1;
                continue;
            }

            number = number * 10.0;
            number = number + input[i] - '0';
            i++;

            if (inFraction) divider *= 10.0;
        }

        number /= divider;

        printf("string %s -> number %g \n", input, number);
    }
    else
    {
        printf("Enter a number! \n");
    }
}
Viktor Simkó
  • 2,607
  • 16
  • 22
  • 1
    Note: Not too bad, yet reports 0.0 for very small input that overflow `divider`. Unnecessarily loses some precision with strings with many digits like "1152921504606846976" (2**60) – chux - Reinstate Monica Jan 18 '16 at 16:13