本篇介绍 stdio.h头文件中安全函数学习之gets_s,tmpnam_s,fopen_s,tmpfile_s,freopen_s。
实验环境 window11, VS2022
gets / gets_s 示例代码:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
#include <limits.h>
#include <inttypes.h>
#include <stdint.h>
#pragma warning(disable:4996)
int main(void)
{
//char str[20]; // 创建一个字符数组来存储输入的字符串
//printf("please input one line text:\n");
//char* ret = gets(str); // VS2022 已经没有gets()函数了
//printf("ret = %s\n", ret);
//printf("The text you entered is:\n");
//printf("str = %s\n", str);
char str2[10]; // 创建一个字符数组来存储输入的字符串
printf("please input one line text:\n");
char* ret2 = gets_s(str2, sizeof str2); // 调用gets_s()函数读取输入的字符串
printf("ret2 = %s\n", ret2);
printf("The text you entered is:\n");
printf("str2 = %s\n", str2);
printf("hello world\n");
return 0;
}
运行结果:
参考:
https://zh.cppreference.com/w/c/io/gets
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/gets-s-getws-s?view=msvc-170
tmpnam / tmpnam_s example
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
#include <limits.h>
#include <inttypes.h>
#include <stdint.h>
#pragma warning(disable:4996)
int main(void)
{
// 注意,编译器/连接器可能会发出安全警告,
// C4996 'tmpnam': This function or variable may be unsafe.Consider using tmpnam_s instead.To disable deprecation, use _CRT_SECURE_NO_WARNINGS.See online help for details.safefunction D : \vscpp\cpp20\cpp20standard\safefunction\stdio.c 21
char* name1 = tmpnam(NULL);
printf("temporary file name: %s\n", name1);
char name2[L_tmpnam];
if (tmpnam(name2))
printf("temporary file name: %s\n", name2);
char name3[L_tmpnam]; //L_tmpnam最长目录字符数
int ret = tmpnam_s(name3, sizeof name3); //ret = 0表示正常,非0表示失败
if (ret == 0)
{
printf("temporary file name3: %s\n", name3);
}
else
{
printf("temporery is error: %d\n", ret);
}
char name4[20];
int ret2 = tmpnam_s(name4, sizeof name4); //ret = 0表示正常,非0表示失败
if (ret2 == 0)
{
printf("temporary file name4: %s\n", name4);
}
else
{
printf("temporery is error: %d\n", ret2);
}
return 0;
}
运行结果:
参考:
https://zh.cppreference.com/w/c/io/tmpnam
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tmpnam-s-wtmpnam-s?view=msvc-170
fopen / fopen_s example
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
#include <limits.h>
#include <inttypes.h>
#include <stdint.h>
#pragma warning(disable:4996)
int main(void)
{
const char* fname = "./fopen_name.txt"; // 或 tmpnam(NULL);
int is_ok = EXIT_FAILURE;
FILE* fp = fopen(fname, "w+");
if (!fp) {
perror("File opening failed");
return is_ok;
}
fputs("Hello, world!\n", fp);
rewind(fp);//该函数将参数stream指向流的文件位置指示符设置为文件开头
int c; // 注意:为处理 EOF 需要 int 而非 char
while ((c = fgetc(fp)) != EOF) // 标准 C 的 I/O 文件读取循环
putchar(c);
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp)) {
puts("End of file is reached successfully");
is_ok = EXIT_SUCCESS;
}
fclose(fp);
//remove(fname); //不移除
const char* fname2 = "./fopen_name2.txt";
FILE* fp2;
int ret = fopen_s(&fp2, fname2, "w+"); //ret == 0表示正常, 非0表示失败
if (ret != 0) {
perror("File opening failed2");
return is_ok;
}
fputs("Hello, world-2!\n", fp2);
rewind(fp2);
int c2; // 注意:为处理 EOF 需要 int 而非 char
while ((c2 = fgetc(fp2)) != EOF) // 标准 C 的 I/O 文件读取循环
putchar(c2);
if (ferror(fp2))
puts("I/O error when reading-2");
else if (feof(fp2)) {
puts("End of file is reached successfully-2");
is_ok = EXIT_SUCCESS;
}
fclose(fp2);
//remove(fname2); //不移除
return is_ok;
}
运行结果:
参考:
https://zh.cppreference.com/w/c/io/fopen
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-s-wfopen-s?view=msvc-170
tmpfile / tmpfile_s example
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
#include <limits.h>
#include <inttypes.h>
#include <stdint.h>
#pragma warning(disable:4996)
int main(void)
{
printf("TMP_MAX = %d, FOPEN_MAX = %d\n", TMP_MAX, FOPEN_MAX);
FILE* tmpf = tmpfile();
fputs("Hello, world", tmpf);//将字符串写入到tmpf中
rewind(tmpf);
char buf[6];
fgets(buf, sizeof buf, tmpf);//从给定文件流读取最多 count - 1 个字符并将它们存储于 str 所指向的字符数组。
printf("got back from the file: '%s'\n", buf);
//tmpfile_s
FILE* stream;
char tempstring[] = "String to be written";
// Create temporary files.
for (int i = 1; i <= 3; i++)
{
int ret = tmpfile_s(&stream); //ret == 0表示成功,非0表示失败
if (ret)
perror("ret = %d Could not open new temporary file\n", ret);
else
printf("ret = %d Temporary file %d was created\n", ret, i);
}
// Remove temporary files.
printf("%d temporary files deleted\n", _rmtmp());
return 0;
}
运行结果:
参考:
https://zh.cppreference.com/w/c/io/tmpfile
https://www.standards.wiki/c/c_library_stdio_function_tmpfile.html
https://www.standards.wiki/c/c_appendix_secure_function_tmpfile_s.html
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tmpfile-s?view=msvc-170
freopen / freopen_s example
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
#include <limits.h>
#include <inttypes.h>
#include <stdint.h>
#pragma warning(disable:4996)
int main(void)
{
//freopen example
//puts("stdout is printed to console");
//if (freopen("./redir.txt", "w", stdout) == NULL)
//{
// perror("freopen() failed");
// return EXIT_FAILURE;
//}
//puts("stdout is redirected to a file"); // 写入 redir.txt
//fclose(stdout);
//freopen_s example
FILE* stream;
// Reassign "stderr" to "freopen.out":
int ret = freopen_s(&stream, "./freopen.out", "w", stderr);
if (ret != 0)
fprintf(stdout, "error on freopen\n");
else
{
fprintf(stdout, "successfully reassigned\n");
fflush(stdout);
fprintf(stream, "This will go to the file 'freopen.out'\n");
fclose(stream);
}
system("type freopen.out");
return EXIT_SUCCESS;
}
运行结果:
参考:
https://zh.cppreference.com/w/c/io/freopen
https://www.standards.wiki/c/c_library_stdio_function_freopen.html
https://www.standards.wiki/c/c_appendix_secure_function_freopen_s.html
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/freopen-s-wfreopen-s?view=msvc-170