Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 5.01 on page 97

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.



Solution by Gregory Pietsch

#include <ctype.h>
#include <stdio.h> /* for EOF */

int getch(void);
void ungetch(int);

/* getint:  get next integer from input into *pn 
 * 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.
 */
int getint(int *pn)
{
    int c, sign, sawsign;

    while (isspace(c = getch()))   /* skip white space */
        ;
    if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
        ungetch(c);    /* it's not a number */
        return 0;
    }
    sign = (c == '-') ? -1 : 1;
    if (sawsign = (c == '+' || c == '-'))
        c = getch();
    if (!isdigit(c)) {
        ungetch(c);
        if (sawsign)
            ungetch((sign == -1) ? '-' : '+');
        return 0;
    }
    for (*pn = 0; isdigit(c); c = getch())
        *pn = 10 * *pn + (c - '0');
    *pn *= sign;
    if (c != EOF)
        ungetch(c);
    return c;
}


Solution by Jose G. López (Category 0)

#include <stdio.h>
#include <ctype.h> /* for isdigit(c), etc. */

#define MAX 10

int getint(int *pn);

int main(void)
{
	int i, num[MAX];
	int val;

	for (i = 0; i < MAX && (val = getint(&num[i])) != EOF; i++)
		printf("num[%d] = %d, \tvalue returned: %d (%s)\n", i, num[i], 
				val, val != 0 ? "number" : "not a number");

	return 0;
}

int getch(void);
void ungetch(int c);

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

	*pn = 0;
	while (isspace(c = getch()))
		;
	if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
		/* ungetch(c);*/ /* if returned to input we fill the array */
		return 0;
	}
	sign = (c == '-') ? -1 : 1;
	if (c == '+' || c == '-') {
		c = getch();
		if (!isdigit(c)) {
			ungetch(sign == 1 ? '+' : '-');
			return 0;
		}
	}
	while (isdigit(c)) {
		*pn = 10 * *pn + (c - '0');
		c = getch();
	}
	*pn *= sign;
	if (c != EOF)
		ungetch(c);

	return c;
}

int bufp = 0;
int buf[MAX];

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

void ungetch(int c)
{
	if (bufp < MAX)
		buf[bufp++] = c;
}


Solution by menonsahab

/* I've added a function to view the buffer elements. */
#include <ctype.h>
#include <stdio.h>
#define BUFFERLENGTH 100
int getch(void);
void ungetch(int);

int buf[BUFFERLENGTH];
int nfp = 0;

void viewbuffer(void)
{
	int i;
	printf("\nbuffer:\n");
	for(i = nfp - 1; i >= 0; i--)
		printf("%d\n", buf[i]);
}

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

void ungetch(int c)
{
	if(nfp < BUFFERLENGTH)
		buf[nfp++] = c;
	else
		printf("error: ungetch buffer overflow\n");
}

int getint(int *pn)
{
	int c, sign;
	while(isspace(c = getch()));
	if(!isdigit(c) && c != EOF && c != '+' && c != '-')
	{
			ungetch(c);
			return 0;
	}
	sign = (c == '-') ? -1 : 1;
	if(c == '+' || c == '-') // If character read is + or -
	{
		c = getch(); // Read next character
		if(!isdigit(c)) // If it is not a digit
		{
			ungetch(sign == -1 ? '-' : '+'); // pushback on to the buffer the operator that was previously read
			return 0;
		}
	}	
	for(*pn = 0; isdigit(c); c = getch())
		*pn = *pn * 10 + (c - '0');
	*pn *= sign;
	if(c != EOF)
		ungetch(c);
	return c;
}

int main()
{
	int x, retval;
	int* px;
	px = &x;
	retval = getint(px);
	printf("retval = %d, x = %d\n", retval, x);
	viewbuffer();
	return 0;
}


Solution by Luke Panayi

#include <stdio.h>
#include <ctype.h>
#define BUFFER 1000

