Home > Mobile >  Why when using fgets() do we need to remove the string -1 when we are declaring it?
Why when using fgets() do we need to remove the string -1 when we are declaring it?

Time:05-31

Why when we are declaring the function fgets() we need to put -1 string from the original char? like this:

#include <stdlib.h>
#include <stdio.h>

int main ()
{
    char string[15]; 

    fgets(string,14,stdin); // < the original variable has 15 strings, but in fgets() we need to set 14, why?
    printf("%s\n", string);

    return 0;
    getchar();
}

I'm a beginner in C, so i'm having this doubt in my mind

CodePudding user response:

You don't need to. fgets takes three arguments.

  • A C string buffer to read into.
  • A count of characters.
  • A file stream to read from.

It reads at most count - 1 characters into the buffer, thus leaving room for the null terminator every C string needs.

As a side note: your call to getchar falls after the return and is thus completely pointless as control flow will never reach it.

CodePudding user response:

There is no need to subtract 1 from the array length for the size argument to fgets().

The second argument tells fgets the length of the array pointed to by the first argument so fgets() only writes inside the buffer boundaries. fgets() will read at most one less byte from the stream than the length of the destination array and write a null terminator so make the array a C string.

Since sizeof(char) is 1 by definition, it is idiomatic in C to pass the size of the array as sizeof(string), but only do this if string is an actual array, not a pointer.

Unless the stream pointer it in error or at end of file, the string read by fgets() will be null terminated. You should test the return value of fgets() to avoid reading the array in case of failure to read a string from the stream.

Here is a modified version:

#include <stdio.h>

int main() {
    char string[15]; 

    while (fgets(string, sizeof string, stdin)) {
        printf(">>%s<<\n", string);
    }
    printf("Bye\n");
    return 0;
}

Now let's run the program and do some testing:

  • If you type a short string Hello!followed by the Enter key, you will see 2 lines of output:

    >>Hello!
    <<
    

    fgets() read the string, including the trailing newline into the string array and printf outputs it, preceded by >> and followed by << and a newline, producing 2 lines in one call.

  • If you type a longer string I am testing this function relentlessly followed by the Enter key, fgets() will read at most 14 bytes at a time and only the last chunk will have the trailing newline:

    >>I am testing t<<
    >>his function r<<
    >>elentlessly
    <<
    
  • Finally, if the input does not have a trailing newline, eg: Yes! followed by Ctrl-DCtrl-D, the array string will not have a newline at the end either and the next call to fgets() will return NULL:

    >>Yes!<<
    Bye!
    

CodePudding user response:

Why when we are declaring the function fgets() we need to put -1 string from the original char?

I believe you are talking about the use of

    buffer[strlen(buffer) - 1] = 0;

after using fgets() to fill in buffer, with the purpose of removing* the expected \n from the string. Not when "declaring the function" but after the call.

Well, this is wrong.

Example

#include <ctype.h>
#include <stdio.h>
int main(void)
{
    char      buf[5] = {0};
    const int n      = sizeof(buf);
    printf("Enter up to %d bytes: ", n);
    char* p = fgets(buf, n, stdin);
    while ((p != NULL) && (*p != '\n'))
    {
        printf("Buffer: ");
        for (int i = 0; i < n; i  = 1)
            if (isprint((int)*(buf   i)))
                printf("%c ", *(buf   i));
            else
                printf("0x%0X ", *(buf   i));
        printf("\n\nEnter up to %d bytes: ", n);
        p = fgets(buf, n, stdin);
    };  // while()
    return 0;
}

This program reads a string from stdin using fgets, buffer size is set to 5. After the read the 5 bytes are shown. When not printable they are displayed in HEX. 0x0A is the code for \n

Running

Enter up to 5 bytes: 12
Buffer: 1 2 0xA 0x0 0x0

Enter up to 5 bytes:
SO>

And there is a newline after the 12, at buf[2]

but

Enter up to 5 bytes: 1234
Buffer: 1 2 3 4 0x0

Enter up to 5 bytes:
SO>

Here we have no \n since all 4 bytes were used and the last holds the mandatory 0, the terminating NULL for the string.

And the '\n' are left for the next read. The program finishes since an ENTER at the beginning of the string ends the loop.

Same if the user enters all 5 proposed bytes, as in

Enter up to 5 bytes: abcde
Buffer: a b c d 0x0

Enter up to 5 bytes: Buffer: e 0xA 0x0 d 0x0

Enter up to 5 bytes:

And the second call reads "5\n". This time the program does not end, since the '\n' is on the second byte.

So...

fgets() will keep the '\n' at the end of the string as long as there is space for it. If all bytes are taken the remaining data is left on the input buffer.

fgets returns a pointer

As you see in the manual, fgets() returns a pointer to the buffer or NULL in case of error or end of file. In case of error errno is set.

If fgets reads nothing the buffer is not touched at all, so every day many many sudent's programs hangs because the program does not check the returned pointer and keeps using the same data over and over, after error or EOF.

  • Related