I’ve been creating a function that’s supposed to open a file (catalogname []). However whenever I compile I get these two errors that I can’t figure out.
a3.c: In function ‘openCatalog’:
a3.c:20: warning: assignment from incompatible pointer type
a3.c:22: warning: return makes pointer from integer without a cast
Here is my code:
FILE* openCatalog(char catalogname[])
{
catalogname = fopen ("*catalogname", "r");
if(fopen != 0)
{
return 1;
}
else
{
return 0;
}
}
Thanks in advance for any insight you can provide.
A full exegesis on this code will take a while.
The brief version is:
This opens the named file for reading and returns the file stream pointer.
An alternative brief version checks whether the file can be opened:
Exegesis
The original code is:
We don’t have a specification beyond ‘open the file’. Given the function signature, it appears that you want the
FILE *(file stream pointer) for the open file returned. So, let’s critique the code on that basis.The function prototype line is OK; it could be
char const catalogname[]to emphasize that the function won’t modify the file name, but that’s a refinement, not a bug-fixing change.The type of
catalognamein the function ischar *. In a function’s argument list, an array is loosely equivalent to a pointer. I’d normally writeFILE *openCatalog(char const *catalogname)to emphasize that within the function, it is achar const *variable. Nevertheless, it is 100% legitimate to use the array notation you used; it is purely a stylistic preference for me to use the pointer notation.The next executable line has a couple of problems. The function call to
fopen()is not technically wrong, though it opens a file with a fixed name*catalognamerather than the file specified in the variablecatalogname. To fix that, you need to remove the quotes. The*would give you a character instead of a string, and it would be the first character of the file name. So, remove the*too.This leaves you with
fopen()returning a value, actually aFILE *, and you assign it tocatalogname, achar *. This is a type mismatch, which the compiler warns about. As shown in the first rewrite, the more normal way to handle this would be:This accounts for your error message:
We do not know whether your catalog is a text file or a binary file. If it is a binary file, then you should use
"rb"to open it if you are on Windows (where it really matters), and that will work fine on Unix-like systems too (where there is no distinction between text and binary files).The next line in your code is the conditional:
This actually checks whether the function pointer for the function
fopen()is null or not. And the C standard guarantees that in a hosted environment (which you are using), no function pointer will be null. So the compiler can optimize that test to assume that the condition is always true.What you actually need is a test of the result:
You then have two return statements, one returning 1, one returning 0. The one returning 1 elicits a warning about converting an integer to a pointer because the function is defined to return a
FILE *and 1 is an integer.This accounts for your other warning message:
The return returning 0 does not generate a warning because 0 is a null pointer constant, and that is a valid value for a function like this to return.
The code should probably simply return the value from
fopen(). It is correct to test the value somewhere, either in this function or in the calling function, to ensure that the open succeeded. You might test it here with:Using
errnoandstrerror()means that you should also include the headers:The code should return the file stream from
fopen():In total, that leads to:
The problems cited above are much the same if the function is intended to check whether the file can be opened for reading. The revised code I showed first is slightly verbose. Since the presumed purpose is to check whether the file can be opened, the calling code should be responsible for dealing with the ‘it cannot be opened case’; it knows what sort of diagnostic to generate. This is a slightly more compact version of the revision, but the object code for the this and the one above would be identical.
A simple implementation of
err_report_and_exit()is:The “errreport.h” header might be:
The GCC-specific bits mean that you get the same level of format error reporting as if you were using
printf()directly.(This code is modelled on a bigger package that systematically uses
err_as a function prefix. In that package, this function would beerr_error(). That’s why it iserr_rather thanerror_— though the explanation takes longer to type than it would to fix it. The big package is contained in filesstderr.candstderr.h, though there’s an argument that it is treading on thin ice using thestdprefix. It is, however, my standard error reporting package.)