Thread: C99 standard prog buggy with Linux but not Windows

  1. #1
    Registered User
    Join Date
    Dec 2003
    Posts
    4

    C99 standard prog buggy with Linux but not Windows

    Hello all. I've run into a problem I just can't figure out and I'm beginning to think it's my compiler. I'll attach the source file, it's rather long to post on this message. The problem is when get_data() is called from main() the first input (Enter First Name)is skipped completely. But when get_data() is called from continue_function(), it runs fine. There is also a problem with display_report(), but I'm not too concerned about that now; I think both problems are related.

    I have no idea what the problem is. The strange thing is it runs-bug free on my friend's windows system (compiled with dev-c++), but is buggy with my Linux system.

    Thank you all in advance!

    P.S. This is a "type-and-run" program in book I'm trying to learn from. It's just basically a long program at the end of the chapter to pull together everything learned so far. It's supposed to collect information (you can see what sort of information in the struct before the start of main() I've replaced a few things, such as the gets() functions with fgets().

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > fflush(stdin); /* remove extra characters from keyboard buffer */
    Does absolutely nothing on any kind of operating system which isn't Microsoft.

    If you want to argue about it, the bug is really in the M$ side, because it's doing something non-standard with a standard function.

    This is why it's wrong - FAQ

    This is a short-term fix - FAQ

    The long-term fix is to replace all the varieties of input reading you have (scanf(), getchar()) with fgets() calls, and the whole flushing input problem goes away.

    Your line in main should be replaced with
    Code:
    char buff[BUFSIZ];
    
    //      ch = getchar();
    //      fflush(stdin);  /* remove extra characters from keyboard buffer */
            fgets( buff, BUFSIZ, stdin );
            ch = buff[0];
    Similarly, your use of scanf() later on should be replaced with a fgets() followed by a sscanf()
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2003
    Posts
    13
    Originally posted by Salem
    The long-term fix is to replace all the varieties of input reading you have (scanf(), getchar()) with fgets() calls, and the whole flushing input problem goes away.
    I've seen this show up with fgets() on Slackware Linux... I've been using:

    Code:
    #include <stdio.h>
    #include "clearkb.h"
    
    void clearkb(void)
    {
      char junk[80];
      fgets(junk,80,stdin);
    }
    to get around it. (Ha, I got it outta a book ;-) )
    #define punkCow

  4. #4
    Wannabe Coding God
    Join Date
    Mar 2003
    Posts
    259
    Originally posted by punkCow

    Code:
    #include <stdio.h>
    #include "clearkb.h"
    
    void clearkb(void)
    {
      char junk[80];
      fgets(junk,80,stdin);
    }
    what if there's more then 80 char's left in the buffer?
    They say that if you play a Windows Install CD backwords, you hear satanic messages. That's nothing; play it forward and it installs Windows.

  5. #5
    King of the Internet Fahrenheit's Avatar
    Join Date
    Oct 2001
    Posts
    128
    Then he can get them with another fgets call.

  6. #6
    Registered User linuxdude's Avatar
    Join Date
    Mar 2003
    Location
    Louisiana
    Posts
    926
    come on guys the easiest way for even infinite number of characters in the buffer
    Code:
    while(getchar()!='\n');

  7. #7
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    I would think this would be even better:
    Code:
    do
    {
      ch=getchar();
    }while( (ch != '\n') && (ch != EOF) );
    Which is what I use for my input buffer flushing.

  8. #8
    Registered User
    Join Date
    Dec 2003
    Posts
    4
    Thank you guys. I have the program working now. I wrote a function that I'd like to use to accept user input, but I'd like to get an opinion of someone more experienced.

    Here goes...
    Code:
    void gstring(char *string, int string_length)
    {
        char buffer[BUFSIZ];
        int counter;    
    
        fgets(buffer, BUFSIZ, stdin);
        for(counter = 0; counter < string_length; counter++)
        	string[counter] = buffer[counter];
        string[string_length - 1] = '\0';
        
    }
    usage...
    Code:
    char sentance[20];
    
    gstring(sentance, 20);
    So basically if I only want 20 characters to be read, it'll read just the 20.. but not leave anything standing around in stdin.

    I would like to have a function that's universal to strings that use arrays to allocate the memory and strings that use malloc() or some other memory allocation function to allocate the memory.

    like if I were to do the following...
    Code:
    char *string;
    string = malloc(80 * sizeof(char));
    how could I just get 80 characters or less without leaving anything in stdin?

    Thank you all again for reading this (long) post. I find all this "extra characters waiting in stdin" to be very troublesome and confusing.

  9. #9
    Been here, done that.
    Join Date
    May 2003
    Posts
    1,164
    Your code will do it, 99.999999% of the time. The only time it won't will be when some bozo decides to type in BUFSIZ or more characters. Assuming BUFSIZ is huge (or the default), probably not a problem.

    Slightly modified, this might work a little better:

    Code:
    void gstring(char *string, int string_length)
    {
        char buffer[BUFSIZ];
        int k;    
    
        fgets(buffer, BUFSIZ, stdin);
        buffer[string_length - 1] = '\0';       // clear at the max return length
        k = strlen(buffer)-1;                   // index of last character
        if (buffer[k] == '\n') buffer[k]= '\0'; // clear trailing return
        strcpy(string, buffer);                 // copy buffer to return value
    }
    Definition: Politics -- Latin, from
    poly meaning many and
    tics meaning blood sucking parasites
    -- Tom Smothers

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > The only time it won't will be when some bozo decides to type in BUFSIZ or more characters
    The bozo typically being someone trying a buffer overflow attack on your code. At which point, you can reasonably do anything you like so long as you maintain the integrity of your code.

    If your current fgets() buffer does not contain a newline, you can either read ahead until you do get a newline, or just leave it there for the next fgets() call to see if it still makes any sense.


    > fgets(buffer, BUFSIZ, stdin);
    For additional safety, you should check whether this returns NULL or not. If it does return NULL, buffer is undefined (and should not therefore be used).

    > buffer[string_length - 1] = '\0';
    pedantic: what if string_length > BUFSIZ
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    The use of the local buffer is pointless (and potentially dangerous). Just write to the memory provided as a pointer in the function parameter, for the specified length.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  12. #12
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    A considerably better solution for gstring would be to use fgets, remove the newline (if you need to. It can be useful sometimes), and return status codes to let the client know the state of both the buffer and the stream. The four minimum conditions you want to handle are success, extraneous data in the stream, end of file, and read error:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    int prefgets ( char *buff, size_t size, FILE *in )
    {
      int rc = 1;  /* Success */
      
      if ( fgets ( buff, size, in ) != NULL ) {
        char *newline = strrchr ( buff, '\n' );
        if ( newline != NULL )
          *newline = '\0';
        else
          rc = 2;  /* More input */
      }
      else {
        if ( feof ( in ) )
          rc = 0;  /* End of file */
        if ( ferror ( in ) )
          rc = -1; /* Read error */
      }
      
      return rc;
    }
    
    int main ( void )
    {
      char buff[5];
      int rc;
    
      rc = prefgets ( buff, sizeof buff, stdin );
      if ( rc > 0 ) {
        printf ( "%s\n", buff );
        if ( rc == 2 )
          printf ( "There's still more data in the stream\n" );
      }
      else {
        if ( rc == -1 )
          perror ( NULL );
        else
          printf ( "EOF found\n" );
      }
    
      return 0;
    }
    My best code is written with the delete key.

  13. #13
    Registered User caroundw5h's Avatar
    Join Date
    Oct 2003
    Posts
    751
    Originally posted by WaltP
    Your code will do it, 99.999999% of the time. The only time it won't will be when some bozo decides to type in BUFSIZ or more characters. Assuming BUFSIZ is huge (or the default), probably not a problem.
    Doesn't BUFSIZ have a value of 5xx bytes. Or does it depend on the bit bt value of your Platform. 16,32, 64 ? Just wondering.

  14. #14
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Doesn't BUFSIZ have a value of 5xx bytes.
    No, but it does have to be at least 256. The actual size depends on the size of the buffer used by the setbuf function.
    My best code is written with the delete key.

  15. #15
    Been here, done that.
    Join Date
    May 2003
    Posts
    1,164
    Originally posted by Hammer
    The use of the local buffer is pointless (and potentially dangerous). Just write to the memory provided as a pointer in the function parameter, for the specified length.
    I don't know about pointless. I keeps the input stream clean when more than string_length characters are entered. If you use the provided pointer, this call will only load the first string_length characters leaving the rest of the input in the stream. The next fgets() call will load the next portion of the input from the first fgets -- definitely not a good idea.

    And dangerous? Why?
    Definition: Politics -- Latin, from
    poly meaning many and
    tics meaning blood sucking parasites
    -- Tom Smothers

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A question about windows programming
    By Hussain Hani in forum Windows Programming
    Replies: 16
    Last Post: 05-23-2007, 07:38 AM
  2. Script errors - bool unrecognized and struct issues
    By ulillillia in forum Windows Programming
    Replies: 10
    Last Post: 12-18-2006, 04:44 AM
  3. Why Linux, for the average user?
    By Hunter2 in forum A Brief History of Cprogramming.com
    Replies: 32
    Last Post: 07-07-2006, 02:36 PM
  4. Erm...so what DOES Linux do that Windows doesn't?
    By 7smurfs in forum Tech Board
    Replies: 19
    Last Post: 09-09-2005, 03:04 PM
  5. Dabbling with Linux.
    By Hunter2 in forum Tech Board
    Replies: 21
    Last Post: 04-21-2005, 04:17 PM