-1

As I was practicing the use of fgets() to read string from input, I found myself copying the same piece of code over and over, so I created a function to call every time I need to do it. Here is a simple example of how it works:

#include <stdio.h>
#include <string.h>

void GetLine(char str[]) {
    // This is the function, I added a printf() to better show what's happening
    printf("Maximum size of the string in GetLine: %i\n", sizeof(str));
    fgets(str, sizeof(str), stdin);

    // This is for clearing the newline character
    // either from the recently received string or from the input buffer
    if (str[strlen(str)-1] == '\n')
        str[strlen(str)-1] = '\0';
    else {
        char DISCARD;
        while((DISCARD = getchar())!='\n' && DISCARD != EOF);
    }
}

int main() {
    char MyString[51];

    printf("Maximum size of the string in main: %i\n", sizeof(MyString));
    GetLine(MyString);

    printf("Contents of the string: >%s<\n", MyString);

    return 0;
}

Here's the output:

Maximum size of the string in main: 51
Maximum size of the string in GetLine: 4
My name is Pedro
Contents of the string: >My <

Notice how str[] only have 4 spaces, instead of being the size of the string passed to it.

The workaround for this is pretty easy: make GetLine() also receive an integer that holds the size of the string, so it can read the correct number of characters without depending of sizeof(str).

However I'd really like to know both why this happens(the 4 space thing) and if I can fix this method somehow(make char str[] the same size as the string passed as argument).

Thanks in advance.

1 Answers1

0

fgets(str, sizeof(str), stdin); is incorrect in function GetLine as the array is passed as a pointer to its first element. Hence str in GetLine() is a pointer, so sizeof(str) is not the size of the destination array, but merely the size of a pointer, 4 bytes on your system.

You should instead pass the size of the array to GetLine() and use that as the size argument to fgets().

There are other problems in your code:

  • you should test the return value of fgets() to properly detect end of file.

  • you should make DISCARD an int so it can store EOF properly.

  • you discard the newline from the end of the buffer with an inefficient and slightly incorrect method: there is a remote possibility that strlen(str) be 0. You could use this one liner:

    str[strcspn(str, "\n")] = '\0';  // discard the newline if present.
    

    Or you could use strchr().

Here is a corrected version:

#include <stdio.h>
#include <string.h>

char *GetLine(char str[], int size) {
    if (fgets(str, size, stdin)) {
        char *p = strchr(str, '\n');
        if (p != NULL) {
            // This is for clearing the newline character
            *p = '\0';
        } else {
            int c;
            while ((c = getchar()) != EOF && c != '\n')
                continue;
        }
        return str;
    }
    return NULL;
}

int main(void) {
    char MyString[51];

    printf("Maximum size of the string in main: %i\n", (int)sizeof(MyString) - 1);
    if (GetLine(MyString, sizeof(MyString)))
        printf("Contents of the string: >%s<\n", MyString);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • or better - have getline allocate a buffer and return it – pm100 Oct 31 '17 at 22:23
  • by the way, "Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.", so `strchr()` could be remove just use the return value of `fgets()`. – Stargateur Oct 31 '17 at 22:43
  • @Stargateur: the `GetLine()` function reads a line into the destination array, and strips the newline. Long lines are truncated and the remaining characters are discarded, unlike `fgets()` which breaks long lines and returns the next fragment at the following call. – chqrlie Oct 31 '17 at 22:58
  • @chqrlie I didn't well understand what you said but whatever never mind, I forget that `fgets()` don't return the number of characters read. – Stargateur Oct 31 '17 at 23:07