2

I'm trying to write a function to get a decimal input from the user and return the actual value converted from ASCII. However, the function causes the next input from the user to be skipped. As in:
Enter input: 123

Enter input: /* doesn; allow for input */

Enter input: 456

long sum = 0;

int character = fgetc(stdin);

while(character != '\n'){

    if(character >= '0' && character <= '9'){
        /* convert from ASCII */
        character -= '0';
        sum = sum * 10 + character;

    }
    else{
        /* reenter number */
    }
    character = fgetc(stdin);
}
return sum;
4
  • 1
    Use <ctype.h> and isdigit(); consider newlines; consider EOF. It's good that you're using an int for the value returned by fgetc(). It would be better if you showed sum being used, or didn't show sum at all. Actually, a complete function would be better. Please read the About page soon and see how to create an MCVE (How to create a Minimal, Complete, and Verifiable Example?). Commented Jan 17, 2016 at 0:55
  • This is not to reproduce. Commented Jan 17, 2016 at 1:39
  • i seem to have an extra newline in the stdin buffer. any reason why? Commented Jan 17, 2016 at 1:43
  • Is there anything in the empty else clause? If not, remove it. It formally doesn't do any harm, but it looks silly — as if someone intended to write something but forgot to come back and complete it. Commented Jan 17, 2016 at 4:51

3 Answers 3

1

To figure out why your code doesn't work, I suggest you post your full code, because problems may lie in the way you call this function.

So before full code is posted, I can just tell you that this code works well on my machine:

#include <stdio.h>
#include <ctype.h>

int getlong();

int main() {
    printf("\t%d\n", getlong());
    printf("\t%d\n", getlong());
    return 0;
}

int getlong() {
    long sum = 0;
    int character = fgetc(stdin);
    while (character != '\n') {
        if (isdigit(character)) {
            /* convert from ASCII */
            character -= '0';
            sum = sum * 10 + character;
            character = fgetc(stdin);
        }
        else {
            character = fgetc(stdin);
            continue;
        }
    }
    return sum;
}

ctype.h is included in order to use isdigit(), while tells you whether a character is decimal digit.

But in fact, you don't have to do everything on your own. Using standard library is more effective and efficient, both for you and for the computer.

For example, you can scan a long integer directly from stdin:

#include <stdio.h>

int main() {
    long value;
    puts("Please input numbers:");
    while (scanf(" %ld", &value) != 1) {
        puts("Only numbers are welcome:");
        scanf("%*[^\n]");
    }
    printf("%ld", value);
    return 0;
}

Notice the white-space at the beginning of format, this makes scanf() discard all white-space characters(including spaces, newline and tab characters) extracted until a non-white-space character is met.

Or, use strtol(), while is relatively rarely seen:

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

int main()
{
    char buf[80];
    char *pEnd;
    long value;
    do
    {
        puts("Numbers please:");
        if (fgets(buf, 80, stdin) == NULL)
        {
            perror("fgets()");
            return 1;
        }
        value = strtol(buf, &pEnd, 10);
    }
    while (*pEnd != '\n');
    printf("%ld", value);
    return 0;
}

Of course, sscanf() also works, you can just write the code on your own.

Sign up to request clarification or add additional context in comments.

Comments

1

From comments:
an extra newline in the stdin buffer...
Try replacing your current method with scanf() using following format string:

char* fmt = "%[^\n]%*c";

It reads everything up to the newline, then consumes the newline. * is an assignment suppressor.

Example: (includes functions to convert input string to float/integer number)

float get_float(void);
long get_int(void);
int main(void)
{

    float num_f = get_float();
    long num_i = get_int();

    return 0;
}

float get_float(void)
{
    char input[80];
    char **dummy={0};
    char* fmt = "%[^\n]%*c";
    printf("Enter floating point number and hit return:\n");
    scanf(fmt, input);
    return strtod(input, dummy);
}

long get_int(void)
{
    char input[80];
    char **dummy={0};
    char* fmt = "%[^\n]%*c";
    printf("Enter integer number and hit return:\n");
    scanf(fmt, input);
    return strtol(input, dummy, 10);
}

Note: These functions are bare bones illustrations of how converting input into number variables might be done, and were written without any error or range checking. As the commenter has stated, it would be worth your while before implementing production versions to read up on strtol() and strtof in detail. (Links are to the Linux man pages, but because both functions are part of the C standard libraries, documentation can also be found on MSDN here and here)

2 Comments

This is a good approach. It might be helpful to mention that to validate the return, OP would need to check errno against ERANGE and the return against LONG_MIN and LONG_MAX to protect against over/underflow and also check ptr against endptr (parameters in man strtol) to validate whether a conversion was made.
@DavidC.Rankin - Thank you. your comment is so complete, I almost copied & pasted directly.
0

Why not just use fgets and sscanf?

char buf[80];
float n;

if (fgets(buf, 80, stdin) != NULL) {        
    if (sscanf(buf, "%f", &n) == 1)
        printf("%f\n", n);
    else
        fprintf(stderr, "invalid float\n");
}

1 Comment

It looks as if the input is a decimal integer, hence the use of long for sum, which might perhaps be better named value. But using fgets() and sscanf() is a good technique, though you really need to test the return from fgets() before using the input with sscanf(), and sscanf() will return EOF if the input string is empty, or only contains white space (e.g. just a newline), so that test should be == 1 and not the implicit != 0 that you have used.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.