Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using fopen_s in C

I have a problem with programming in C, especially with fopen in Visual Studio. I read about the fopen_s function and added the following line to my project, but it still doesn't work.

_CRT_SECURE_NO_WARNINGS

So I tried using fopen_s in this way:

FILE *fp;
errno_t err;
if ((err = fopen_s(&fp, "C:/File.txt", "rt")) != 0)
    printf("File was not opened\n");
else
    fprintf(fp, "Date: %s, Time: %s, Score: %i \n", __DATE__, __TIME__, score);
fclose(fp);

It's still crashing. What's wrong?

like image 983
nikodamn Avatar asked Jun 09 '14 19:06

nikodamn


People also ask

What is the difference between fopen and fopen_s?

Save this answer. Show activity on this post. fopen_s is a variant of fopen which contains parameter validation and hands back an error code instead of a pointer in case something goes wrong during the open process. It's more secure than the base variant because it accounts for more edge conditions.

Does fopen work on Windows?

The fopen function opens the file that is specified by filename . By default, a narrow filename string is interpreted using the ANSI codepage ( CP_ACP ). In Windows Desktop applications, it can be changed to the OEM codepage ( CP_OEMCP ) by using the SetFileApisToOEM function.


2 Answers

You use fclose with an invalid fp value, even if opening failed. Add {} around the else branch, at least.

Many developers think it is generally a good idea to use braces everywhere, even with one statement inside them. It's so easy to make a mistake like this if you don't, even for experienced developers. So put them around the then branch too.

like image 162
hyde Avatar answered Oct 12 '22 18:10

hyde


The _s functions are unportable Microsoft inventions which, for the most part, duplicate functionality that already existed under a more portable name. Moreover, blindly changing from the non-_s variant of a function to the _s variant generally does not fix anything. (For instance, silently truncating a string is less disastrous than clobbering the stack but it is still misbehavior which may be exploitable.)

Your problem -- which is not affected by the difference between fopen and fopen_s -- is almost certainly that you are not bothering to check for errors properly. Here is how to check for errors properly:

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

int main(int argc, char **argv)
{
    FILE *fp;

    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        return 2;
    }

    fp = fopen(argv[1], "rb");
    if (!fp) {
        fprintf(stderr, "opening %s: %s\n", argv[1], strerror(errno)); // HERE
        return 1;
    }

    // use 'fp' here...

    return 0;
}

Notice how the line marked // HERE prints both the exact string that was passed to fopen and the result of strerror(errno). It is absolutely essential that you print both the arguments and strerror(errno) whenever a system call fails. (Note: If you do wind up using one of the _s functions that returns an error code rather than setting errno, then you must pass the return value to strerror instead.)

Change your program to do this and you will be able to figure out why it isn't working.

like image 22
zwol Avatar answered Oct 12 '22 16:10

zwol