tags:

views:

162

answers:

3

Why is the following code giving segmentation fault?

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

int main()
{
    FILE *file;
    file = fopen("text","r");
    if (file == NULL) printf("Error READING FILE");
    if (ferror(file)) printf("error reading file");    //line 9
    return 0;
}

Doing backtrace in gdb gives:-

> #0  0x00007ffff7ad9d30 in ferror () from /lib/libc.so.6
> #1  0x00000000004005fa in main () at test.c:9
+6  A: 

file is NULL. You're not seeing the first printf because the program crashes before stdout is flushed.

ergosys
+1 referencing i/o buffer flushing.
pilcrow
When is the stdout flushed actually? I mean normally..
shadyabhi
If i add:- fflush(stdout) before line 9, i get the output.But, just for information I want to know, when is stdout flushed in programs?
shadyabhi
When you print a newline character*, or when the buffer is full, or when the program ends. (*): By default, `stdout` is line-buffered on most systems. You should also print error messages on `stderr`: usually it's unbuffered (but more importantly, error messages should go to `stderr`, not `stdout`).
Alok
@AlokThanx for the reply.. Exactly what I asked.
shadyabhi
+2  A: 

If file is equal to NULL on line 9, then the Seg Fault will occur during the ferror() call.

If there the file is NULL (as determined on line 8), then you shouldn't perform line 9.

Your line 8 code should be changed as such:

if (file == NULL)
{
    printf("Error READING FILE");
    return 1;
}

NB: i could be very wrong about this, it's been a while since i've done C/C++

Alastair Pitts
Or change line 9 to `else if ...`.
KennyTM
also another possibility
Alastair Pitts
I thought ferror() can be used for checking if the file could be opened successfully. But, its used after the file is opened and checking further error, if any..Am i right?
shadyabhi
ferror() checks the stream to see if the error indicator (on the stream) has been set. Passing a NULL stream will produce the seg fault. http://www.cplusplus.com/reference/clibrary/cstdio/ferror/
Alastair Pitts
Shadyabhi: If `fopen` returns NULL, then the file isn't open; you're passing `NULL` in to `ferror`, which is invalid. You don't have an open file to pass in; that's what `NULL` means, that it couldn't give you a file pointer. `ferror` is for getting errors related to reading and writing the file, once it has actually been opened and you have the file to work with.
Brian Campbell
If the file couldn't be opened successfully, you don't have a valid `FILE *` value. So, what will you call `ferror()` on?
Alok
@BrianThanx.. short and accurate:)
shadyabhi
Slight complaint here, but why wouldn't you accept my answer? It was correct, timely and accurate, yet I have 1 vote. *sigh*
Alastair Pitts
@Alastair I think the reason is that you didn't explain quite well enough why you need to check for `NULL` instead of using `ferror` to check for a file error. What you said is correct, and was timely, but it sounds like Shadyabhi is a real beginner here, and so needed things explained in a bit more detail (which is why I tried to explain in more detail in the comment on your answer, and then decided to expand that into a full answer). It's helpful, when explaining to beginners, to be as explicit as possible, and point out all of the alternatives to them.
Brian Campbell
@Brian Thank you for that response Brian. I appreciate the explanation as I certainly want to get better and helping. Thanks!
Alastair Pitts
+2  A: 

If fopen returns NULL, then the file isn't open; you're passing NULL in to ferror, which is invalid. You don't have an open file to pass in; that's what NULL means, that it couldn't give you a file pointer. ferror is for getting errors related to reading and writing the file, once it has actually been opened and you have the file to work with.

If fopen fails, and you want to get more information about why, you need to check the errno global variable, defined in errno.h.

#include <errno.h>

// ...snip...

if (file == NULL) 
  printf("Error READING FILE: %s\n", strerror(errno));

This example shows how to fetch a string describing the error; you could also compare the value in errno against one of the possible values it could have, and do something different depending on what the error is. See the fopen man page, or the POSIX spec, for a list of possible errors to compare against. Here's how you could check against various possible errors:

if (file == NULL) {
  int error = errno;  // copy it so other calls like printf don't modify it
  printf("Error READING FILE: %s\n", strerror(error));
  switch (error) {
  case EACCESS:
    // access was denied
    break;
  case ENOENT:
    // the file or one of its ancestors doesn't exist
    break;
    // etc...
  }
}

(this is an expansion of something I originally wrote in a comment on another answer)

Brian Campbell
+1, nice answer. Note that the C standard doesn't require `fopen` to set `errno` (POSIX does). You should set `errno` to 0 before calling `fopen()`, "just in case". Also, `errno` may or may not be a global variable: it is a modifiable lvalue, which may result from a function call if the library implements it like that.
Alok
Thanks for the clarification, Alok. I thought of mentioning that `errno` is not actually a global, but I think that would be more confusing than enlightening. I was not aware that C doesn't require `fopen` to set `errno`; most C code I write is on Linux, Mac OS X, or the BSDs, so I tend to pay more attention to the man pages, and POSIX, than the C standard. It's good to know that that assumption isn't necessarily portable.
Brian Campbell
Yeah - I see it as a quality of implementation issue too - so it would be hard to find a good library that doesn't set `errno`, particularly because POSIX requires it.
Alok