Program when opening file, always "NULL"

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,362
Good day! I have this simple program to count characters in a file and output the length, but whenever I open the file "File.txt" I always get that its "NULL", does anyone have any ideas?

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// declare function before it's called
void Count (char * FILENAME);

int main ()
{
    //int c;
    char f1[100];   // array big enough to hold expected input

    printf ("Please enter file for character counting\n");
    scanf  ("%99s", f1);    // set max characters to read to prevent buffer overflow

    Count(f1);
    int c = getchar ();
    while (c>0)
        ;

    return 0;
}

void Count (char * FILENAME)
{
         printf("Counting started\n");
         FILE *inFile;
         int Length;

         int Byte;       // fgetc returns int, so use an int for "Byte" and "newByte"

         inFile = fopen(FILENAME,"r");

         if(inFile == NULL)
         {
            printf("Error: Can't Open file!\n");
         }
         else
         {
                 Length = 0;
                 while((Byte = fgetc(inFile)) != EOF)    // read a byte, check if EOF, "EOF" is outside the range of "char most times"
                 {
                    ++Length;
                 }
         }
         if (inFile != NULL) fclose(inFile);            // close your files when you're done
         printf ("The file contains %d characters, blanks, tabs, spaces are included!", Length);
}
 

WBahn

Joined Mar 31, 2012
30,072
A very common mistake that people make, which your code as posted does not, is to use

if (inFile = NULL)....

which sets inFile equal to NULL and then ensures that you use a NULL pointer. Better to get in the habit of doing

if (NULL == inFile)....

since if you make the very common typo of using a single equals sign you have turned a logic error into a syntax error that the compiler can catch.

An alternative is to use

if (!inFile)....

Before you try to open the file, print the filename out to the screen to make sure it is correct and doesn't contain extra characters such as spaces or newlines.

printf("Filename: <%s>\n", FILENAME);

Also, using all caps for a variable name is bad practice. Convention is that all caps are used for symbolic constants and struct data types.

What is the purpose of your while(c>0) loop in your main. Since it is very difficult to get getchar() to return 0, this will always be an infinite loop. I suspect you are wanting to wait until you hit Return in order to end the program, but you likely have something still in the buffer after the scanf() call. Using scanf(), especially for user input, is extremely unreliable and dangerous. Far better to use fgets() instead as it gives you complete control over what is happening.
 

spinnaker

Joined Oct 29, 2009
7,830
There is no reason for an if statement here:
if (inFile != NULL) fclose(inFile); // close your files when you're done

This printf is going to get executed regardless. Is that what you want?

printf ("The file contains %d characters, blanks, tabs, spaces are included!", Length);


I am not aware that fgetc ever returns EOF. I don't even think EOF is a valid keyword in C.





Corrected code.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// declare function before it's called
void Count (char * FILENAME);
int main ()
{
    //int c;
    char f1[100];   // array big enough to hold expected input
    printf ("Please enter file for character counting\n");
    scanf  ("%99s", f1);    // set max characters to read to prevent buffer overflow
    Count(f1);
    int c = getchar ();
    while (c>0)
        ;
    return 0;
}
void Count (char * FILENAME)
{
         printf("Counting started\n");
         FILE *inFile;
         int Length;
         int Byte;       // fgetc returns int, so use an int for "Byte" and "newByte"
         inFile = fopen(FILENAME,"r");
         if(inFile)
         {

                 Length = 0;
                 while(feof(inFile))   
                 {
                   Byte = fgetc(inFile)
                    ++Length;
                 }
                
                 fclose(inFile);
                 printf ("The file contains %d characters, blanks, tabs, spaces are included!", Length);


         }
         else
         {
                      printf("Error: Can't Open file!\n");

         }

}
 

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,362
A very common mistake that people make, which your code as posted does not, is to use

if (inFile = NULL)....

which sets inFile equal to NULL and then ensures that you use a NULL pointer. Better to get in the habit of doing

if (NULL == inFile)....

since if you make the very common typo of using a single equals sign you have turned a logic error into a syntax error that the compiler can catch.

An alternative is to use

if (!inFile)....
Its not this, thanks for the idea!

Before you try to open the file, print the filename out to the screen to make sure it is correct and doesn't contain extra characters such as spaces or newlines.

