Why We Should Never Use gets()... And Why To Use fgets() Instead | C Programming Tutorial

Sdílet
Vložit
  • čas přidán 7. 05. 2022
  • Why we should never use the gets() function in C, including an explanation as to how it is unsafe due to buffer overflow, and an explanation as to why we should use fgets instead. Source code: github.com/portfoliocourses/c... Check out www.portfoliocourses.com to build a portfolio that will impress employers!

Komentáře • 43

  • @emirhandemir3872
    @emirhandemir3872 Před 2 lety +17

    Great explanation

  • @sai_eshu7159
    @sai_eshu7159 Před 10 měsíci +1

    great explanation....

  • @gourabmaityeducation
    @gourabmaityeducation Před rokem

    Thank you so much 😊😊

  • @sabitnirob983
    @sabitnirob983 Před rokem +1

    Thanks for this class.. ❤️👍

  • @AhmadAlMutawa_abunoor
    @AhmadAlMutawa_abunoor Před rokem +2

    This video is very informative. I wish you would include a way to flush the stdin before reading any left over from the previous attempt. That would have been wonderful.

    • @PortfolioCourses
      @PortfolioCourses  Před rokem +1

      Hi Ahmad, this video covers how to clear the standard input buffer: czcams.com/video/N7-MueK2CX8/video.html. :-)

  • @elmarc4289
    @elmarc4289 Před 10 měsíci

    Muchas gracias amigo, de verdad que me has ayudado mucho. Saludos desde México

  • @Brock-Landers
    @Brock-Landers Před 2 lety +6

    My 2 pennies, you can just discard the overflow up to newline so your next call will be clean.
    For input from stdin:
    if(strchr(buffer, '
    ') == NULL)
    while((fgetc(stdin) != '
    ');
    For input from a file also check for end of file or you will go into an infinite loop :
    if(strchr(buffer, '
    ') == NULL)
    {
    char discard;
    while((discard = fgetc(fp) != '
    ' && discard != EOF);
    }
    Then strip the newline character, only if one exists:
    buffer[strcspn(buffer, "
    ")] = '\0';
    Now buffer contains exactly what one would expect.

    • @PortfolioCourses
      @PortfolioCourses  Před 2 lety +2

      Thanks for sharing this! 🙂

    • @edgarherrera8587
      @edgarherrera8587 Před rokem +1

      Hi Brock. Do you have a code (i.e. at GitHub) where I can see your solution implemented? I have been looking for a solution since days ago. But this might bring me some light. Thanks

    • @Brock-Landers
      @Brock-Landers Před rokem

      @@edgarherrera8587 Here's a video I made on the subject that uses this exact code:
      czcams.com/video/ITR-Acel7tg/video.html
      There is a link in the description to the source code on my github for that channel.

    • @cervelex
      @cervelex Před rokem

      @@Brock-Landers nice

  • @bettyswunghole3310
    @bettyswunghole3310 Před 25 dny

    Thank you! This is a very good explanation!
    Can you just clarify one point, though? if I use "fgets(buffer,5,stdin)" and then display the buffer contents, it shows four characters, but it's *_really_* showing 5 because the last character is the \0 Null character?

  • @mateuscruz3009
    @mateuscruz3009 Před 7 měsíci +1

    When you use the second fgets in the end of video, shouldn't have another space for data input in terminal? One for fgets buffer and other for fgets next? You only typed and entered one time, one data, why it happened?

  • @vicsteiner
    @vicsteiner Před 3 dny

    What if I want to discard any extra chars in the stdin and actually prompt the user again? How do we clean the stdin? Or how do I know how many times I have to call fgets till the stdin is empty and ready to read new input data from the user?

  • @ritapiu319
    @ritapiu319 Před 8 měsíci

    謝謝!

  • @vicsteiner
    @vicsteiner Před 4 dny

    Using gcc in Ubuntu when I tried passing the string with more than 5 chars like in the example it does print the abcdef string to the stdout but also the message:
    *** stack smashing detected ***: terminated
    Aborted (core dumped)
    And the program return value was 134.

  • @py4311
    @py4311 Před 4 měsíci

    Afaik, most of time, we would get more spaces than how much we have applied due to memory alignment for performance. but why 16 bytes[a-p] when you applied for 5, I think it would be 8.

  • @Stekaren
    @Stekaren Před 6 měsíci

    i tried something like this
    int main(){
    char a[] = "hello"; // here im initializing my char array with a string without declaring how many characters i want in the array, i know that the compiler will put 6 characters away so that the char array a may store 5 characters + null characters = 6 characters.
    printf("enter string:
    "); //
    fgets(a, 21, stdin); /* here i use fgets, and i have 21 characters i want to write, which are "you are most welcome" 20 characters + white space character + the null character at the end that indicates end of the string = 21 characters total */
    printf("string: %s", a); // will print "you are most welcome"

    return 0;
    }
    i got no warning writing this. So still the question remains, do i need to dynamically allocate memory like you did sir or is this legal in C?

  • @Stekaren
    @Stekaren Před 6 měsíci

    hello sir im trying to learn c on my own. so why i came here from neso academy was because of this: video was about difference between scanf and gets, in order to print out the white space character. what i understood was when the scanf() function sees a white space character it does not print anything else past that, so if i write "you are most welcome" it will only print out "you" and ignore the rest. with gets() the problem was as you are also mentioning, it can overwrite in the memory and use memory that is not allocated for the char array.
    so in order to get the white space character and print out the complete sentence "you are most welcome" i can use fgets() function instead of gets(). my question is sir, do i need to dynamically allocate memory everytime with the malloc function or can i just go ahead and use fgets? im new to this and i appreciate any help you can give me

    • @swati9841
      @swati9841 Před 2 měsíci

      we can use the fgets function only if we know the size of the string so instead of using fgets its better to use selective scanf syntax:-scanf("%[^
      ]", str); in this syntax ^ indicates starting of string and
      indicates the end of the line and str is string name

  • @josso8584
    @josso8584 Před rokem

    Soy de Mexico y tuve que ver tu video en subtitulos pero tienes mi like jeje

    • @PortfolioCourses
      @PortfolioCourses  Před rokem

      That's awesome! :-) I hope one day CZcams does AI translation on the fly. Hopefully this translation makes sense.

  • @luka_9196
    @luka_9196 Před 8 měsíci

    Hi sorry I’m new to programming but if i use a second fgets to prevent overflow and the user doesn’t write a string longer than the max characters I chose the fgets want an input how do I resolve this issue thank you for the help.

    • @henry_tsai
      @henry_tsai Před 4 měsíci

      The second fgets isn't needed if you just want to avoid overflow from the first input, fgets already limits how many characters it's going to read.
      However, I assume you want to read user input for the second time and the remaining characters in the stdin stream may wrongly be read in. In which case, a solution I come up with is to: 1.check if the user's first input is longer then first input buffer and has thus remaining data in stdin stream 2. if so, clear stdin stream 3. read user input.
      For step1, since fgets will stop reading if a
      is encountered, you can check if the first input string contains a
      , ex: with buffer size 5 and user inputs "abc
      ", then you knows there isn't any excess characters in stdin, then you can use a "if" to skip step2 and use another fgets() to read second input. if first input doesn't contain
      , then it means user input more character then the buffer size, ex: buffer size 5 but user inputs "abcdef
      ", then in buffer will be "abcd\0", and "ef
      " will remain in stdin, then you can use:
      char c[2];
      while(c[0] != '
      '){
      fgets(c, 2, stdin);
      }
      which should clear out any remain characters in stdin, then you can continue to step3 and use another fgets() to read.

    • @haroldcruz8550
      @haroldcruz8550 Před 2 měsíci

      That's actually considered the best practice specially for newbies

  • @fadyasaad1105
    @fadyasaad1105 Před rokem +1

    Is there a way to clear stdin before fgets again??

    • @PortfolioCourses
      @PortfolioCourses  Před rokem

      Great question Fady! :-) This video might help you out: czcams.com/video/0UJX96_ZpVE/video.html. These answers might help too: stackoverflow.com/q/7898215.

  • @Architector120
    @Architector120 Před 2 lety +2

    Can you explain how to make non-blocking delay or events in while loop in C? i came up with this approach... it works but CPU 100% loaded... hope you get the idea...
    #include
    #include
    void my_event(clock_t *cnt, int time_delay)
    {
    if(clock() - *cnt >= time_delay)
    {
    *cnt = clock();
    printf("%ld
    ", clock());
    }
    }
    int main()
    {
    clock_t tim = 0;
    while(1)
    {
    my_event(&tim, 1000);
    if(tim == 10000) break;
    }
    return 0;
    }

    • @PortfolioCourses
      @PortfolioCourses  Před 2 lety +2

      I'm not too sure, I think it depends on what you mean by non-blocking delay and what you're trying to do. Is the goal to delay executing some code by some amount of time, but to allow other code to execute in the meantime? If that's the case, it sounds like a situation best solved using threads. These folks have an interesting article on the idea: learn.digilentinc.com/Documents/407. And others seem to suggest using threads to solve the problem: stackoverflow.com/questions/7771142/non-blocking-sleep-timer-in-c. Maybe I can make a video about this, though I think I'd likely solve the problem using threads. :-)

    • @Architector120
      @Architector120 Před 2 lety

      I already thought about using threads... But here's the catch... CPU single threaded...

    • @PortfolioCourses
      @PortfolioCourses  Před 2 lety +1

      @@Architector120 Interesting, that makes things more challenging. 🙂
      I think if the delay is for some amount of time, the general idea would be something like this:
      time1 = the current time
      do {
      // do work that can be done now
      time2 = the current time
      diff = difference between time2 and time1
      } while (diff < desired);
      // do work that could only be done after diff amount of time has passed
      Just out of curiosity, what is the work that needs to be done in-between waiting some amount of time? Is it something that can be put into a function and called frequently? Is the delay for some fixed amount of time like 10 seconds, or is it until some event has occurred? Maybe I can make a video on this idea some day.

  • @Awwe12675
    @Awwe12675 Před rokem

    He bro stdin Is macro
    stdin is 1 stdout is 0
    Like that
    #define stdin 1
    #define stdout 0
    stdin only to tell for programmer hey we need use input with fgets function

    • @PortfolioCourses
      @PortfolioCourses  Před rokem +3

      Yes, the actual term "stdin" is a macro in C. If anyone wants to learn more about that you can read up on it here: man7.org/linux/man-pages/man3/stdin.3.html. The standard input stream is a bigger concept than just a macro that sets to 1 though. It's not even necessarily going to be user input, it could be a file if it is re-directed when the programmer is run. Maybe one day I can make a video on the standard input streams and re-directing them. :-)

  • @bolvarsdad3825
    @bolvarsdad3825 Před rokem +3

    Here's the function I always use to take input, which I afterwards use other accompanying functions to convert the string value to what I need.
    #include
    size_t get_line(char *buffer, size_t bufsz)
    {
    size_t buflen = 0;
    int ch;
    while ((ch = getchar()) != EOF && ch != '
    ')
    if (buflen < bufsz)
    buffer[buflen++] = ch;
    return buflen;
    }
    int main(int argc, char **argv)
    {
    char buffer[5];
    size_t nread = get_line(buffer, 5);
    // I don't need to null terminate the buffer because of this printf format
    // If you were using puts instead of printf here, you should null terminate it by writing:
    // buffer[nread] = '\0';
    // But since we're using printf in this case that can be ignored.
    printf("%.*s
    ", (int)nread, buffer);
    return 0;
    }
    Input: 12345678
    Output: 12345

    • @PortfolioCourses
      @PortfolioCourses  Před rokem

      Thank you for sharing this! :-)

    • @IonizedComa
      @IonizedComa Před rokem

      I always just use scanf("%[^
      ]s", stringName);

    • @PortfolioCourses
      @PortfolioCourses  Před rokem

      @@IonizedComa that works! 🙂

    • @Queue_27
      @Queue_27 Před rokem

      to me, getchar is the only one that make sense out of everything. i always feel safe considering every char even \0 and
      .