467,906 Members | 1,662 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 467,906 developers. It's quick & easy.

Weird problem

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[i] = '\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
Nov 13 '05 #1
  • viewed: 1984
Share:
8 Replies


On 11/7/2003 6:31 AM, Jeff wrote:
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: <snip> 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.
(^C)
$

Any feedback will be appreciated!
Cheers!

- Joseph


Nov 13 '05 #2
ag*******@netcourrier.com (Jeff) wrote:
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[i] = '\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[i] = '\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
--
Irrwahn
(ir*******@freenet.de)
Nov 13 '05 #3
On 7 Nov 2003 04:31:20 -0800
ag*******@netcourrier.com (Jeff) wrote:
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[i] = '\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[i] = '\0';

return (i);
}

HTH.
--
Mark Gordon
Paid to be a Geek & a Senior Software Developer
Although my email address says spamtrap, it is real and I read it.
Nov 13 '05 #4
> 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[i] = '\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
Nov 13 '05 #5
Oups, sorry about the error, it should be printf ("%s", s);

- Joseph
Nov 13 '05 #6


On 11/7/2003 1:06 PM, Jeff wrote:
<snip>
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.

Nov 13 '05 #7
ag*******@netcourrier.com (Jeff) wrote:

[attribution restored, please do not snip it, thank you]
Irrwahn Grausewitz wrote:
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[i] = '\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
--
Irrwahn
(ir*******@freenet.de)
Nov 13 '05 #8
Jeff <ag*******@netcourrier.com> wrote:
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[i] = '\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
Cheers! - Joseph


Nov 13 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by redneck_kiwi | last post: by
6 posts views Thread by Unicorn | last post: by
1 post views Thread by Jeffrey Melloy | last post: by
reply views Thread by Zwyatt | last post: by
1 post views Thread by Strange Cat | last post: by
reply views Thread by P Pulkkinen | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.