printf("Filename: <%s>\n", FILENAME);
I might try this.

Also, using all caps for a variable name is bad practice. Convention is that all caps are used for symbolic constants and struct data types.
I know this part, its a mistake on my turn.

What is the purpose of your while(c>0) loop in your main. Since it is very difficult to get getchar() to return 0, this will always be an infinite loop. I suspect you are wanting to wait until you hit Return in order to end the program,
This part is so, since only "getchar()" does not work, meaning the program closes instead of waiting for a key to be hit.

but you likely have something still in the buffer after the scanf() call. Using scanf(), especially for user input, is extremely unreliable and dangerous. Far better to use fgets() instead as it gives you complete control over what is happening.
"scanf ()" is only for the file name, it shouldnt be a problem? What is the way of flashing the memory (RAM, buffer) after the program ends, isnt that done with closing the file?

The new code that I made works, dont know why. It works when I start it from the "exe" file I believe, but when I use the codeblocks IDE, it does not work. Maybe I need administrative privileges?

Code:
/*
The example is working. Implementing a simple encryption method. The professor told me that this is the encryption banks use with a longer public key (??? publicly known how long it is). In the example that he gave though, we were allocating memory with "malloc()" or "calloc()" (I thinkg it was "callock()". He was indexing both the file and the key with a counter (i,z), I think the same counter for the file and key (i for the the file and key)
*/

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

// declare function before it's called
void Count (char * FILENAME);

int main ()
{
    char f1[100];   // array big enough to hold expected input

    printf ("Please enter file for character counting\n");
    scanf  ("%99s", f1);    // set max characters to read to prevent buffer overflow

    Count(f1);

    return 0;
}

void Count (char * FILENAME)
{
         printf("Counting started\n");
         FILE *inFile;
         int Length;

         int Byte;       // fgetc returns int, so use an int for "Byte" and "newByte"

         inFile = fopen(FILENAME,"r");

         if(inFile == NULL)
         {
            printf("Error: Can't Open file!\n");
         }
         else
         {
                 Length = 0;
                 while((Byte = fgetc(inFile)) != EOF)    // read a byte, check if EOF, "EOF" is outside the range of "char most times"
                 {
                     if (Byte != '\n' && Byte != '\t' && Byte != ' ')
                        ++Length;
                 }
         }
         if (inFile != NULL) fclose(inFile);            // close your files when you're done
         printf ("The file contains %d characters, blanks, tabs, spaces are excluded!", Length);

         int c = getchar ();
         while (c>0)
            ;
}
 

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,362
You are wrong here! EOF is valid constant, declared in the standard libraries, it is needed and is there for every file, without it the compiler does not know when to terminate. Its a common mistake that people make!
 

spinnaker

Joined Oct 29, 2009
7,830

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,362
Last edited:

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,362
I found the problem and it was that codeblocks generates 2 exe files, one of them is in the folder debug, but when you click "run" it starts the second "main.exe" file in the main directiory. If the file that I want to count is not in the main directory, the program fails.
 

WBahn

Joined Mar 31, 2012
30,072
I found the problem and it was that codeblocks generates 2 exe files, one of them is in the folder debug, but when you click "run" it starts the second "main.exe" file in the main directiory. If the file that I want to count is not in the main directory, the program fails.
Your problem is probably because of where your IDE is assuming the files are located. Frequently an IDE places the actual executable in a subfolder based on the compile settings, such as debug or release, but when you run the program from within the IDE it behaves as though the file is located in the main project directory, even though it is not. But when you run the .exe file from its actual location directly, it uses the folder it is actually located in as the current directory. You can usually explicitly set the working directory for the IDE-controlled execution from somewhere within the project settings.
 

spinnaker

Joined Oct 29, 2009
7,830
Your problem is probably because of where your IDE is assuming the files are located. Frequently an IDE places the actual executable in a subfolder based on the compile settings, such as debug or release, but when you run the program from within the IDE it behaves as though the file is located in the main project directory, even though it is not. But when you run the .exe file from its actual location directly, it uses the folder it is actually located in as the current directory. You can usually explicitly set the working directory for the IDE-controlled execution from somewhere within the project settings.

