Weird problem

J

Jeff

Hello everybody,

I was doing one of the exercises in the K&R book, and I got something
really strange. Here's the source code:

/*
* Exercise 2-2 from the K&R book, page 42
*/
#include <stdio.h>

enum loop_control { EXIT, CONTINUE };

int getline (char s[], int lim)
{
short int loop = CONTINUE;
unsigned int i = 0;
int c;

while (loop) {
c = getchar();
if (i == (lim - 2))
loop = EXIT;
else if (c == EOF)
loop = EXIT;
else if (c == '\n')
loop = EXIT;
else
s[i++] = c;
}

if (c == '\n')
s[i++] = c;
s = '\0';

return (i);
}

The strange thing is that lim doesn't seem to control anything at all.
I compiled it using GCC under cygwin on a windows 98 system (I added a
simple main() function that gets a line using getline() and then
prints it).
The strange thing is that even when I put a very small value for lim,
say 10, I can still get very big strings into it without it crashing.
Here's an example output:
$ gcc -o ex exercise2-2.c
$ ./ex
123333333333333333
1233333333333333
fdkjghfgsfgkjsdf
fdkjghfgfgkjsdf
(^C)
$

Any feedback will be appreciated!
Cheers!

- Joseph
 
E

Ed Morton

Hello everybody,

I was doing one of the exercises in the K&R book, and I got something
really strange. Here's the source code:
The strange thing is that lim doesn't seem to control anything at all.
I compiled it using GCC under cygwin on a windows 98 system (I added a
simple main() function that gets a line using getline() and then
prints it).
The strange thing is that even when I put a very small value for lim,
say 10, I can still get very big strings into it without it crashing.
Here's an example output:
$ gcc -o ex exercise2-2.c
$ ./ex
123333333333333333
1233333333333333
fdkjghfgsfgkjsdf
fdkjghfgfgkjsdf

Notice that the above string is correct for the first 8 chars (i.e. lim -2 when
lim is 10) then it skips the "s" and keeps going. You didn't by any chance write
your main() function as:

int main() {
...
while(1) {
getline(s,10);
printf("%s",s);
}
...
}

did you? I suspect you're calling getline() in a loop. Show us your "main()" if
that isn't the case.

Ed.
 
I

Irrwahn Grausewitz

I was doing one of the exercises in the K&R book, and I got something
really strange. Here's the source code:
#include <stdio.h>

enum loop_control { EXIT, CONTINUE };

int getline (char s[], int lim)
{
short int loop = CONTINUE;
unsigned int i = 0;
int c;

while (loop) {
c = getchar();
if (i == (lim - 2))

What if this function is invoked with second parameter < 2 ?

The buffer s isn't used as efficiently as possible, if there's
no '\n' within the first lim-2 characters of input.
loop = EXIT;
else if (c == EOF)
loop = EXIT;
else if (c == '\n')
loop = EXIT;
else
s[i++] = c;
}

if (c == '\n')
s[i++] = c;
s = '\0';

return (i);


You return an unsigned int from a function declared as returning int.
BTW, the parentheses in the return statement are unnecessary.
}

The strange thing is that lim doesn't seem to control anything at all.
I compiled it using GCC under cygwin on a windows 98 system (I added a
simple main() function that gets a line using getline() and then
prints it).
The strange thing is that even when I put a very small value for lim,
say 10, I can still get very big strings into it without it crashing.
Here's an example output:
$ gcc -o ex exercise2-2.c
$ ./ex
123333333333333333
1233333333333333
fdkjghfgsfgkjsdf
fdkjghfgfgkjsdf

I cannot reproduce this behaviour. Here's how I used your function:

#define BUFLEN 10

int main( void )
{
char str[BUFLEN];
int n = getline( str, BUFLEN );

printf("%d %s\n", n, str );
return 0;
}

Would you mind to post your main function as well? Maybe something's
wrong with it.