char buf[BUFFER];
int bufp=0;

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

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

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

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

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

	sign = (c == '-') ? -1 : 1;
	if (c == '+' || c == '-')
		c = getch();
	for (*pn = 0; isdigit(c); c = getch())
		*pn = 10 * *pn + (c - '0');

	if (*pn == 0 && c != '0')	{ //if +/- is followed by NaN, pn will stay at 0
		ungetch(sign == 1 ? '+' : '-');
		return 0;
	}

	*pn *= sign;
	if (c != EOF)
		ungetch(c);
	return c;
}

int main()	{
	
	int n, array[BUFFER]; 

	for (n = 0; n < BUFFER && getint(&array[n]) != EOF; n++);
	printf("%d\n", array[1]);

	return 0;
}



Solution by DtxdF

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

/* Used by getch/ungetch */
int buff = EOF;

int getint(int *pn);

int main(void) {
	int number;

	getint(&number);

	printf("%d\n", number);

	return EXIT_SUCCESS;

}

int getch(void) {
	int temp;

	if (buff != EOF) {
		temp = buff;
		buff = EOF;
	
	} else
		temp = getchar();

	return temp;

}

void ungetch(int c) {
	if (buff != EOF)
		fputs("ungetch: Too many characters", stderr);

	else
		buff = c;

}

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

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

	if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
		ungetch(c);
		return 0;
	
	}

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

	/**
	 * Workaround: When the user enters a number with more than one
	 * sign (+/-) causing it to be set to 0, it also happens when
	 * you enter one or more signed digits and include characters
	 * other than numbers.
	 *
	 * The following examples resulted in 0 being obtained:
	 * 1): --1: What you wanted was -1, but you got 0.
	 * 2): ++1: What you wanted was 1, but you got 0.
	 * 3): -a1: You wanted it was -1, but you got 0.
	 * 4): +a1: What you wanted was 1, but you got 0.
	 * 5): --------1: What I wanted was -1, but you got 0.
	 *
	 * Now the user can enter data like the above, and would get:
	 * -1, 1, -1, 1, -1.
	 *
	 **/

	while (!isdigit(c))
		c = getch();

	for (*pn = 0; isdigit(c); c = getch())
		*pn = 10 * *pn + (c-'0');

	*pn *= sign;

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

	return c;

}

Solution by anonymous

The wording of the exercise could be improved because it isn't clear what is being asked of the reader. My interpretation is if you discover a plus or minus symbol followed by a non-digit, then push the non-digit back to the buffer, and return 0 which represents a non-digit was found. Something that was implied is to make sure an EOF is returned if found instead of returning zero and processing the EOF the next go around. I also took the liberty initializing the values of the array to zero so they aren't garbage if the function returns early before setting it to zero in the for loop. Finally, I added a for loop in main to print out the values set in the array, which greatly helped in understanding what was going on (e.g. if there are no digits, the program keeps trying to set the same non-digit char over and over again until n == SIZE and the initial for loop exits). This isn't ideal and this is the result of pushing "such a character back on the input" as requested. Honestly, the "correct" way of doing this is to discard garbage and only allow valid input.

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

/*
    Exercise 5-1. 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.
*/

#define BUFSIZE 100
#define SIZE 100

char buf[BUFSIZE];  // buffer for ungetch
int bufp = 0;       // next free position in buf

int getch(void);
void ungetch(int);
int getint(int *pn);

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

int getint(int *pn)
{
    int c, sign;
    *pn = 0; // set value to zero so it isn't garbage
    while (isspace(c = getch())) // skip white space
        ;
    if (!isdigit(c) && c != EOF && c != '+' && c != '-')
    {
        ungetch(c); // not a number
        return 0;
    }
    sign = (c == '-') ? -1 : 1;
    if (c == '+' || c == '-')
    {
        c = getch();
        if (!isdigit(c) && c != EOF) // don't ungetch EOF, we want that returned this iteration
        {
            ungetch(c); // not a number
            return 0;
        }
    }
    for (*pn = 0; isdigit(c); c = getch())
        *pn = 10 * *pn + (c - '0');
    *pn *= sign;
    if (c != EOF)
        ungetch(c);
    return c;
}

// get a (possibly pushed back) character
int getch(void)
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

// push character back on input
void ungetch(int c)
{
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}
Personal tools