C语言-文件操作-一些我想到的、见到的奇怪的问题
博客主页:【夜泉_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.h>int 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.h>int 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.h>int 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语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!
相关文章:
C语言-文件操作-一些我想到的、见到的奇怪的问题
博客主页:【夜泉_ly】 本文专栏:【C语言】 欢迎点赞👍收藏⭐关注❤️ C语言-文件操作-一些我想到的、见到的奇怪的问题 前言1.在不关闭文件的情况下,连续多次调用 fopen() 打开同一个文件,会发生什么?1.1过…...
变电站设备检测系统源码分享
变电站设备检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…...
电机foc线上课程开课啦
凌鸥学园电机控制学习盛宴,诚邀您的加入 🎓免费学习,荣誉加冕 凌鸥学园提供免费的电机控制课程,从基础到专业,全程无负担。 📚全面课程体系,灵活学习模式 凌鸥学园提供从基础到专业的全面课程…...
解决Mac 默认设置 wps不能双面打印的问题
目录 问题描述: 问题解决: 问题描述: 使用mac电脑的时候,发现wps找不到双面打印的按钮,导致使用wps打开的所有文件都不能自动双面打印 问题解决: mac的wps也是有双面打印的选项,只是默认被关…...
智谱清影 - CogVideoX-2b-部署与使用
🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 体验地址:[丹摩DAMODEL官网](https://www.damodel.com/console/overview) CogVideoX 简介本篇将详细介绍使用丹摩服务器部…...
python queue.Queue介绍
queue.Queue 是 Python 中的线程安全队列,适合用于多线程或多进程环境中进行任务和数据的共享。queue.Queue 提供了 FIFO(先进先出)队列的实现,并包含线程锁机制以保证在多线程环境下数据的安全性。 queue.Queue 的主要方法&…...
Qt 每日面试题 -3
21、static和const的使用 static : 静态变量声明,分为局部静态变量,全局静态变量,类静态成员变量。也可修饰类成员函数。 有以下几类∶ 局部静态变量 : 存储在静态存储区,程序运行期间只被初始化一次,作用域仍然为局部…...
TypeScript系列:第四篇 - typeof 与 keyof
在 TypeScript系列:第三篇 - 泛型 有提及 keyof 的使用。 本文将详细介绍 keyof 和 typeof 运算符的基本概念、应用场景以及如何结合使用它们来提高代码的类型安全性。 #mermaid-svg-bnMG6PMTxMI4iafc {font-family:"trebuchet ms",verdana,arial,sans-se…...
JDK8新增特性(值得收藏)
1.Lamdba表达式 就相当于要使用接口Lock就不需要再创建一个类去实现接口了,直接用Lambda表达式省略了在创建的那个类。 Lamdba表达式是什么? “->”,Lambda操作符或箭 头操作符,它将Lambda表达式分割为两部分。 左边:指Lam…...
MATLAB系列06:复数数据、字符数据和附加画图类
MATLAB系列06:复数数据、字符数据和附加画图类 6. 复数数据、字符数据和附加画图类6.1 复数数据6.1.1 复变量( complex variables)6.1.2 带有关系运算符的复数的应用6.1.3 复函数( complex function)6.1.4 复数数据的作…...
【永磁同步电机(PMSM)】 4. 同步旋转坐标系仿真模型
【永磁同步电机(PMSM)】 4. 同步旋转坐标系仿真模型 1. Clarke 变换的模型与仿真1.1 Clarke 变换1.2 Clarke 变换的仿真模型 2. Park 变换的模型与仿真2.1 Park 变换2.2 Park 变换的仿真模型 3. Simscape标准库变换模块3.1 abc to Alpha-Beta-Zero 模块3…...
CSAPP Attack Lab
个人感觉非常有意思的一个 Lab,涉及的知识面比较窄,主要关注 缓冲区溢出漏洞 这一个方面,并基于此进行代码攻击,体验一把做黑客的感觉,对应知识点为书中的 3.10 节内容。 这个 Lab 上手便给了我当头一棒,在…...
通信工程学习:什么是NFVI网络功能虚拟化基础设施层
NFVI:网络功能虚拟化基础设施层 NFVI(Network Functions Virtualization Infrastructure)即网络功能虚拟化基础设施层,是NFV(Network Functions Virtualization,网络功能虚拟化)架构中的一个重要…...
不在同一局域网怎么远程桌面?非局域网环境下,实现远程桌面访问的5个方法分享!
非局域网环境下,怎么远程桌面?还能做到吗? 在企业管理中,远程桌面访问已成为提高工作效率、实现跨地域协同工作的关键工具。 然而,当被控端与控制端不在同一局域网时,如何实现远程桌面连接成为了许多企业…...
SparkSQL-初识
一、概览 Spark SQL and DataFrames - Spark 3.5.2 Documentation 我们先看下官网的描述: SparkSQL是用于结构化数据处理的Spark模块,与基本的Spark RDD API不同。Spark SQL提供的接口为Spark提供了更多关于正在执行的数据和计算结构的信息。在内部&a…...
Go语言的垃圾回收(GC)机制的迭代和优化历史
Go语言的垃圾回收(GC)机制自Go语言发布以来经历了多次重要的迭代和优化,以提高性能和减少程序运行时的停顿时间。 以下是一些关键的版本和相应的GC优化: Go版本GC耗时情况主要改进点Go 1.0-1.4可能达到几百毫秒至秒级使用简单的标…...
thinkphp8 从入门到放弃(后面会完善用到哪里写到哪)
thinkphp8 从入门到放弃 引言 thinkphp* 大道至简一、 thinkphp8 安装安装Composerthinkphp 安装命令(tp-项目名称)多应用安装(一个项目不会只有一个应用)安装完文件目录如下本地部署配置伪静态好了项目可以run 二、架构服务(Service…...
对于电商跨境电商独立站中源代码建站和SaaS建站的区别
电商跨境电商独立站的搭建有多种方式,作为电商企业,搭建完全自主控制的电商独立站,对于电商企业的发展和运营有着至关重要的作用。下面推荐一个使用多年的跨境电商独立站系统源码,做简要介绍,据说前段时间火爆的Pandab…...
使用vite+react+ts+Ant Design开发后台管理项目(二)
前言 本文将引导开发者从零基础开始,运用vite、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术…...
C++之 string(中)
C之 string string类对象的容量操作 resize 将有效字符的个数该成n个,多出的空间用字符c填充 虽然在string里用的不多,但是在vector里面常见 这里有三种情况: 1)resize小于当前的size 2)resize大于当前的size,小于capacity …...
告别B站评论区识人难题!这个免费工具让你一键掌握用户背景
告别B站评论区识人难题!这个免费工具让你一键掌握用户背景 【免费下载链接】bilibili-comment-checker B站评论区自动标注成分,支持动态和关注识别以及手动输入 UID 识别 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-comment-checker …...
Stable Diffusion VAE重构图像效果不理想?可能是你忘了调整这个关键参数
Stable Diffusion VAE图像重构效果优化指南:关键参数解析与实战调整 当你第一次使用Stable Diffusion的VAE(Variational Autoencoder)进行图像重构时,可能会遇到这样的困惑:明明按照教程一步步操作,为什么输…...
如何快速上手MoMask:面向初学者的3D人体运动生成完整指南
如何快速上手MoMask:面向初学者的3D人体运动生成完整指南 【免费下载链接】momask-codes Official implementation of "MoMask: Generative Masked Modeling of 3D Human Motions (CVPR2024)" 项目地址: https://gitcode.com/gh_mirrors/mo/momask-code…...
ABC系统实战指南:革新数字电路设计的逻辑综合与形式验证技术突破
ABC系统实战指南:革新数字电路设计的逻辑综合与形式验证技术突破 【免费下载链接】abc ABC: System for Sequential Logic Synthesis and Formal Verification 项目地址: https://gitcode.com/gh_mirrors/ab/abc 在现代集成电路设计流程中,工程师…...
Deepfake Offensive Toolkit实战:视频会议系统渗透测试案例
Deepfake Offensive Toolkit实战:视频会议系统渗透测试案例 【免费下载链接】dot The Deepfake Offensive Toolkit 项目地址: https://gitcode.com/gh_mirrors/dot/dot 想要了解如何利用深度伪造技术进行视频会议系统安全测试吗?Deepfake Offensi…...
HP-Socket技术债务管理会议决策记录:选项、理由与结果
HP-Socket技术债务管理会议决策记录:选项、理由与结果 【免费下载链接】HP-Socket High Performance TCP/UDP/HTTP Communication Component 项目地址: https://gitcode.com/gh_mirrors/hp/HP-Socket 作为一款高性能TCP/UDP/HTTP通信组件库,HP-So…...
大数据毕业设计容易的题目答疑
1 引言 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际应用需求ÿ…...
NaViL-9B一文详解:双GPU显存占用分析、服务重启与端口验证
NaViL-9B一文详解:双GPU显存占用分析、服务重启与端口验证 1. 平台概述 NaViL-9B是由专业研究机构开发的原生多模态大语言模型,具备文本问答和图片理解双重能力。该模型在设计上充分考虑了工程落地需求,特别针对双GPU环境进行了优化适配。 …...
开源工具Cowabunga Lite:iOS设备零门槛个性化方案全解析
开源工具Cowabunga Lite:iOS设备零门槛个性化方案全解析 【免费下载链接】CowabungaLite iOS 15 Customization Toolbox 项目地址: https://gitcode.com/gh_mirrors/co/CowabungaLite 在iOS生态系统中,用户对设备个性化的需求与系统封闭性之间始终…...
Wan2.2-I2V-A14B企业落地:汽车4S店车型介绍短视频自动化生产系统
Wan2.2-I2V-A14B企业落地:汽车4S店车型介绍短视频自动化生产系统 1. 项目背景与需求分析 汽车4S店每天需要为不同车型制作大量介绍视频,传统视频制作方式面临三大痛点: 人力成本高:专业视频团队制作单条视频成本约2000-5000元制…...