Anyway, how about this:

int getline( char *s, int lim )
{
int i = 0;
int c;

while( ((c = getchar()) != EOF) && (c != '\n') && (i < lim-2) )
s[i++] = c;
if (c == '\n')
s[i++] = c;
s = '\0';

return i;
}

Note: this version still uses the buffer provided by the caller
inefficiently, if no '\n' appears within the first lim-2 characters
of input. You may want to improve it (left as an exercise).

Regards
 
M

Mark Gordon

On 7 Nov 2003 04:31:20 -0800
Hello everybody,

I was doing one of the exercises in the K&R book, and I got something
really strange. Here's the source code:

/*
* Exercise 2-2 from the K&R book, page 42
*/
#include <stdio.h>

enum loop_control { EXIT, CONTINUE };

int getline (char s[], int lim)

size_t would be better than int, look up size_t in K&R.
{
short int loop = CONTINUE;

I would suggest
enum loop_control loop = CONTINUE;

A good debugger might then show you the enumeration used. If memory was
tight and you wanted to save space then you could make loop a char, but
I can't see any reason for a short in this case.
unsigned int i = 0;

Again, size_t would be a better type.
int c;

while (loop) {
c = getchar();
if (i == (lim - 2))

You have a problem if lim == 1.
loop = EXIT;
else if (c == EOF)
loop = EXIT;
else if (c == '\n')
loop = EXIT;

Why two seperate ifs?
else
s[i++] = c;
}

if (c == '\n')
s[i++] = c;

You could have handled this when you detected the newline above. Also,
if you hit the lim-2 without a newline you have just thrown away a
character.
s = '\0';


A problem if lim==1, even if that is a silly value.
return (i);
}

The strange thing is that lim doesn't seem to control anything at all.
I compiled it using GCC under cygwin on a windows 98 system (I added a
simple main() function that gets a line using getline() and then
prints it).
The strange thing is that even when I put a very small value for lim,
say 10, I can still get very big strings into it without it crashing.
Here's an example output:
$ gcc -o ex exercise2-2.c
$ ./ex
123333333333333333
1233333333333333
fdkjghfgsfgkjsdf
fdkjghfgfgkjsdf

If you used the following main you would get a better idea.


#define SIZ 5

int main(void)
{
char buf[SIZ];
int len;
while (1) {
len = getline(buf,SIZ);
printf("\"%s\" %d\n",buf,len);
}
return 0;
}

Here is a possible rework of your code. Note, I've reworked your code
rather than trying to solve the exersize, so it may not be what you
actually want.

int getline (char s[], size_t lim)
{
enum loop_control loop = CONTINUE;
size_t i = 0;
int c;

while (loop) {
c = getchar();
if (c == EOF)
loop = EXIT;
else {
s[i++] = c;
if (c == '\n' || i+1 >= lim)
loop = EXIT;
}
}

if (i<lim)
s = '\0';

return (i);
}

HTH.
 
J

Jeff

Anyway, how about this:
int getline( char *s, int lim )
{
int i = 0;
int c;

while( ((c = getchar()) != EOF) && (c != '\n') && (i < lim-2) )
s[i++] = c;
if (c == '\n')
s[i++] = c;
s = '\0';

return i;
}


That's the actual function, the exercise is to re-write it without
using &&'s ;)

I can't really remember what my main () function was exactly, but it
was basically something like this:

#define MAXLENGTH 10

int main (void)
{
int len;
char s[MAXLENGTH];

while ((len = getline (s, MAXLENGTH)) > 0)
printf("%s");

return (0);
}

Oh, and BTW I know the parentheses are unecessary, but I just like
writing my code like that.

Thanks for the feedback,

- Joseph
 
E

Ed Morton

On 11/7/2003 1:06 PM, Jeff wrote:
I can't really remember what my main () function was exactly, but it
was basically something like this:

#define MAXLENGTH 10

