Reputation: 39
I have got the following code:
#include <stdio.h>
#include "config.h"
#include <errno.h>
char buffer[50];
long long bufSize = 50;
FILE* fptr;
char* readConfig(char* buffer, size_t bufSize) {
fptr = fopen("config.txt", "rt");
if (fptr == NULL) {
return "error opening config file: %s", strerror(errno);
} else {
if ((fgets(buffer, bufSize, fptr)) == NULL) {
fclose(fptr);
return "error reading config file: %s", strerror(errno);
}
else {
fclose(fptr);
return buffer;
}
}
}
For test purposes I deleted the config.txt file so that the fopen() function should return NULL. What wonders me is that fopen("config.txt", "rt"); fails, but when debugging the code it just skips the "if (fptr == NULL) {...}" part and directly jumps out of the function.
When going on with the debugging process, I get the following error when trying to work with the return Value of readConfig() "0xC0000005: Access violation reading location 0xFFFFFFFFA4E0EB70"
Upvotes: 0
Views: 171
Reputation:
main()
) and didn't include config.h.#include <string.h>
for strerror()
.buffer[50]
and bufSize = 50;
use sizeof
to determine the size of the array. The other good alternative is to define a constant.fopen()
mode "t" isn't standard, so either leave it out or tag your program with windows or whatever.else
& indentation.return "error opening config file: %s", strerror(errno);
doesn't work the way you expect, it will evaluate the first part in void context then return the 2nd part strerror(errno)
. I was not able to otherwise reproduce any ill effects.fgets()
return NULL on eof or error but not appear to set errno
. You can use feof()
and/or ferror()
to tell which if needed.fgets()
you call fclose()
prior to inspecting errno
, so it have the status of the fclose()
call instead.#include <errno.h>
#include <stdio.h>
#include <string.h>
char *readConfig(char *buffer, size_t bufSize) {
FILE* fptr = fopen("config.txt", "r");
if(!fptr)
return strerror(errno);
if(!fgets(buffer, bufSize, fptr)) {
fclose(fptr);
return "fgets eof/error";
}
fclose(fptr);
return NULL;
}
int main(void) {
char b[50];
const char *error = readConfig(b, sizeof b);
if(error) {
printf("error: %s\n", error);
return 1;
}
printf("%s", b);
}
Consider having caller open the file and pass in the FILE *
. It gives you the flexibility, for instance, to use stdin
as the file handle.
I prefer using goto
instead of the multiple returns when resource cleanup is required. It's a bit more verbose here but each error case is handled the same way. When you swap the arguments you can document how they are related with recent compilers:
char *readConfig(size_t bufSize, char buffer[bufSize]) {
char *r = NULL;
FILE* fptr = fopen("config.txt", "r");
if(!fptr) {
r = strerror(errno);
goto out;
}
if(!fgets(buffer, bufSize, fptr)) {
r = "fgets eof/error";
goto out;
}
out:
fptr && fclose(fptr);
return r;
}
Upvotes: 1