Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Weird problem

Reply
Thread Tools

Weird problem

 
 
Jeff
Guest
Posts: n/a
 
      11-07-2003
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
 
Reply With Quote
 
 
 
 
Ed Morton
Guest
Posts: n/a
 
      11-07-2003


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


 
Reply With Quote
 
 
 
 
Irrwahn Grausewitz
Guest
Posts: n/a
 
      11-07-2003
(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
()
 
Reply With Quote
 
Mark Gordon
Guest
Posts: n/a
 
      11-07-2003
On 7 Nov 2003 04:31:20 -0800
(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.
 
Reply With Quote
 
Jeff
Guest
Posts: n/a
 
      11-07-2003
> 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
 
Reply With Quote
 
Jeff
Guest
Posts: n/a
 
      11-07-2003
Oups, sorry about the error, it should be printf ("%s", s);

- Joseph
 
Reply With Quote
 
Ed Morton
Guest
Posts: n/a
 
      11-07-2003


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.

 
Reply With Quote
 
Irrwahn Grausewitz
Guest
Posts: n/a
 
      11-07-2003
(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
()
 
Reply With Quote
 
Matt Gessner
Guest
Posts: n/a
 
      11-12-2003
Jeff <> 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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: A Weird Appearance for a Weird Site Beauregard T. Shagnasty HTML 1 01-21-2011 04:17 PM
Re: A Weird Appearance for a Weird Site richard HTML 0 01-21-2011 07:10 AM
Re: A Weird Appearance for a Weird Site dorayme HTML 1 01-21-2011 06:51 AM
Re: A Weird Appearance for a Weird Site richard HTML 0 01-21-2011 06:46 AM
newbie with a weird technical problem (@ least I think it's weird) will Ruby 6 12-27-2006 04:46 PM



Advertisments