Exercise 5.1 - get next integer from input to *pn

Question

As written, getint treats a + or - not followed by a digit as a valid representation of zero. Fix it to push such a character back on the input.

/* getint: get next integer from input to *pn.
 * Free form input conversion routine */

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

#define SIZE 1000
#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;


int getch(void) {
    return (bufp > 0) ? buf[--bufp] : getchar();
}


void ungetch(int c) {
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}


int getint(int *pn) {
    int c, sign;

    while (isspace(c = getch()));

    if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
        ungetch(c); /* it's not a number */
        return -1; /* -1 will end the program directly */
    }

    sign = (c == '-') ? -1 : 1;

    if (c == '+' || c == '-')
        c = getch();
    /* This snippet avoids to treat a '+' or '-' not followed by a digit as a valid representation of zero */
    if (!isdigit(c))
        return 0;
    for (*pn = 0; isdigit(c); c = getch())
        *pn = 10 * *pn + (c - '0');

    *pn *= sign;

    if (c != EOF)
        ungetch(c);

    return c;
}

int main(void)
{
    int n,s,array[SIZE];

    for(n=0;n<SIZE && getint(&array[n]) !=EOF; n++){
        printf("storing in n = %d, getint %d\n", n, array[n]);
    }

    printf("storing in n = %d, getint %d\n", n, array[n]);

    for(s=0;s<=n; s++)
        printf("%d",array[s]);

    return 0;
}

Explanation

We are to explain the function getint(int *) which takes a pointer to an integer as the argument. We also use getch and ungetch as two functions, from chapter 4, which work on buf of BUFSIZE sharing a global variable called bufp. ungetch function returns the character read to buf while getch tries to read that character to our program and if no character is present, it uses getchar to get the character.

In this program, we declare an array of size of 1000, and we send each digit of the array to getint using a call like getint(&array[n]). Our intention is to load the characters in array with a valid integer format like +/-1234EOF, that is + or - 1234 and ending with EOF character.

In getint function, we get a character and if it’s space, we simply ignore it. And this snippet.

if(!isdigit(c) && c !=EOF && c!='+' && c!='-')
{
    ungetch(c); /* it's not a number */
    return 0;
}

Ensures that if we get a character which is not +,-, digit, EOF, then we return 0 and in the main loop we end the program. That is, we strictly look for characters that can be converted to integer in this program. So the only valid inputs are like this.

123
+123
-123

And if we get any invalid input.

abc
%**

Then the program will immediately end.

So, on a valid input, the initial check is done to see if there is a sign and if yes, it stores the sign and then it goes about finding the next digit in a for loop and calculates the number using this expression.

*pn = 10 * *pn + (c-'0')

This is responsible for converting the character like 1 to integer 1 and store it in *pn, the place in the array. We multiply the number by sign and when we find EOF, we store that EOF, so that the program terminates correctly.

Once the getint sees an EOF, we end the program and print the contents of the array.