1

I have this function to check if a file exists:

#include <stdio.h>

int main(int argc, char **argv) {
    int textFileExists(const char *filename){
        FILE *fp=   fopen(filename,'r');
        if(fp==NULL){
            printf("%s %s.\n","There was an error opening ", filename);
            return -1;
        }
        return 1;
    }

    textFileExists("text.txt");
    return 0;
}

But when I compile this code, I get this warning.

warning: passing argument 2 of ‘fopen’ makes pointer from integer without a cast
  FILE *fp= fopen(filename,'r');

Running this code gives me a segmentation fault.

What is going on here?

Username
  • 3,463
  • 11
  • 68
  • 111
  • 8
    `'r'` ===> `"r"` – WhozCraig Dec 31 '16 at 10:06
  • 5
    The second argument of `fopen` should be a string (`char*`) rather than a character (`char`). Change `'r'` to `"r"`. `'r'` is a character while `"r"` is a string literal. – Spikatrix Dec 31 '16 at 10:06
  • See: [Single quotes vs. double quotes in C or C++](http://stackoverflow.com/questions/3683602/single-quotes-vs-double-quotes-in-c-or-c). – P.P Dec 31 '16 at 10:38

3 Answers3

5

The usage of literal 'r' as fopen parameter is equivalent to using the following:

const char* filename = ...;
char mode = 'r';
fopen(filename, mode);

The 'r' is therefore assumed to be of type char and has the value of 0x72 (ASCII). This is then passed to the char* mode, converting the 0x72 to a memory address (pointer) to be read from to obtain the characters of mode string by fopen. Accessing the memory location at 0x72 fails as that location is most probably not available to your application.

For a char* literal, you need to use "r" as in

const char* filename = ...;
const char* mode = "r";
fopen(filename, mode);
Zdeněk Jelínek
  • 2,611
  • 1
  • 17
  • 23
5

'r' is a single character which, when passed to a function, has type int.

The function fopen() expects the second argument to be a (const) pointer to char (i.e. a const char *). Hence the warning message. A conversion from an int to a pointer is permitted in C, for various reasons, but compilers often treat such conversions as suspicious, and warn you.

The function expects the passed pointer to be a string, which means it assumes the value points to the first character of an array of char. It doesn't (since you have passed an int) so exhibits undefined behaviour. One symptom of undefined behaviour is a segmentation violation (caused by your operating system detecting your program accessing memory it shouldn't, and sending a SIGSEGV signal to your program).

To fix the problem pass "r" instead of 'r'. Note the double quotes rather than single quotes. "r" is a string literal, which is represented using two characters, 'r' and '\0', which is what fopen() expects. Doing this will eliminate both the warning and the error when running the program.

Get in the habit of checking warning messages from your compiler BEFORE running the program. Warnings often indicate a potential problem - in this case, the cause of the warning is also the cause of the abnormal program exit.

Peter
  • 35,646
  • 4
  • 32
  • 74
-2

In C there's a difference between 'r' and "r". Check your C book.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • Not the downvoter, but answer should specify where the problem lies, why is it a problem, and what's the solution. – machine_1 Dec 31 '16 at 10:17
  • 1
    @AlexeyFrunze Also not a downvoter, but I think this answer is so terse it’s unlikely to help someone who’s so new they need to ask this question. Especially since their grasp on pointers, implicit casts, and cstrings is probably rather hazy. They might fix the error, but not know why the error is fixed. – Patrick M Feb 06 '18 at 09:08