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

int main() {
    int length;
    char **lines, buffer[80];

    printf("How many lines do you want to enter?.\n");
    scanf("%d", &length);
    getchar();
    lines = (char**)malloc(length * sizeof(char*));
    for (i = 0; i < length; ++i) { //Scan user's lines
        gets(buffer);
        lines[i] = (char*)malloc(strlen(buffer) * sizeof(char) + 1);
        if (!lines[i]) { //Check if allocation available
            printf("Error! Out of memory!");
            return endProgram;
        }
        strcpy(lines[i], buffer);
    }
    return 0;
}

I'd like to know why does the gets() function giving me an error about assuming extern returning int, I'm just trying to scan a string.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Morta1
  • 609
  • 7
  • 20
  • [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Dec 29 '15 at 20:01
  • 1
    Never use `gets()`, try using `fgets()` instead. – Sourav Ghosh Dec 29 '15 at 20:02
  • Warning!! You have used `buffer` unitialized in this code... – Sourav Ghosh Dec 29 '15 at 20:03
  • As far as I know, `gets` has been removed since C11 in favor of `gets_s` or `fgets`. – Joachim Isaksson Dec 29 '15 at 20:05
  • 1
    Please include the exact error you're getting in your question – Kninnug Dec 29 '15 at 20:05
  • also note that your length calculation is wrong for the lines[i] malloc. Assume that you're running on a system where sizeof(char) = 2. You will allocate one byte to few. You should code it as: lines[i] = malloc((1 + strlen(buffer)) * sizeof(char)); – bruceg Dec 29 '15 at 20:13
  • @bruceg `sizeof(char)` is ***never*** 2. It is 1 by definition. – Weather Vane Dec 29 '15 at 20:51
  • 1
    @bruceg: look closer, the OP does allocate space for 1 extra byte. `sizeof(char)` is `1` by definition, this line should be simplified as `lines[i] = malloc(strlen(buffer) + 1);` or even simpler: `lines[i] = strdup(buffer);` – chqrlie Dec 29 '15 at 20:55
  • @WeatherVane good point – bruceg Dec 29 '15 at 21:10
  • Note that there is an extensive discussion of alternatives to `gets()` at [Why `gets()` is so dangerous that it should not be used](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used). – Jonathan Leffler Dec 29 '15 at 21:42

3 Answers3

8

The most likely reason is that gets() function has been deprecated for some time. It looks like it has been removed from <stdio.h> on your system.

Fortunately, this situation is easy to fix: replace the call with fgets(), like this:

fgets(buffer, sizeof(buffer), stdin);

Note: fgets is not a drop-in replacement for gets, because it keeps '\n' character at the end of line inside the string that it returns. This Q&A discusses the issue, and provides a solution.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    This answer is too short, `fgets` is not a drop in replacement for `gets`, one must strip the final `'\n'` to get similar semantics. – chqrlie Dec 29 '15 at 20:57
  • Detail: As a _replacement for existing code_, in addition to stripping the potential `'\n'`, `fgets()` also requires a buffer 1 longer than `gets()` for it to handle maximal input that `gets()` did so without UB. Then additional code could be needed to insure that extra byte unused, after stripping the potential `'\n'` as following code may not be equipped to handle a 1 extra long input. – chux - Reinstate Monica Dec 29 '15 at 21:35
2

The gets() function has been removed from the C Standard. It was never a good function to use because there is no way to tell gets how large the argument buffer is, making it very easy to cause buffer overflow or even malicious attacks if the input file is from an untrusted source. The reason your compiler complains about assuming extern returning int is that the prototype for gets is no longer present in your <stdio.h> system header.

Modify your code this way:

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

int main(void) {
    int length;
    char **lines, buffer[81];

    printf("How many lines do you want to enter?.\n");
    if (scanf("%d", &length) != 1)
        return 1;
    getchar();  // consuming the line feed typed by the user.
    lines = malloc(length * sizeof(char*));
    if (lines == NULL) {
        printf("Error! Out of memory!\n");
        return 2;
    }
    for (i = 0; i < length; i++) { //Scan user's lines
        if (!fgets(buffer, sizeof buffer, stdin)) {
            printf("Error! Premature end of file!\n");
            return 2;
        }
        buffer[strcspn(buffer, "\n")] = '\0'; // overwrite the final \n
        lines[i] = strdup(buffer);
        if (lines[i] == NULL) {
            printf("Error! Out of memory!\n");
            return 2;
        }
    }
    // perform other work on the buffer.
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

gets() was deprecated in C99 and dropped from standard C with C11.

OP received the warning "about assuming extern returning int" because it is not prototyped in the standard include files.

To replace gets() with something else can be done approximately with fgets() @dasblinkenlight

With new code, use fgets() and its quirks.


To roll your own my_gets(char *dest, size_t size), with a high degree of former gets() compatibility, code should:

  1. Take a size parameter that matches the size of the destination array.

  2. Upon reading too many characters for the destination array, my_gets() is free to perform any reasonable functionality as the former gets() would cause undefined behavior at this point. Recommend filling the array as best as possible, consuming characters until '\n' or EOF, and returning NULL to indicate error (possible setting errno).

  3. A simplistic use of fgets() is problematic as the size passed to fgets() is the space for characters, the '\n' and '\0', whereas the size passed to my_gets() really should be the space needed for the characters and '\0'. The '\n' being consumed and not saved.

A candidate function that meets these goals, using VLA, is at https://stackoverflow.com/a/34031881/2410359.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Interestingly, I don't believe `gets()` was deprecated formally in C99 (not in ISO/IEC 9899:1999); neither the definition of `gets()` in §7.19.7.7 nor the 'Future Directions' in ¶7.26 lists `gets()` as deprecated. It was deprecated in one of the technical corrigenda — TC3 from 2007, in fact, and not in TC1 or TC2. – Jonathan Leffler Dec 29 '15 at 21:49