Thread: fgets not truncating text

  1. #16
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Quote Originally Posted by Adak View Post
    fgets() does truncates input. Try to add a full row of text, and see for yourself.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    #define SIZE 50
    
    int main(void) {
       char name[SIZE];
       char *pch;
       int len;
    
       fgets(name, sizeof(name), stdin);
       
       len=strlen(name);
       pch=&name[len-1];
       if(*pch=='\n')
          *pch='\0';
       printf("name: %s has %d chars in it\n",name,strlen(name));
    
       return 0;
    }
    The title might be off because as a beginner that is what it appeared to me was happening. However the issue that is happening is still present.


    char *storage; // Create a storage container to store the answer from the user in fgets.storage=malloc(sizeof(MAXNAME)); // Allocate memory for the pointer just created with malloc// And have a string "storage" of size MAXNAME, orcompany *storage; // Create a storage container to store the answer from the user in fgets.storage=malloc(sizeof(company)); // Allocate memory for the pointer just created with malloc// And go through making sure that you are writing to the correct members in the structure.
    I changed the malloc back to MAXNAME and that didn't help out at all. The below is still the same result. My understanding is the malloc simply allocates memory on the heap to be able to use so it shouldn't matter other than the amount of memory I am allocating whether or not I use MAXNAME (which is equal to 20) or company (which is equal to 112). As long as there is enough memory to hold the requests, isn't that correct?

    Result
    What is the 1st employees first name? Kammiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
    What is Kammiiiiiiiiiiiiiii's last name? How old is Kammiiiiiiiiiiiiiii iiiiiiiiiiiiiiiiiii? What is iii's hourly wage? $What is the date of hire for iii (ie. 04-20-1975)? When was the last pay raise date for iii (ie. 04-20-1975)? What is the home phone for iii (ie. 555-555-5555)?
    Last edited by scrfix; 12-18-2012 at 07:19 PM.

  2. #17
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Quote Originally Posted by fnoyan View Post
    I have read 12.26a and already tried fflush(stdout) without success.
    I had not read 12.26b and that was pretty interesting to know. Is that trying to tell me that there is nothing standardized that I can do in order to get rid of additional characters? Really?

  3. #18
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Is that trying to tell me that there is nothing standardized that I can do in order to get rid of additional characters? Really?
    No, it said
    Alternatively, you can consume the rest of a partially-read line with a simple code fragment like


    while((c = getchar()) != '\n' && c != EOF)
    /* discard */ ;
    Fact - Beethoven wrote his first symphony in C

  4. #19
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Okay,

    I will try that right now. Although I am not really sure how to implement that so I will have to figure out what this actually means. It looks like it has EOF which I understand to be End of File which would indicate that it is talking about opening an actual file which is not the case here, is that correct?

    Wayne
    Last edited by scrfix; 12-18-2012 at 07:35 PM.

  5. #20
    Just kidding.... fnoyan's Avatar
    Join Date
    Jun 2003
    Location
    Still in the egg
    Posts
    275
    Quote Originally Posted by scrfix View Post
    I had not read 12.26b and that was pretty interesting to know. Is that trying to tell me that there is nothing standardized that I can do in order to get rid of additional characters? Really?
    yes... so, you may want to write your own function.

    Have you tried compiling the same code under Win32 (not with MinGW or Cygwin)? (i.e with a completely different fflush() implementation)

    Please also refer (or from command line "man 3 fflush")
    http://manpages.ubuntu.com/manpages/.../fflush.3.html

    And, is there a particular reason why you do not use scanf()?
    Last edited by fnoyan; 12-18-2012 at 07:56 PM.

  6. #21
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Quote Originally Posted by fnoyan View Post
    yes... so, you may want to write your own function.

    Have you tried compiling the same code under Win32 (not with MinGW or Cygwin)? (i.e with a completely different fflush() implementation)
    I have not tried compiling it with another OS other than GCC in the Linux environment. I kind of wanted to get it working first in the linux environment prior to compiling it in another environment.

  7. #22
    Just kidding.... fnoyan's Avatar
    Join Date
    Jun 2003
    Location
    Still in the egg
    Posts
    275
    Well, definitely the flushing does not work for you here. So, you may;

    1 ) write your own function to read from input
    2 ) Use scanf()

    I'd vote for option 2

  8. #23
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Quote Originally Posted by fnoyan View Post
    Well, definitely the flushing does not work for you here. So, you may;

    1 ) write your own function to read from input
    2 ) Use scanf()

    I'd vote for option 2
    So what you are telling me is that fgets is not the correct function to use here because people can obviously type more than what fgets expects and it doesn't just drop the excess text. I was told to use fgets when accepting string input because it checks the length of the string. I should not be using that? I should be using scanf instead? Isn't there a length buffer overflow that can happen with using scanf?

    I will try to change the code from fgets to scanf's to see if that prevents the issue.

    Wayne

  9. #24
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Have a look at this example:
    Code:
    int main(void)
    {
        char *fname;
        int read_ok;
    
    
        fname = malloc(MAXNAME * sizeof(*fname));
    
    
        do
        {
            char *s;
    
            printf("Enter Name:");
            fflush(stdout);
    
    
            fgets(fname, MAXNAME, stdin);
            if ((s=strstr(fname, "\n")) != NULL)
            {
                *s = '\0';
                read_ok = 1;
            }
            else
            {
                int c;
                while((c = getchar()) != '\n' && c != EOF) continue;
    
    
                fprintf(stderr, "Problem with string size\n");
                read_ok = 0;
            }
        } while (read_ok == 0);
    
    
        printf("Name is %s\n", fname);
    
    
        free(fname);
    
    
        return 0;
    }
    [edit]
    Note that using scanf for strings can be dangerous if you don't restrict the input - You risk having an overflow.

    The easiest way of managing input is using fgets, like the example I have given above.
    [/edit]
    Last edited by Click_here; 12-18-2012 at 08:43 PM.
    Fact - Beethoven wrote his first symphony in C

  10. #25
    Just kidding.... fnoyan's Avatar
    Join Date
    Jun 2003
    Location
    Still in the egg
    Posts
    275
    Quote Originally Posted by scrfix View Post
    So what you are telling me is that fgets is not the correct function to use here ....
    No fgets() is a better choice actually, obviously you can implement scanf() functionalty as a combination of fgets() + sscanf() functions.

  11. #26
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    You can truncate input with scanf(), fscanf() or sscanf(), and we know that fgets() can always truncate input to the size you specify.

    C has nothing in the standard, to stop the user from pressing keys on his keyboard, and having them echoed up to the screen. (There is a small char buffer that handles that).

  12. #27
    Registered User
    Join Date
    Apr 2012
    Posts
    35
    Some of that is a little over my head but I will study the code and then try to implement it in my code. Thanks. I will try to get back to you with what my results are but that probably won't be tonight unless I get it completed tonight.

    From what I can tell each line does the following. The only thing I have not seen before is the continue keyword phrase. I am not sure what function that actually serves.

    The conditional within the do while loop looks like it will never hit the else condition because it looks for the \n using strstr and then sets read_ok=1; Since we are using fgets and it adds the \n it will find it, set read_ok=1 and proceed. It will skip past the else since we have already determined. It will get to the while and see that read_ok is not set to 0 and it will exit out of the do while loop. Am I wrong about that?

    Code:
    int main(void)
    {
      char *fname;                  // Create a pointer of type char. 
      int read_ok;                  // Create a read_ok variable of type int
    
    
      fname = malloc(MAXNAME * sizeof(*fname)); // Malloc out MAXNAME which is 20 bytes * the size of a pointer which is 4 bytes so this should malloc 80 bytes of memory on the heap.
    
    
      do                            // This will run a minimal of once even if read_ok does not equal 0.
      {
        char *s;                    // Create a pointer that will point to a type char.
    
        printf("Enter Name:");      // Print out sentence asking user for input.
        fflush(stdout);             // Flush out the standard output.
    
    
        fgets(fname, MAXNAME, stdin); // Wait for input from the user.  Store that input into the malloc'ed space that fname is pointing to.
        if ((s = strstr(fname, "\n")) != NULL)  // Look for the first occurrence of \n and if we find one then proceed.
        {
          *s = '\0';                // Replace that occurrence with a NUL terminator.
          read_ok = 1;              // Set read_ok to 1.  This means that the do while loop will end. 
        } else                      // There was no new line found. However it doesn't appear that this will ever be reached.
        {
          int c;                    // Create a variable of type int.
          while ((c = getchar()) != '\n' && c != EOF)
            continue;               // I believe this is supposed to be looking at each character while it gets typed however I believe fgets will prevent this from ever being used.  I don't know what continue does.
    
    
          fprintf(stderr, "Problem with string size\n");  // I have never used fprintf before so I am not sure what this does other than prints out the error code and text.
          read_ok = 0;
        }
      } while (read_ok == 0);       // Only do this while the int read_ok is equal to 0.
    
    
      printf("Name is %s\n", fname);  // Print out the text stored in the pointer.
    
    
      free(fname);                  // Free the memory malloc'ed.
    
    
      return 0;                     // Successful completion
    }
    C has nothing in the standard, to stop the user from pressing keys on his keyboard, and having them echoed up to the screen. (There is a small char buffer that handles that)
    I know they don't have anything to stop people from pressing keys on the keyboard or it repeating on the screen. I was looking for something to stop the rest of the excess text from going in to my next answers after enter is pushed.
    Last edited by Salem; 12-18-2012 at 10:55 PM. Reason: demunged the code

  13. #28
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    // Create a variable of type int.
    int c;

    // I believe this is supposed to be looking at each character while it
    // gets typed however I believe fgets will prevent this from ever being
    // used. I don't know what continue does.

    while((c = getchar()) != '\n' && c != EOF) continue;
    I think that you can see that it keeps pulling stuff off stdin until either a new line is found, or the EOF.

    "continue" is used in loops to say "start the loop again". It is not needed: However, I've put it here so that this "while" can be easily told apart from the end of a do/while loop when looking at the code.
    Fact - Beethoven wrote his first symphony in C

  14. #29
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    If you wanted my advice on how to implement this into your code, turn this into a function like this:

    Code:
    void get_user_input (char *prompt, char *input_string, size_t input_string_size);
    
    
    int main(void)
    {
        char *fname;
    
    
        fname = malloc(MAXNAME * sizeof(*fname));
    
    
        get_user_input ("Enter first name", fname, MAXNAME);
    
    
        printf("Name is %s\n", fname);
    
    
        free(fname);
    
    
        return EXIT_SUCCESS;
    }
    
    
    void get_user_input (char *prompt, char *input_string, size_t input_string_size)
    {
        int read_ok;
    
    
        do
        {
            char *s;
    
    
            printf("%s: ", prompt);
            fflush(stdout);
    
    
            fgets(input_string, input_string_size, stdin);
            
            if ((s=strstr(input_string, "\n")) != NULL)
            {
                *s = '\0';
                read_ok = 1;
                
            }
            else
            {
                int c;
                
                while((c = getchar()) != '\n' && c != EOF)
                {
                    continue;
                    
                }
    
    
                fprintf(stderr, "Problem with string size\n");
                read_ok = 0;
                
            }
    
    
        }
        while (read_ok == 0);
    
    
    }
    Fact - Beethoven wrote his first symphony in C

  15. #30
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    There is one last thing to worry about - That's the return value from fgets -> If this is NULL, there is a big problem. I've implemented this with a return value. [edit] It would also be worth mentioning the return value from malloc should not be NULL [/edit]

    If you want to test if it is working, change stdin to stdout
    Code:
    char *get_user_input (char *prompt, char *input_string, size_t input_string_size);
    
    
    int main(void)
    {
        char *fname;
    
    
        if ((fname = malloc(MAXNAME * sizeof(*fname))) == NULL)
        {
            fprintf(stderr, "-ERROR-\nAllocation Failure\n");
            return EXIT_FAILURE;
        }
    
    
        if (get_user_input ("Enter first name", fname, MAXNAME) != NULL)
        {
            printf("Name is %s\n", fname);
        }
        else
        {
            fprintf(stderr, "-ERROR-\nProblem with reading string\n");
    
            return EXIT_FAILURE;
        }
    
    
        free(fname);
    
    
        return EXIT_SUCCESS;
    }
    
    
    char *get_user_input (char *prompt, char *input_string, size_t input_string_size)
    {
        int read_ok;
        char *return_val;
    
    
        do
        {
            char *s;
    
    
            printf("%s: ", prompt);
            fflush(stdout);
    
    
    
    
            if ((return_val = fgets(input_string, input_string_size, stdin)) == NULL)
            {
                break;
            }
    
    
            if ((s=strstr(input_string, "\n")) != NULL)
            {
                *s = '\0';
                read_ok = 1;
    
    
            }
            else
            {
                int c;
    
    
                while((c = getchar()) != '\n' && c != EOF)
                {
                    continue;
    
    
                }
    
    
                fprintf(stderr, "Problem with string size\n");
                read_ok = 0;
    
    
            }
    
    
        }
        while (read_ok == 0);
    
    
        return return_val;
    }
    Last edited by Click_here; 12-18-2012 at 11:14 PM.
    Fact - Beethoven wrote his first symphony in C

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. FGETS from text to array
    By Oonej in forum C Programming
    Replies: 30
    Last Post: 07-10-2011, 01:46 AM
  2. Fgets() & Fputs() to combine text files?
    By d2rover in forum C Programming
    Replies: 5
    Last Post: 11-20-2010, 03:58 PM
  3. truncating front
    By jimmianlin in forum C Programming
    Replies: 2
    Last Post: 10-01-2009, 04:12 PM
  4. Truncating a char *
    By ajb268 in forum C++ Programming
    Replies: 3
    Last Post: 01-31-2005, 02:57 PM
  5. Truncating a double?
    By criticalerror in forum C++ Programming
    Replies: 13
    Last Post: 12-08-2003, 12:49 PM