1

I was writing a program in C which takes user input and when I enter Ctrl+d, it print thousands of (null)'s as output. What is happening? Is it some sort of memory leak? Here's the code:

while (1) {
    char *buffer = malloc(BUFFER_SIZE);
    fgets(buffer, BUFFER_SIZE, stdin);
    printf("%s", buffer);
  }

BUFFER_SIZE is set to 256.

human
  • 73
  • 4

1 Answers1

3

Yes, this is probably due to the memory leak in the code. You allocate some memory at each round through the loop, but you never free it. So eventually you'll run out of memory.

At first malloc returns a new 256-byte memory block each time. fgets reads from standard input. Since the user pressed Ctrl+D, the standard input is empty, so fgets returns buffer and doesn't write anything. (fgets is not guaranteed to write an empty string, i.e. to write a null byte at buffer[0], if it hasn't read anything.) Then printf prints whatever the content of buffer is1, which could by any random garbage and could possibly crash since the memory is uninitialized and there's no guarantee that there's a null byte to end the string in the buffer. Plausibly, if this is the only thing your program does, the operating system provides zero-filled memory to your program, and so the very first time malloc uses a particular chunk of memory, it's still filled with zeroes, so buffer is all-bytes-zero which is an empty string, so the printf calls have no visible effect.

Eventually malloc runs out of memory, so it returns NULL. Calling fgets with a null buffer would normally result in a segmentation fault1. However, in the special case where fgets sees empty input, it likely doesn't try to access the buffer at all, so it just returns NULL. Then printf("%s", NULL), on your platform1, prints (null).

The solution is to check the return value of malloc and fgets, and to free the memory that you allocated. (And of course you could allocate a buffer once and reuse it instead of allocating a new buffer on each iteration, but I'm assuming this is a learning exercise or a simplification of a more complex problem.)

while (1) {
    char *buffer = malloc(BUFFER_SIZE);
    if (buffer == NULL) {
        printf(stderr, "Out of memory\n");
        exit(EXIT_FAILURE);
    }
    if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) break;
    printf("%s", buffer);
    free(buffer);
}

1 In general, in C, this has undefined behavior. I'm describing the likely behavior on a platform where Ctrl+D is the standard key binding to indicate the end of user input.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • FYI, [Control-D does not indicate the end of user input; it merely transmits the currently queued characters to the foreground process](https://stackoverflow.com/a/21365313/298225). When the transmission contains zero characters, other software interprets that as EOF. E.g., if you type several characters and then press control-D, the characters are processed normally and no EOF is reported. If you press control-D at the beginning of a line, when no characters are pending, then an EOF is reported by that other software. Or if you press control-D twice, the second one causes an EOF. – Eric Postpischil Dec 26 '21 at 11:27
  • @EricPostpischil Yes, but in the context of this question, Ctrl+D at the beginning of a line indicating the end of input is the only relevant aspect. – Gilles 'SO- stop being evil' Dec 26 '21 at 12:58
  • Planting false ideas in people’s heads causes more work overall, because it is harder to correct the wrong idea and teach the correct idea than to teach them correctly in the first place. – Eric Postpischil Dec 26 '21 at 13:29