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.
CodePudding user response:
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.