int main (void)
{
int len;
char s[MAXLENGTH];

while ((len = getline (s, MAXLENGTH)) > 0)
printf("%s");

Change that to:

printf("[%s]",s);

then rerun your test and the source of your problem should become clear.

Ed.
 
I

Irrwahn Grausewitz

(e-mail address removed) (Jeff) wrote:

[attribution restored, please do not snip it, thank you]
Irrwahn said:
Anyway, how about this:

int getline( char *s, int lim )
{
int i = 0;
int c;

while( ((c = getchar()) != EOF) && (c != '\n') && (i < lim-2) )
s[i++] = c;
if (c == '\n')
s[i++] = c;
s = '\0';

return i;
}


That's the actual function, the exercise is to re-write it without
using &&'s ;)


Yikes, sorry, I didn't have my copy of K&R handy... :)
I can't really remember what my main () function was exactly, but it
was basically something like this:

#define MAXLENGTH 10

int main (void)
{
int len;
char s[MAXLENGTH];

while ((len = getline (s, MAXLENGTH)) > 0)
printf("%s");
OK, you already corrected this in another reply to read:

printf ("%s", s);

Well, and now consider what happens: you read up to MAXLENGTH-2
characters in the first call of getline, *but* the rest of the
input is still waiting and gets processed in the consecutive calls
to getline. If you change the line to

printf ("%s\n", s);

you'll see that getline works as expected, just your output looked
like it didn't.
return (0);
}

Oh, and BTW I know the parentheses are unecessary, but I just like
writing my code like that.

Well, I just thought I mention it for the sake of whatever... :)
Thanks for the feedback,

You're welcome.

Regards
 
M

Matt Gessner

Jeff said:
Hello everybody,

Hello, Jeff,
I was doing one of the exercises in the K&R book, and I got something
really strange. Here's the source code:
/*
* Exercise 2-2 from the K&R book, page 42
*/
#include <stdio.h>
enum loop_control { EXIT, CONTINUE };
int getline (char s[], int lim)
{
short int loop = CONTINUE;
unsigned int i = 0;
int c;
while (loop) {
c = getchar();
if (i == (lim - 2))
loop = EXIT;
else if (c == EOF)
loop = EXIT;
else if (c == '\n')
loop = EXIT;
else
s[i++] = c;
}
if (c == '\n')
s[i++] = c;
s = '\0';

return (i);
}
The strange thing is that lim doesn't seem to control anything at all.
I compiled it using GCC under cygwin on a windows 98 system (I added a
simple main() function that gets a line using getline() and then
prints it).

Sure it does sometihng.
It leaves room in the buffer for the trailing \n and \0.
That's why you see the expression 'lim - 2'.

The strange thing is that even when I put a very small value for lim,
say 10, I can still get very big strings into it without it crashing.
Here's an example output:
$ gcc -o ex exercise2-2.c
$ ./ex
123333333333333333
1233333333333333
fdkjghfgsfgkjsdf
fdkjghfgfgkjsdf
(^C)
$

This seems strange to me, because I ran it under cygwin under
Win2k and I got exactly what I expected.

Here's what I recommend, for your own edification:

Change the four parts of the if-else if-else if-else block to
contain a printf statement that states what's happening.

I did that, too, and here it is:

if (i == (lim - 2))
{
loop = EXIT;
printf ("Hit limit: exiting\n");
}
else if (c == EOF)
{
loop = EXIT;
printf ("Hit EOF: exiting\n");
}
else if (c == '\n')
{
loop = EXIT;
printf ("Hit EOL: exiting\n");
}
else
{
s[i++] = c;
printf ("Adding character '%c'\n", c);
}

I got exactly what I expected.

HTH
 

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

compile error 30
Getchar() problem 8
Fibonacci 0
wcslen function 2
don't understand the "&&" in K&R2 example 2
Command Line Arguments 0
Beginner at c 0
Function is not worked in C 2

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top