Weird problem

Discussion in 'C Programming' started by Jeff, Nov 7, 2003.

  1. Jeff

    Jeff Guest

    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
    Jeff, Nov 7, 2003
    #1
    1. Advertising

  2. Jeff

    Ed Morton Guest

    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
    Ed Morton, Nov 7, 2003
    #2
    1. Advertising

  3. (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 = '\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
    --
    Irrwahn
    ()
    Irrwahn Grausewitz, Nov 7, 2003
    #3
  4. Jeff

    Mark Gordon Guest

    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 = '\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.
    --
    Mark Gordon
    Paid to be a Geek & a Senior Software Developer
    Although my email address says spamtrap, it is real and I read it.
    Mark Gordon, Nov 7, 2003
    #4
  5. Jeff

    Jeff Guest

    > 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
    Jeff, Nov 7, 2003
    #5
  6. Jeff

    Jeff Guest

    Oups, sorry about the error, it should be printf ("%s", s);

    - Joseph
    Jeff, Nov 7, 2003
    #6
  7. Jeff

    Ed Morton Guest

    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.
    Ed Morton, Nov 7, 2003
    #7
  8. (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 = '\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
    ()
    Irrwahn Grausewitz, Nov 7, 2003
    #8
  9. Jeff

    Matt Gessner Guest

    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 = '\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
    Matt Gessner, Nov 12, 2003
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. dorayme
    Replies:
    1
    Views:
    610
    richard
    Jan 21, 2011
  2. richard
    Replies:
    0
    Views:
    576
    richard
    Jan 21, 2011
  3. richard
    Replies:
    0
    Views:
    612
    richard
    Jan 21, 2011
  4. Beauregard T. Shagnasty

    Re: A Weird Appearance for a Weird Site

    Beauregard T. Shagnasty, Jan 21, 2011, in forum: HTML
    Replies:
    1
    Views:
    432
    Captain Paralytic
    Jan 21, 2011
  5. will
    Replies:
    6
    Views:
    406
    Phrogz
    Dec 27, 2006
Loading...

Share This Page