Friday, April 8, 2011

What is the correct way to declare and use a FILE * pointer in C/C++?

What is the correct way to declare and use a FILE * pointer in C/C++? Should it be declared global or local? Can somebody show a good example?

From stackoverflow
  • It doesn't matter at all whether it's local or global. The scope of the file pointer has nothing to do with its use.

    It's usually a good idea to avoid global variables as much as possible.

    Here's a sample showing how to copy from input.txt to output.txt:

    #include <stdio.h>
    int main (void) {
        FILE *fin;
        FILE *fout;
        int c;
    
        fin = fopen ("input.txt", "r");
        if (fin != NULL) {
            fout = fopen ("output.txt", "w");
            if (fout != NULL) {
                c = fgetc (fin);
                while (c >= 0) {
                    fputc (c, fout);
                    c = fgetc (fin);
                }
                fclose (fout);
            } else {
                fprintf (stderr, "Cannot write to output.txt");
            }
            fclose (fin);
        } else {
            fprintf (stderr, "Cannot read from input.txt");
        }
        return 0;
    }
    
  • Here is the first hit on google for "file io in c"

    http://www.cs.bu.edu/teaching/c/file-io/intro/

    Here is the third hit from gamedev with more of a C++ slant

    http://www.gamedev.net/reference/articles/article1127.asp

    You declare the pointer in the scope that you need it.

  • It's just an ordinary pointer like any other.

    FILE *CreateLogFile() 
    {
        return fopen("logfile.txt","w"); // allocates a FILE object and returns a pointer to it
    }
    
    void UsefulFunction()
    {
       FILE *pLog = CreateLogFile(); // it's safe to return a pointer from a func
       int resultsOfWork = DoSomeWork();
       fprintf( pLog, "Work did %d\n", resultsOfWork );  // you can pass it to other functions
       fclose( pLog ); // just be sure to clean it up when you are done with fclose()
       pLog = NULL;    // and it's a good idea to overwrite the pointer afterwards
                       // so it's obvious you deleted what it points to
    }
    
  • int main(void)
    {
      char c;
      FILE *read;
      read = fopen("myfile", "r"); // opens "myfile" for reading
      if(read == NULL)
      {
        perror("Error: could not open \"myfile\" for reading.\n");
        exit(1);
      }
      c = fgetc(read);
      fclose(read);
      printf("The first character of myfile is %c.\n", c);
      return 0;
    }
    

    You're perfectly allowed to declare global filehandles if you like, just like any other variable, but it may not be recommended.

    This is the C way. C++ can use this, but I think there's a more C++ friendly way of doing it. As a note, I hate it when questions are marked C/C++, because C and C++ are not the same language and do not work the same. C++ has a lot of different ways to do things that C doesn't have, and they may be easier for you to do in the context of C++ but are not valid C. So while this will work for either language, it's not what you want if you predominantly use C++.

    EDIT: Added some error checking. Always use error checking in your code.

  • First, keep in mind that a file pointer (and the associated allocated structure) is based on the lower level open() read() write() calls. The associated file descriptor (obtained by fileno(file_pointer) is the least interesting thing, but something you might want to watch your scope with.

    If your going to declare a file pointer as global in a module, its usually a very good idea to keep it static (contained within that module / object file). Sometimes this is a little easier than storing it in a structure that is passed from function to function if you need to write something in a hurry.

    For instance, (bad)

    #include <stdio.h>
    #include ...
    
    #define MY_LOG_FILE "file.txt"
    
    FILE *logfile
    

    Better done as:

    #include <stdio.h>
    
    #define MY_LOG_FILE "file.txt"
    
    static FILE *logfile;
    
    int main(void)
    {
    

    UNLESS, you need several modules to have access to that pointer, in which case you're better off putting it in a structure that can be passed around.

    If its needed only in one module, consider declaring it in main() and letting other functions accept a file pointer as an argument. So, unless your functions within the module have so many arguments that another would be unbearable .. there's (usually) no reason to declare a file pointer globally.

    Some logging libraries do it, which I don't care for ... especially when dealing with re-entrant functions. Nevermind C's monolithic namespace :)

0 comments:

Post a Comment