长沙网站设计公司重庆标志,服装商城网站源码,网站建设经费预算表,中国有几个搜索引擎博客主页#xff1a;【夜泉_ly】 本文专栏#xff1a;【C语言】 欢迎点赞#x1f44d;收藏⭐关注❤️ C语言-文件操作-一些我想到的、见到的奇怪的问题 前言1.在不关闭文件的情况下#xff0c;连续多次调用 fopen() 打开同一个文件#xff0c;会发生什么#xff1f;1.1过… 博客主页【夜泉_ly】 本文专栏【C语言】 欢迎点赞收藏⭐关注❤️ C语言-文件操作-一些我想到的、见到的奇怪的问题 前言1.在不关闭文件的情况下连续多次调用 fopen() 打开同一个文件会发生什么1.1过程1.2结论1.3意义 2.fseek如果设置到文件前的位置会发生什么2.1过程1.2结论 3.fseek设置到单个汉字的中间会发生什么?3.1过程3.2结论3.3意义 4.同时读、写同一个文件会发生什么4.1过程4.2结论 5.在追加模式下使用fseek会不会覆盖原文件5.1过程5.2结论 6.在只读模式下写入会发生什么6.1过程6.2结论 7.FILE类型的结构体是开在堆上的吗如果是free它一下会发生什么7.1过程7.2结论7.3意义 前言
关于C语言文件操作的文章在CSND上很多很多我自身才疏学浅补充不了什么内容因此我决定换一个角度分享一下我想到的、见到的奇怪的问题。
这个奇怪当然也是我单方面认为的
注本篇只讨论数据文件且只讨论纯文本文件(.txt)。
1.在不关闭文件的情况下连续多次调用 fopen() 打开同一个文件会发生什么
1.1过程
为了验证这个问题我当然不想创建很多的文件指针来一对一因此我尝试使用同名指针两次打开同一个文件
#include stdio.h
int main()
{FILE* pf fopen(test.txt, w);printf(time 1:%p\n, pf);pf fopen(test.txt, w);printf(time 2:%p\n, pf);return 0;
}运行结果如下图 这说明即便是同一个文件指针同一个文件只要使用fopen系统都会再用一个新的文件描述符。 那么要验证这个问题就很简单了代码如下
#include stdio.h
int main()
{FILE* pf;int count 1;while (1){pf fopen(test.txt, w);if (pf NULL){printf(time %d::, count);perror();break;}printf(time %d:%p\n, count, pf);}return 0;
}运行结果如下图 可以看见当打开第510次时以及没有更多的文件描述符了。 当然我用的是VS2022而在其他环境下具体次数可能会改变但应该还是会有个限制的。 在现代操作系统中每个进程可以同时打开的文件数是有限的通常可以通过 ulimit -n 查看限制。每次调用 fopen()操作系统都会为文件分配一个文件描述符文件描述符是操作系统为进程管理文件资源的句柄。当打开的文件数量超过系统允许的最大数量时fopen() 将返回 NULL。 1.2结论
对文件只开不关会使得系统提供的文件描述符被耗尽最后fopen会返回一个空指针。
1.3意义
如果有人只会开文件不会关文件那么那个人多半在开文件时也不会检查文件是否打开成功。 那么这样的错误就有可能出现了
fputs(HaHa, NULL);具体场景如下
#include stdio.h
int main()
{FILE* pf;int count 1;while (1){pf fopen(test.txt, w);if (pf NULL){printf(time %d::, count);perror();break;}printf(time %d:%p\n, count, pf);}fputs(HaHa, pf);// pf 此时已经为 NULL了return 0;
}如果运行程序最终会崩掉 因此在使用完文件后一定要fclose
2.fseek如果设置到文件前的位置会发生什么
2.1过程
有这样的问题是因为有一天我写了这样一个代码
#include stdio.h
int main()
{FILE* pf fopen(test.txt, w);if (!pf)return 1;int ch a;fputc(ch,pf);fseek(pf, -1000000, SEEK_SET);ch a;fputc(ch, pf);fclose(pf);pf NULL;return 0;
}我在fgetc之后用了fseek并把位置设置到了开始位置的-10000之后再次使用了fgetc。 然后程序运行成功了并且在文件中输入了两个a
aa为什么不是一个a或者报错 其实非常简单因为刚进fseek就被弹出来了
#include stdio.h
int main()
{FILE* pf fopen(test.txt, w);if (!pf)return 1;int ch a;fputc(ch, pf);printf(fseek前的偏移量%d\n, ftell(pf));if (fseek(pf, -1000000, SEEK_SET)) {perror(fseek failed);}printf(fseek后的偏移量%d\n, ftell(pf));ch a;fputc(ch, pf);fclose(pf);pf NULL;return 0;
}运行结果如下图
1.2结论
什么都不会发生fseek会返回一个非零值并设置错误码对应的错误信息就是 Invalid argument但偏移量不会改变。
3.fseek设置到单个汉字的中间会发生什么?
3.1过程
众所周知一个汉字占多个字节那我用fseek设置到这多个字节的中间会发生什么呢 代码如下
#include stdio.h
int main()
{FILE* pf fopen(test.txt, w);if (!pf)return 1;fprintf(pf, 今天的日期20240921);fclose(pf);pf fopen(test.txt, r);if (!pf)return 1;fseek(pf, 1, SEEK_SET);char ch[100];fscanf(pf, %s, ch);printf(%s\n, ch);return 0;
}运行结果如下
3.2结论
可能会输出乱码。
3.3意义
在C语言中有很多地方使用汉字会导致未定义行为因此尽量避免使用汉字。
4.同时读、写同一个文件会发生什么
4.1过程
代码如下
#include stdio.hint main() {FILE* write fopen(test.txt, w);FILE* read fopen(test.txt, r);if (!read || !write)return 1;fputs(Hello World!, write);char ch[100];fgets(ch, 100, read);printf(%s\n, ch);fclose(write);write NULL;fclose(read);read NULL;return 0;
}这里我在对文件写入之后立刻读取最终得到下图的结果 但如果我在fputs语句之后刷新缓冲区则会正常输出 fputs(Hello World!, write);fflush(write);如果我将fclose提前也能正常输出 fputs(Hello World!, write);fclose(write);write NULL;4.2结论
可能缓冲区没被刷新导致读到乱码或不完整的信息。
5.在追加模式下使用fseek会不会覆盖原文件
5.1过程
先写再追加最后读
#include stdio.hint main()
{FILE* write fopen(test.txt, w);if (!write)return 1;fputs(Hello World!, write);fclose(write);write NULL;FILE* add fopen(test.txt, a);if (!add)return 1;fseek(add, -10, SEEK_SET);perror();fputs(xxxxxxxxxx, add);fclose(add);add NULL;FILE* read fopen(test.txt, r);char ch[100];fgets(ch, 100, read);printf(%s\n, ch);fclose(read);read NULL;return 0;
}结果如下图
5.2结论
并不会覆盖原文件fseek又是一进去就被弹出来了(rewind也不行会设置在追加的起始位置)。
6.在只读模式下写入会发生什么
6.1过程
我先写入Hello World!然后在只读模式下尝试写入信息(还加了一个perror打印错误信息)最后读取文件信息。 代码如下
#include stdio.hint main() {FILE* write fopen(test.txt, w);if (!write)return 1;fputs(Hello World!, write);fclose(write);write NULL;FILE* pf fopen(test.txt, r);if (!pf)return 1;fprintf(pf, HaHa);perror();fclose(pf);FILE* read fopen(test.txt, r);char ch[100];fgets(ch, 100, read);printf(%s\n, ch);fclose(read);read NULL;return 0;
}运行结果如下图 错误信息是坏的文件描述符可能是指我的文件指针用错了吧。
6.2结论
会拒绝写入原文件信息不会改变。
7.FILE类型的结构体是开在堆上的吗如果是free它一下会发生什么
7.1过程
先简单验证一下VS2022中是不是开在堆上的
#include stdio.h
#include stdlib.h
int main()
{int* a (int*)malloc(sizeof(int));int* b (int*)malloc(sizeof(int));FILE* pf fopen(test.txt, w);printf(%p\n%p\n%p, a, b, pf);return 0;
}运行结果如下图 可以发现这三个变量的地址相近因此可以认为FILE类型的结构体是开在堆上的。 既然如此那么free(文件指针)应该是可以运行的
#include stdio.h
#include string.h
int main()
{FILE* write fopen(test.txt, w);if (!write)return 1;fputs(Hello World!, write);fflush(write);free(write);FILE* read fopen(test.txt, r);char ch[100];fgets(ch, 100, read);printf(%s\n, ch);fclose(read);read NULL;return 0;
}运行结果如下图
7.2结论
在VS2022中FILE类型的结构体是开在堆上的因此free(结构体指针)时不会报错。 但是FILE类型的结构体并不是通过 malloc 或 calloc 分配的内存所以使用 free 会导致未定义行为如在下一次读取时输出一堆乱码。
7.3意义
虽然 FILE* 在堆上分配但由于它是由C标准库通过 fopen() 处理的不应直接使用 free()而应该使用 fclose() 来正确释放资源!!! 希望本篇文章对你有所帮助并激发你进一步探索编程的兴趣 本人仅是个C语言初学者如果你有任何疑问或建议欢迎随时留言讨论让我们一起学习共同进步