Whenever I suspect the code is not finding the file where I think it should be finding it then I specify the whole path. Takes the guess work out of it. ;)
 

WBahn

Joined Mar 31, 2012
30,072
Maybe in you compiler. I have never seen any standard documentation where fgetf returns EOF

http://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

It does return NULL which makes sens but mentions nothing about EOF.
While I generally like tutorialspoint, it is NOT the C language standard.

I'm not aware of any fgetf() function in the standard libraries.

The fgets() function cannot return EOF because it returns a pointer to a char and EOF is an integer.

On the other hand, fgetc() cannot return NULL because it returns an integer. But it can (and must, by the language standard), return EOF under certain conditions.

And tutorialspoint DOES cover this:

https://www.tutorialspoint.com/c_standard_library/c_function_fgetc.htm

From the standard for fgetc() : "Returns: If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and fgetc returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and fgetc returns EOF."

EOF is a macro required by the C language standard and defined in stdio.h. It is required to expand to an integer constant expression of type int with a negative value. It is the value returned by several functions, usually to indicate an end-of-file condition, but not always. For instance, fclose() returns zero if it is successful and EOF if an error occurs. Similarly for fflush(). The scanf() family of functions return EOF if an input failure occurs prior to any conversions. The fgetc() function returns EOF if the end-of-stream indicator is set or if an error occurs. This is why there are feof() and ferror() functions -- to allow the program to distinguish between an end-of-file condition. The various put() functions also return EOF if there is a write error.
 

WBahn

Joined Mar 31, 2012
30,072
There is no reason for an if statement here:
if (inFile != NULL) fclose(inFile); // close your files when you're done
Oh, but there IS a need for it!

If inFile is NULL, then he will be calling fclose() with a NULL pointer. This invokes undefined behavior -- something I found out the hard way a couple decades ago. It is the programmer's responsibility to ensure that fclose is only called with a pointer to a valid FILE object.

In the TS's code, this line is reached regardless of whether the file opened successfully or not, so it must be trapped.
 

spinnaker

Joined Oct 29, 2009
7,830
Oh, but there IS a need for it!

If inFile is NULL, then he will be calling fclose() with a NULL pointer. This invokes undefined behavior -- something I found out the hard way a couple decades ago. It is the programmer's responsibility to ensure that fclose is only called with a pointer to a valid FILE object.

In the TS's code, this line is reached regardless of whether the file opened successfully or not, so it must be trapped.

Not if it is done this way.

Code:
if(inFile)
         {
                 Length = 0;
                 while(feof(inFile)) 
                 {
                   Byte = fgetc(inFile)
                    ++Length;
                 }
              
                 fclose(inFile);
                 printf ("The file contains %d characters, blanks, tabs, spaces are included!", Length);
         }
         else
         {
                      printf("Error: Can't Open file!\n");
         }
 

WBahn

Joined Mar 31, 2012
30,072
Not if it is done this way.

Code:
if(inFile)
         {
                 Length = 0;
                 while(feof(inFile))
                 {
                   Byte = fgetc(inFile)
                    ++Length;
                 }
            
                 fclose(inFile);
                 printf ("The file contains %d characters, blanks, tabs, spaces are included!", Length);
         }
         else
         {
                      printf("Error: Can't Open file!\n");
         }
Sure, but that's not the way he did it nor the recommendation you made to him about it. The way he did it, he can't omit the if() test per your recommendation.

In most of my programs (which tend to be of a scale that it is reasonable for me to not attempt to recover from failing to open a file or most other errors) I usually write something like:

Code:
void fail(char *s)
{
   fprintf("ABORT! - %s\n", s);
   exit(EXIT_FAILURE);
}
Then, where I open a file, I'll do something like

Code:
   fp = fopen(filename, mode);
   if (!fp) fail("Failed to open input file.");
Beyond this point, I can assume that fp points to a valid FILE object, so I don't need to do further checks.

Of course, if I want to be able to recover from these types of events, then I need to take a fundamentally different tack.
 

spinnaker

Joined Oct 29, 2009
7,830
Sure, but that's not the way he did it nor the recommendation you made to him about it. The way he did it, he can't omit the if() test per your recommendation.
Didn't mean for him to just leave it out of his code, rather put everything in the block.
 
Top