fgets behaviour with strncmp

Discussion in 'C Programming' started by Krumble Bunk, Jun 17, 2008.

  1. Krumble Bunk

    Krumble Bunk Guest

    Hi all,

    Having some trouble with a seemingly-simple task. Need to have a
    basic CLI functionality as per:

    prompt> <- \n
    prompt> <- \n
    prompt> quit <- should quit as per my snippet, but doesn't.

    I've thrown a few random fflush()'s in, but no joy. I have never
    really learnt the ANSI way ala fgets, fopen, etc.. so this is quite
    new to me. Any advice on how I can actually make the program quit
    when "quit" is entered would be appreciated :)

    Code:

    #include <stdio.h>

    int main()
    {

    int done=0;
    int len=0;
    char buf[MAXBUF];

    printf("> ");
    while(!done)
    {
    if(fgets(buf,MAXBUF,stdin) < 0)
    {
    perror("fgets");
    exit(1);
    }

    len=strlen(buf);
    buf[len]='\0';

    fflush(stdin);
    if(*buf == '\n')
    printf("> ");
    printf("debug: %s\n",buf);
    fflush(stdin);
    fflush(stdout);
    if(!strncmp(buf,"quit",len))
    done=1;
    }
    return 0;
    }

    thanks

    kb
    Krumble Bunk, Jun 17, 2008
    #1
    1. Advertising

  2. On Jun 17, 11:01 am, Krumble Bunk <> wrote:
    > Hi all,
    >
    > Having some trouble with a seemingly-simple task. Need to have a
    > basic CLI functionality as per:
    >
    > prompt> <- \n
    > prompt> <- \n
    > prompt> quit <- should quit as per my snippet, but doesn't.
    >
    > I've thrown a few random fflush()'s in, but no joy. I have never
    > really learnt the ANSI way ala fgets, fopen, etc.. so this is quite
    > new to me. Any advice on how I can actually make the program quit
    > when "quit" is entered would be appreciated :)
    >
    > Code:
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    >
    > int done=0;
    > int len=0;
    > char buf[MAXBUF];
    >
    > printf("> ");
    > while(!done)
    > {
    > if(fgets(buf,MAXBUF,stdin) < 0)
    > {
    > perror("fgets");
    > exit(1);
    > }
    >
    > len=strlen(buf);
    > buf[len]='\0';
    >
    > fflush(stdin);
    > if(*buf == '\n')
    > printf("> ");
    > printf("debug: %s\n",buf);
    > fflush(stdin);
    > fflush(stdout);
    > if(!strncmp(buf,"quit",len))
    > done=1;
    > }
    > return 0;
    >
    > }
    >
    > thanks
    >
    > kb


    Lots of issues there, but your central problem is that buf includes
    the newline. If you set (after appropriate checking) buf[len-1] to
    '\0' and use strcmp you will fix that. A few other points:

    don't fflush(stdin)
    do include string.h, stdlib.h
    do define MAXBUF somewhere
    do turn on your compilers warnings...

    -David
    David Resnick, Jun 17, 2008
    #2
    1. Advertising

  3. Krumble Bunk

    Krumble Bunk Guest

    On Jun 17, 4:14 pm, David Resnick <> wrote:
    > On Jun 17, 11:01 am, Krumble Bunk <> wrote:
    >
    >
    >
    > > Hi all,

    >
    > > Having some trouble with a seemingly-simple task. Need to have a
    > > basic CLI functionality as per:

    >
    > > prompt> <- \n
    > > prompt> <- \n
    > > prompt> quit <- should quit as per my snippet, but doesn't.

    >
    > > I've thrown a few random fflush()'s in, but no joy. I have never
    > > really learnt the ANSI way ala fgets, fopen, etc.. so this is quite
    > > new to me. Any advice on how I can actually make the program quit
    > > when "quit" is entered would be appreciated :)

    >
    > > Code:

    >
    > > #include <stdio.h>

    >
    > > int main()
    > > {

    >
    > > int done=0;
    > > int len=0;
    > > char buf[MAXBUF];

    >
    > > printf("> ");
    > > while(!done)
    > > {
    > > if(fgets(buf,MAXBUF,stdin) < 0)
    > > {
    > > perror("fgets");
    > > exit(1);
    > > }

    >
    > > len=strlen(buf);
    > > buf[len]='\0';

    >
    > > fflush(stdin);
    > > if(*buf == '\n')
    > > printf("> ");
    > > printf("debug: %s\n",buf);
    > > fflush(stdin);
    > > fflush(stdout);
    > > if(!strncmp(buf,"quit",len))
    > > done=1;
    > > }
    > > return 0;

    >
    > > }

    >
    > > thanks

    >
    > > kb

    >
    > Lots of issues there, but your central problem is that buf includes
    > the newline. If you set (after appropriate checking) buf[len-1] to
    > '\0' and use strcmp you will fix that. A few other points:
    >
    > don't fflush(stdin)
    > do include string.h, stdlib.h
    > do define MAXBUF somewhere
    > do turn on your compilers warnings...
    >
    > -David


    many thanks - fixed it nicely.

    thanks again

    kb.
    Krumble Bunk, Jun 17, 2008
    #3
  4. Krumble Bunk

    Flash Gordon Guest

    Krumble Bunk wrote, On 17/06/08 16:01:

    <snip>

    In addition to the other comment you have seen...

    Random changes to code (you mentioned throwing in random calls to
    fflush) is NEVER a good way to develop.

    > #include <stdio.h>
    >
    > int main()


    Better would be
    int main(void)

    > {
    >
    > int done=0;
    > int len=0;
    > char buf[MAXBUF];
    >
    > printf("> ");


    In this instance a do-while loop makes more sense since you always want
    to run the loop at least once.

    > while(!done)
    > {


    fflush(stdout);

    With your code the first prompt might not be displayed before waiting
    for input.

    > if(fgets(buf,MAXBUF,stdin) < 0)
    > {
    > perror("fgets");
    > exit(1);


    This is not a portable value to pass to exit. Only 0, EXIT_SUCCESS and
    EXIT_FAILURE are portable. Some times there are good reasons to use
    non-portable return codes, but not here.

    Also, later you use a return rather than calling exit. You should be
    consistent in which method you use to leave main. Personally I normally
    use return.

    > }
    >
    > len=strlen(buf);
    > buf[len]='\0';


    This would not do what you want if too long a line was input. Check to
    see if it was a newline first.

    > fflush(stdin);


    fflush is not defined for input streams by the C standard. Some
    implementations *might* define it, but others definitely don't.

    > if(*buf == '\n')
    > printf("> ");


    Better in my opinion to be consistent about whether you are using array
    or pointer operators on buf. Mind you, printing the prompt here seems
    odd and doing so conditionally seems even more odd.

    > printf("debug: %s\n",buf);
    > fflush(stdin);
    > fflush(stdout);
    > if(!strncmp(buf,"quit",len))
    > done=1;


    After switching to a do-while loop you could put the above test as the
    condition and scrap the done flag!

    > }
    > return 0;
    > }

    --
    Flash Gordon
    Flash Gordon, Jun 17, 2008
    #4
  5. santosh <> writes:

    > Krumble Bunk wrote:
    >> Having some trouble with a seemingly-simple task. Need to have a
    >> basic CLI functionality as per:
    >>
    >> prompt> <- \n
    >> prompt> <- \n
    >> prompt> quit <- should quit as per my snippet, but doesn't.

    >
    > <snip>
    >
    > #include <ctype.h>
    >
    > int main(void)
    > {

    <snip>
    > while (isblank((int)*line)) line++;


    Presumably you intended to write isblank((unsigned char)*line) here.
    I can't see any value in the cast to int.

    <snip>
    > }


    --
    Ben.
    Ben Bacarisse, Jun 18, 2008
    #5
  6. Krumble Bunk

    santosh Guest

    Ben Bacarisse wrote:

    > santosh <> writes:
    >
    >> Krumble Bunk wrote:
    >>> Having some trouble with a seemingly-simple task. Need to have a
    >>> basic CLI functionality as per:
    >>>
    >>> prompt> <- \n
    >>> prompt> <- \n
    >>> prompt> quit <- should quit as per my snippet, but doesn't.

    >>
    >> <snip>
    >>
    >> #include <ctype.h>
    >>
    >> int main(void)
    >> {

    > <snip>
    >> while (isblank((int)*line)) line++;

    >
    > Presumably you intended to write isblank((unsigned char)*line) here.
    > I can't see any value in the cast to int.


    You are right. In fact, would the cast to unsigned char be necessary at
    all, given that all the characters returned by fgets are guaranteed to
    be positive integers?

    <snip>
    santosh, Jun 18, 2008
    #6
  7. Krumble Bunk

    santosh Guest

    Richard Heathfield wrote:

    > santosh said:
    >
    > <snip>
    >
    >> In fact, would the cast to unsigned char be necessary at
    >> all, given that all the characters returned by fgets are guaranteed
    >> to be positive integers?

    >
    > Chapter and verse, please. I think you're mistaken about the existence
    > of such a guarantee. It applies to fgetc, yes, but not to fgets.


    Aren't all the standard byte input functions implemented as if they were
    composed of successive calls to fgetc? If so, a guarantee for fgetc
    should be applicable to functions modelled upon it too.
    santosh, Jun 18, 2008
    #7
  8. On Tue, 17 Jun 2008 08:01:59 -0700 (PDT), Krumble Bunk
    <> wrote:

    >Hi all,
    >
    >Having some trouble with a seemingly-simple task. Need to have a
    >basic CLI functionality as per:
    >
    >prompt> <- \n
    >prompt> <- \n
    >prompt> quit <- should quit as per my snippet, but doesn't.
    >
    >I've thrown a few random fflush()'s in, but no joy. I have never
    >really learnt the ANSI way ala fgets, fopen, etc.. so this is quite
    >new to me. Any advice on how I can actually make the program quit
    >when "quit" is entered would be appreciated :)
    >
    >Code:
    >
    >#include <stdio.h>
    >
    >int main()
    >{
    >
    > int done=0;
    > int len=0;
    > char buf[MAXBUF];
    >
    > printf("> ");
    > while(!done)
    > {
    > if(fgets(buf,MAXBUF,stdin) < 0)


    fgets returns a char*, not an int. It will return NULL on end of file
    or error. NULL is guaranteed to compare equal to 0 so your error
    message will never get displayed. I doubt if a non-NULL return will
    ever result in your if evaluating true.

    > {
    > perror("fgets");
    > exit(1);


    Use EXIT_FAILURE for portability.

    > }
    >
    > len=strlen(buf);
    > buf[len]='\0';


    If your intent is to remove the '\n' that fgets will include in the
    string if it can, then you need len-1.

    >
    > fflush(stdin);


    fflush is not defined for input streams. This invokes undefined
    behavior.

    > if(*buf == '\n')


    The only way this can evaluate to true is if the user hits enter
    without hitting any data keys. If stdin has been redirected to a
    file, then you would need an empty (not blank) line.

    > printf("> ");
    > printf("debug: %s\n",buf);
    > fflush(stdin);
    > fflush(stdout);
    > if(!strncmp(buf,"quit",len))
    > done=1;
    > }
    >return 0;
    >}



    Remove del for email
    Barry Schwarz, Jun 18, 2008
    #8
  9. Krumble Bunk

    santosh Guest

    Richard Heathfield wrote:

    > santosh said:
    >
    >> Richard Heathfield wrote:
    >>
    >>> santosh said:
    >>>
    >>> <snip>
    >>>
    >>>> In fact, would the cast to unsigned char be necessary at
    >>>> all, given that all the characters returned by fgets are guaranteed
    >>>> to be positive integers?
    >>>
    >>> Chapter and verse, please. I think you're mistaken about the
    >>> existence of such a guarantee. It applies to fgetc, yes, but not to
    >>> fgets.

    >>
    >> Aren't all the standard byte input functions implemented as if they
    >> were composed of successive calls to fgetc?

    >
    > Yes.
    >
    >> If so, a guarantee for fgetc
    >> should be applicable to functions modelled upon it too.

    >
    > And so it is - for just as long as you are storing the results in an
    > array of unsigned char. But you're not, are you? You're storing them
    > (quite properly) in an array of char. So, on systems where char is
    > signed by default (and there are still quite a few of those about),
    > you have a problem if you assume that they are representable as
    > unsigned char without a conversion taking place. For example, consider
    > an input to fgets that includes a character with code point 130, on a
    > system with 8-bit char, signed by default. The fgets function will
    > read this as if via fgetc, so the value 130 will be returned from
    > fgetc (or "as-if-fgetc" if you prefer) as an int. This fulfils the
    > terms of the contract that you mentioned. Now fgets has to store this
    > value somewhere in your array of char. Since, on the system I've
    > mentioned, CHAR_MAX is 127, fgets will have to store the 130 into that
    > array as a negative number: -126 is a definite possibility (I know
    > because it's what happens on my system!), and -126 is not
    > representable as unsigned char, because unsigned char can't represent
    > negative values unless they are first converted into non-negative
    > values.
    >
    > In the case in point, the C99 function isblank is being used. This is
    > one of the "is*" functions, prototyped in <ctype.h>, that require
    > their input to be either EOF or a value representable as an unsigned
    > char. We have discussed many times before how negative values can foul
    > this up. For example:
    >
    > #define isblank(x) ( ((x) == EOF) ? (x) : __isblank[(x)] )
    >
    > which invokes undefined behaviour if passed a negative value other
    > than EOF. (E&OE - my track record on illustrative is* macros is
    > appalling.)


    Okay, many thanks for making that clear.
    santosh, Jun 18, 2008
    #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. pembed2003

    strncmp performance

    pembed2003, Jan 27, 2004, in forum: C Programming
    Replies:
    26
    Views:
    4,652
    pembed2003
    Jan 29, 2004
  2. jacob navia

    strncmp(a,b,0)

    jacob navia, Oct 4, 2004, in forum: C Programming
    Replies:
    9
    Views:
    569
    Dan Pop
    Oct 6, 2004
  3. Bert

    strcmp/strncmp/strnicmp

    Bert, Mar 29, 2005, in forum: C Programming
    Replies:
    1
    Views:
    667
    Richard Bos
    Mar 29, 2005
  4. Preets
    Replies:
    4
    Views:
    530
  5. C. J. Clegg

    Question on strncmp / strnicmp use

    C. J. Clegg, Jan 16, 2009, in forum: C Programming
    Replies:
    56
    Views:
    1,869
    CBFalconer
    Jan 24, 2009
Loading...

Share This Page