I'm writing a simple C program that opens a file, and reads each line into an array, where LISTS is the maximum number of lines in the file that I wish to read.
However, when MASTER_LIST is less than LISTS lines long, I get a segmentation fault on printf() the second time round, but not the first (I've commented to show where).
I'm a little confused by this behaviour, and I'm wondering what causes it and what I can do to circumvent it. Ideally I would stop reading when fgets finds the end of the file.
#define MASTER_LIST "master_list.txt"
#define LINE 64
#define LISTS 32
char **lists = malloc(LISTS * sizeof(char *));
int i;
for (i = 0; i < LISTS; i++) {
lists[i] = malloc(LINE * sizeof(char));
}
/*Open the file for reading.*/
FILE *fp = fopen(MASTER_LIST, "r");
if (fp != NULL) {
/*Each line of the file, up to LISTS is read into lists.*/
for (i = 0; i < LISTS; i++){
lists[i] = fgets(lists[i], LINE, fp);
/*NO SEGFAULT HERE*/ printf("Line Read: %s\n", lists[i]);
}
}
/*print out each line*/
for(i = 0; i < LISTS; i++){
printf("Are we segfaulting yet? %d\n", i);
/*HERE I GET A SEGFAULT*/ printf("%s\n", lists[i]);
printf("How about now? %d\n", i);
}
2 Answers. The main issue that causes a segmentation fault is line 22 - printf ("Name: %s \n", name); This is because you are printing a string, while name is 1 character. If I enter my name, only the first letter entered is actually written to the name variable.
The segmentation error is one of the runtime error, that is caused because of the memory access violation, like accessing invalid array index, pointing some restricted address etc. In this article, we will see how to detect this type of error using the GDB tool.
Overview. A segmentation fault (aka segfault) is a common condition that causes programs to crash; they are often associated with a file named core . Segfaults are caused by a program trying to read or write an illegal memory location.
A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).
fgets
returns NULL
if it fails to read any characters, which would happen if your file contains less than LISTS
lines. Attempting to printf
a NULL pointer is undefined behaviour.
This is a good time to remind ourselves that undefined behaviour really is undefined. It looks like the printf
should crash the first time around. But, the C spec says nothing about what should happen, so your printf
just prints (null)
(many Linux libcs do this, for example).
Why does the second printf
crash, then? It's because you used the pattern
printf("%s\n", lists[i]);
Many compilers will optimize this to
puts(lists[i]);
and on your system, puts
does not check for a NULL pointer and so it segfaults.
Moral of the story? Don't ever rely on undefined behaviour, or even expect consistent results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With