Read an Integer from the User, Part 2

Dave Sinkula 1 Tallied Votes 487 Views Share

Some issues, such as leading whitespace and trailing characters that cannot be part of a number, were not handled in Read an Integer from the User, Part 1. Here such issues receive lip service.

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

int mygeti(int *result)
{
        char c, buff [ 13 ]; /* signed 32-bit value, extra room for '\n' and '\0' */
        return fgets(buff, sizeof buff, stdin) && !isspace(*buff) &&
        sscanf(buff, "%d%c", result, &c) == 2 && (c == '\n' || c == '\0');
}

int main(void)
{
        int value;
        do {
                fputs("Enter an integer: ", stdout);
                fflush(stdout);
        } while ( !mygeti(&value) );
        printf("value = %d\n", value);
        return 0;
}

/* my output
Enter an integer: one
Enter an integer:
Enter an integer: f123
Enter an integer: 123f
Enter an integer:  123
Enter an integer: 123
Enter an integer: 1.23
Enter an integer: -42
value = -42
*/

/* note: this line in the above has a space character following the 123
Enter an integer: 123
*/

Dani AI

Generated

Building on ’s observation that Part 1 missed leading/trailing cases (and echoing ’s appreciation), here is a compact, practical approach that avoids the common pitfalls: undefined behavior from passing plain char to ctype functions, inability to detect overflow, truncated input lines, and trailing junk after the number. The idea: read a full line, parse with strtol, check errno and range against INT_MIN/INT_MAX, and verify that anything after the numeric text is only whitespace/newline.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>

int mygeti(int *result)
{
    char buf[100], *p, *end;
    long val;

    if (!fgets(buf, sizeof buf, stdin))
        return 0; /* EOF/error */

    /* detect and reject an all-whitespace line */
    p = buf;
    while (isspace((unsigned char)*p)) {
        if (*p == '\n' || *p == '\0')
            return 0;
        p++;
    }

    errno = 0;
    val = strtol(p, &end, 10); /* base 10 only */

    if (p == end)                /* no digits found */
        return 0;

    while (isspace((unsigned char)*end)) end++;

    if (*end != '\0' && *end != '\n') /* trailing non-space junk */
        return 0;

    if (errno == ERANGE || val < INT_MIN || val > INT_MAX)
        return 0; /* overflow/underflow */

    *result = (int)val;
    return 1;
}

Notes and tips: cast to (unsigned char) when calling isspace to avoid UB on negative char values; set errno = 0 before strtol so ERANGE is reliable; use getline where available to avoid fixed buffers; detect and discard the rest of a too-long line (if fgets returned a buffer without \n) to avoid leaving input hanging. This rejects inputs like 123f or 1.23, accepts leading whitespace and signs (+, -), and reliably flags overflow.

drxs33 0 Newbie Poster

Thank you sir dave.. it helped me alot.. thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.