con-f-use
con-f-use

Reputation: 4028

Why does it matter where fopen is used?

I could use some help understanding something puzzling to me. It concerns the position of of fopen() to read out a file.

Following code (C compiled with gcc 4.5.2):

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

void try_fopen(FILE* f_handle, const char* f_name, const char* mode) {
    f_handle = fopen(f_name, mode);
    if( f_handle == NULL ) {
        fprintf(stderr, "Error: Unable to open '%s'.", f_name);
        exit(EXIT_FAILURE);
    }
}

int cnt_ones(FILE* pFile) {
    int c;
    int n = 0;

    do {
      c = fgetc (pFile);
      if (c == '1') n++;
    } while (c != EOF);

    return n;
}

Why is it that putting the fopen in a function gives a Segfault:

int main (int argc, char** argv) {
    FILE * pFile;
    try_fopen(pFile, argv[1], "r"); // Gives a Segfault

    printf ("The file contains %d ones.\n", cnt_ones(pFile) );
    fclose (pFile);

    return 0;
}

While putting it into the main (along with the if doesn't):

int main (int argc, char** argv) {
    FILE * pFile;
    pFile = fopen(argv[1], "r"); // While this doesn't give a Segfault
    if( pFile == NULL ) {
        fprintf(stderr, "Error: Unable to open '%s'.", argv[1]);
        exit(EXIT_FAILURE);
    }

    printf ("The file contains %d sign characters.\n", cnt_ones(pFile) );
    fclose (pFile);

    return 0;
}

Upvotes: 0

Views: 703

Answers (4)

Jay
Jay

Reputation: 24895

The reason is simple, when you pass FILE* to function, it's updation will be lost as it is passed by Value. Try passing FILE ** to the function and it will work. Refer to Binyamin Sharet's answer above for the code snippet

The reason for this can be understood by reading this link

Or

You can change the function try_open to return FILE * as the return value.

FILE *try_fopen(const char* f_name, const char* mode) 
{ 
   FILE *f_handle = NULL;    
  *f_handle = fopen(f_name, mode);     
   if( *f_handle == NULL ) 
   {         
     fprintf(stderr, "Error: Unable to open '%s'.", f_name);         
     exit(0);     
   } 
} 

  //In the main function.
  FILE *pFile = try_fopen(argv[1], "r");

Upvotes: 0

Aftnix
Aftnix

Reputation: 4589

You can either do :

File * fp;
try_fopen( &fp,.....); /* void try_fopen (FILE ** fp,....) */

or the following :

File * fp = try_fopen("file name"); /* FILE * try_fopen (const char * file_name,...) */

Upvotes: 1

Naveen
Naveen

Reputation: 73443

Because the pointer pFile is passed by value to the function try_open. The value modified inside the function is not available in the main. To solve this, you need to pass the address of the pointer to the function, so try_open would accept FILE** and assign the result of fopen to *pFile. While calling this function you should pass the address of pFile using &pFile.

Upvotes: 1

MByD
MByD

Reputation: 137322

C is pass by value, not by reference, so you need to pass the pointer to pFile, otherwise you don't change it outside of the function scope:

void try_fopen(FILE** f_handle, const char* f_name, const char* mode) {
    *f_handle = fopen(f_name, mode);
    if( *f_handle == NULL ) {
        fprintf(stderr, "Error: Unable to open '%s'.", f_name);
        exit(EXIT_FAILURE);
    }
}

// ...
try_fopen(&pFile, argv[1], "r");

Upvotes: 4

Related Questions