K&R 5-1

M

mdh

Hi All,
May I ask this. The exercise 5-1 asks one to correct an input in which
a non-digit follows a + or - . T & G show this:

/****/


if ( c == '+' || c == '-'){
d=c;

if ( !isdigit(c=getch())){



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

ungetch(d);

return d;

}
}


My question is: Does this not lead to an endless loop? (That's what I
seem to get) Or is this just illustrating something?

Complete code below.

Thanks in advance.

/****/


#include <stdio.h>
# include <ctype.h>
# define SIZE 10

int main () {

int getint ( int *);


int p, i, arr[SIZE];

for (p=0; getint( &arr[p]) != EOF; p++);

for ( i=0; i< SIZE; i++)
printf( "Converted input in Array idx(%d) = %d\n", i, arr);





return 0;
}

/*******/

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

int getint(int *px){

int c, d, sign;

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

if ( ! isdigit (c) && c != '+' && c != '-' && c != EOF) {

ungetch(c);
return 0;
}

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

if ( c == '+' || c == '-'){
d=c;

if ( !isdigit(c=getch())){



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

ungetch(d);

return d;

}
}


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

*px=*px * sign;

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

return c;

}


/*********/

#define BUFSIZE 10




char buf[BUFSIZE];
int bufp=0;


int getch(void){

return (bufp > 0) ? buf[--bufp]: getchar();

}


void ungetch(int c){

if ( bufp < BUFSIZE)

buf[bufp++] = c;

else

printf("Error: ungetch...buffer overflow");

}
 
S

santosh

mdh said:
Hi All,
May I ask this. The exercise 5-1 asks one to correct an input in which
a non-digit follows a + or - . T & G show this:

The standard doesn't guarantee a pushback of more than one character
at a time. The solution presented is inherently non-portable. All you
can do is pushback the non-digit character, or the sign character, not
both. Some C libraries do allow multiple character pushbacks, but if
you really need such features, it may be better to wrap your own I/O
functions.
 
F

Flash Gordon

santosh wrote, On 03/02/07 20:04:
The standard doesn't guarantee a pushback of more than one character
at a time.

If I recall correctly the program used a function called ungetch which
it defined, not the standard function ungetc, so your points from here
on are irrelevant to what the OP posted. Unfortunately, as you snipped
the parts of the code you are commenting on I have to rely on memory,
and my memory is poor, so I could be wrong. Snipping is good, but you
snipped too much on this occasion in my opinion.
> The solution presented is inherently non-portable. All you
can do is pushback the non-digit character, or the sign character, not
both. Some C libraries do allow multiple character pushbacks, but if
you really need such features, it may be better to wrap your own I/O
functions.

Which, I believe, is what the solution the OP posted did. It was
probably doing it because IIRC the ungetch function was developed in one
of the earlier exercises in K&R.
 
M

mdh

If I recall correctly the program used a function called ungetch....

correct...it was developed as has been used quite extensively up to
now. The way it is written, there does not seem to be a limit on the
number of characters pushed back, and in fact, Tondo & G push back 2
characters in their answer. I just wanted to get a feel for why I was
entering an endless loop.

Full code below....( You mean not everyone uses google? :) )



/****/

#include <stdio.h>
# include <ctype.h>
# define SIZE 10

int main () {

int getint ( int *);

int p, i, arr[SIZE];

for (p=0; getint( &arr[p]) != EOF; p++);

for ( i=0; i< SIZE; i++)
printf( "Converted input in Array idx(%d) = %d\n", i, arr);

return 0;

}

/*******/
int getch(void);
void ungetch(int);

int getint(int *px){

int c, d, sign;

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

if ( ! isdigit (c) && c != '+' && c != '-' && c != EOF) {

ungetch(c);
return 0;

}

sign = (c=='-') ? -1:1;
if ( c == '+' || c == '-'){
d=c;

if ( !isdigit(c=getch())){

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

ungetch(d);

return d;

}

}

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

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

return c;

}

/*********/
#define BUFSIZE 10

char buf[BUFSIZE];
int bufp=0;

int getch(void){

return (bufp > 0) ? buf[--bufp]: getchar();

}

void ungetch(int c){
if ( bufp < BUFSIZE)

buf[bufp++] = c;

else

printf("Error: ungetch...buffer overflow");
}
 
C

CBFalconer

santosh said:
The standard doesn't guarantee a pushback of more than one
character at a time. The solution presented is inherently
non-portable. All you can do is pushback the non-digit character,
or the sign character, not both. Some C libraries do allow
multiple character pushbacks, but if you really need such
features, it may be better to wrap your own I/O functions.

While there is nothing wrong with your post, an interesting fact
arises when you consider the actual mechanism used to implement
pushback. It turns out that many systems CAN push back multiple
chars, provided that the char following a '\n' is never accessed
[1]. This is very handy for such things as the OPs problem, or the
even worse "12.3e+x" [2] problem. A while back I published a short
test function to see what your system actually does.

[1] This is because access after the \n is what usually triggers
the refilling of the buffer. This in turn makes the (unwarranted)
assumption of buffered i/o.

[2] Note that none of these problem sequences involves the '\n'
character.
 
B

Ben Bacarisse

mdh said:
correct...it was developed as has been used quite extensively up to
now. The way it is written, there does not seem to be a limit on the
number of characters pushed back, and in fact, Tondo & G push back 2
characters in their answer. I just wanted to get a feel for why I was
entering an endless loop.

See below.
Full code below....( You mean not everyone uses google? :) )



/****/

Personally, I find separator comments like this visually distracting.
#include <stdio.h>
# include <ctype.h>
# define SIZE 10

int main () {

int getint ( int *);

int p, i, arr[SIZE];

for (p=0; getint( &arr[p]) != EOF; p++);

You can access outside the array unless you test that p < SIZE. Your
layout is all up the spout. I'd write it like this:

for (p = 0; p < SIZE && getint(&arr[p]) != EOF; p++) /* nothing */;

But this is also the source of your never-ending loop. When the input
is incorrect, getint does not return EOF but neither does it consume
any more input so you just keep going round and round.

I would suggest you change the interface so that getint returns true
(any non-zero integer) when it reads a number and false (0) when is
does not.
for ( i=0; i< SIZE; i++)

i < p would be better here since by now you know how many numbers your
have.
printf( "Converted input in Array idx(%d) = %d\n", i, arr);

return 0;

}

/*******/
int getch(void);
void ungetch(int);

int getint(int *px){

int c, d, sign;

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

if ( ! isdigit (c) && c != '+' && c != '-' && c != EOF) {

ungetch(c);
return 0;

}

sign = (c=='-') ? -1:1;
if ( c == '+' || c == '-'){
d=c;

if ( !isdigit(c=getch())){

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

ungetch(d);

return d;


As I say, I would "return 0;" here. local variable d is then not needed.
}

}

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

At the very least, indent the body of you loops!
*px=*px * sign;

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

return c;

and here I would return 0/1 depending on whether any digits were
actually consumed.
}

/*********/
#define BUFSIZE 10

char buf[BUFSIZE];
int bufp=0;

int getch(void){

return (bufp > 0) ? buf[--bufp]: getchar();

}

void ungetch(int c){
if ( bufp < BUFSIZE)

buf[bufp++] = c;

else

printf("Error: ungetch...buffer overflow");
}

Since there is never much purpose in pushing back EOF, you could put
that test in the ungetch function and simplify getint a little bit.
 
M

mdh

thanks for your input.

I also solved the endless loop problem by resetting the buffer to 0
when pushing back two characters...A little dirty as the integer
stored with this is undefined ( I have begun to like that word). :)
 
G

Gregor H.

correct...it was developed and has been used quite extensively up to
now. The way it is written, there does not seem to be a limit on the
number of characters pushed back ...
The limit is given by BUFSIZE.


F.
 
G

Gregor H.

Yes. I think that's a reasonable solution!
A little dirty as the integer stored with this is "undefined"...
Well, no problem. Since the function returns a 0 the caller is warned that
no input value has been (successfully) read.


My own solution:

/* Exercise 5-1 */

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

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

/* getint: get next integer from input into *pn */
int getint(int *pn)
{
int c, d, sign;

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 (c == '+' || c == '-')
{
d = c;
if (!isdigit(c = getch()))
{
if (c != EOF)
ungetch(c);
ungetch(d);
return 0;
}
}
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF)
ungetch(c);

return c;
}

#define BUFSIZE 100

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

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

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

#define SIZE 10

int main(void)
{
int i, n, c, array[SIZE], getint(int *);

for (n = 0; n < SIZE && (c = getint(&array[n])) != EOF && c != 0; n++)
;

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

return 0;
}


F.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top