将文件读入C中的字符数组
当您使用 C 编程语言时,您可能会遇到一些需要将文件读入字符数组的问题,例如分析每个字符的频率,或者将所有句子的每个起始词从小写转换为大写,反之亦然。该解决方案非常简单,但对于不太了解文件读取或写入的人来说可能并不那么简单。因此,在这篇文章中,您可以逐步学习如何在 C 中将文件读入字符数组。
在 C 中打开文件
在 C 语言中打开文件的最简单和最流行的方法是使用以下格式的“fopen”函数:
file = fopen(file_name, "open_mode"); //open the "file-name" file and store the file pointer in the variable 'file'
“fopen”函数的模式参数指定打开文件的模式。该模式可以是以下之一:
- “ r ”:打开文件进行读取。
- “ w ”:将文件截断为零长度或创建一个用于写入的文件。
- “ a ”:追加到文件或创建一个文件(如果不存在)进行写入。
- “ r+ ”:打开文件进行读写。
- “ w+ ”:将文件截断为零长度或创建一个用于读写的文件。
- “ a+ ”:追加到文件或创建文件以供读写。
但由于某种原因,该文件可能无法正常打开。为了在发生此类情况时做好准备,您应该始终检查“fopen”函数的返回值,以确保在尝试读取或写入文件之前已成功打开文件。像这样:
// If 'fopen' returns NULL, print an error message and exit the program
if (file == NULL) {printf("Error: Failed to open file '%s'.\n", file_name);return 1;
}
逐字符读取文件内容
在读取文件之前,您必须有一个字符数组来存储文件内容。让我们这样做吧
char buffer[1000]; //Initialize a char array named 'buffer' with size of 1000
现在,是时候使用“fgetc”读取文件了。该函数每次调用都会读取文件中的一个字符,如果重复调用,它将读取后续的每个字符,直到结束。因此,我们可以使用 while 循环来使过程变得更容易。
int i = 0, c; //c is the intermediate variable, i is the increment variable
while ((c = fgetc(file)) != EOF) {//Read contents until it reach the end of the filebuffer[i] = c;i++;
}
上面的示例假设文件仅包含 ASCII 字符,并且文件大小小于 1000 个字符。
可调整大小的缓冲区
我们之前定义的缓冲区数组最多包含 1000 个字符。但在许多情况下,文件大小远大于此。我们可以通过将缓冲区变成可调整大小的缓冲区来解决这个问题。您可以通过 C 标准库提供的“malloc”、“realloc”和“realloc”函数使用动态内存分配。
char *buffer = NULL; // initialize buffer to NULL
int buffer_size = 0;
/*Open the file here*/
// Read file character by character
int c, i = 0;
while ((c = fgetc(file)) != EOF) {// If buffer is full, resize itif (i >= buffer_size) {buffer_size += 1000; // increase buffer size by 1000 bytesbuffer = realloc(buffer, buffer_size); // resize bufferif (buffer == NULL) {printf("Error: Memory allocation failed.\n");return 1;}}buffer[i] = c;i++;
}
我们在上面的代码片段中使用“realloc”函数,这被证明是有用的,因为文件大小通常是事先未知的。对于“malloc”和“calloc”函数,它们可用于将指定大小的内存块分配给变量。在此示例中,您可以像下面这样使用:
buffer = (char*)malloc(1000); //is the same as define char buffer[1000]
在此示例中,您可能不需要使用“malloc”和“calloc”。我们稍后会再次见到他们。
文件包含非 ASCII 字符
在 C 中,字符串表示为字节序列,这些字节的解释取决于字符编码。如果文件包含非 ASCII 字符,则需要使用支持这些字符的字符编码,例如 UTF-8 或 UTF-16。
对于这个问题,您应该使用可以处理多字节字符的函数,例如“fgetwc”和“fgetws”。这些函数一次分别读取一个宽字符 (wchar_t) 或一个宽字符串 (wchar_t*)。
以下是对代码的一些修改,以使其在文件包含非 ASCII 字符时正常工作:
wchar_t buffer[100];
// Open file for reading
file = fopen(filename, "r,ccs=UTF-8");
// Read file contents
wchar_t c;
int i = 0;
while ((c = fgetwc(file)) != WEOF) {buffer[i] = c;i++;
}
另外,请确保输入和输出流设置为正确的编码,以正确显示或操作字符。在 MacOS 和 Linux 等 Unix 操作系统上,为了确保输出编码为 UTF-8,您可以使用 'setlocale' 函数:
#include
int main()
{setlocale(LC_ALL, "en_US.utf8");// your code herereturn 0;
}
在 Windows 上,您可以使用 '_setmode' 和 '_O_U8TEXT' 函数将输出编码设置为 UTF-8:
#include //_O_U8TEXT
#include //_setmode()
int main()
{_setmode(_fileno(stdout), _O_U8TEXT);// your code herereturn 0;
}
以下是包含越南语单词“Xin chào!”的文件示例 (Hello) 带重音符号(非 ASCII 字符),以 UTF-8 编码保存:
Xin chào!
这是我们的程序在在线 C 编译器上运行后的输出:
Xin chào!...Program finished with exit code 0
Press ENTER to exit console.
读取整个文件内容
如果您不熟悉 C,那么您可以跳过此步骤,但我仍然建议将其作为高级练习来阅读。我想介绍另一种方法来解决“如何在 C 中将文件读入字符数组”问题。新的思路是不再逐个字符地读取文件,而是整体读取文件,在读取之前确定文件大小。这是一个更复杂的解决方案,但也更有效。
首先,您应该定义常用变量:用于打开文件的文件指针和用于包含字符数组的缓冲区。请记住,您还需要文件大小:
FILE *fp;
long file_size;
char *buffer;
然后就可以打开文件来读取:
fp = fopen("example.txt", "r");
要了解文件的大小,可以使用“ftell”函数。它将告诉文件指针中当前位置的字节位置:current_byte = ftell(fp);
但是等等,文件读取总是从文件的开头开始。没问题,“fseek”函数会将读取控件移动到文件中的不同位置:
fseek(fp, 0, SEEK_END);
您现在可以正确获取文件大小。之后,我们再次将读取控件设置为开头,开始读取文件内容:
file_size = ftell(fp);
rewind(fp); move the control to the file's beginning// Allocate memory for the char array
buffer = (char*) malloc(file_size + 1);
这里“malloc”函数的使用非常简单:分配内存来创建一个未初始化的 char 数组,其大小为 (file_size+1) 乘以 1 字节(char 类型的大小)。
如果您想使用“calloc”函数,请按以下步骤操作:
buffer = (char*) calloc(file_size + 1, sizeof(char));
“malloc”和“calloc”之间的主要区别在于,“malloc”仅分配内存而不初始化其内容,而“calloc”既分配内存又将内存初始化为零。使用“calloc”的主要优点是分配的内存已经被清零,如果您打算稍后将 char 数组用作字符串,这会很有帮助。
// Read the file into the char array
fread(buffer, file_size, 1, fp);
创建缓冲区后,您可以使用“fread”函数读取整个文件,该函数获取文件指针、要读取的每个元素的大小、要读取的元素的数量以及目标数组。
// Add a null terminator at the end of the char array
buffer[file_size] = '\0';
您可能想知道为什么需要为“缓冲区”分配额外的字节。为什么不只是(file_size)而是(file_size + 1)?在这里,将在 char 数组的末尾添加 null 终止符,以指示字符串的结束。实际上,如果您唯一的任务是将文件读入数组,那么这一步是不必要的。但稍后如果您想将此数组打印为字符串,那么这是一个要求。C 中的字符串被定义为将最后一个字符作为空终止符“\0”。
清理你的代码
您已经打开并使用了该文件,因此请记住随后将其关闭。只需使用“fclose”函数来释放您分配的“文件”指针变量。
fclose(file);
谈到释放指针,还记得用来存储字符的“缓冲区”数组吗?如果您将其定义为已分配的内存(指针),那么最好立即释放它以避免内存泄漏。
free(buffer);
以下是您的解决方案的概述:
#include
#include int main() {FILE *file;char filename[] = "example.txt";char *buffer = NULL; // initialize buffer to NULLint buffer_size = 0;int i = 0;//Open file for readingfile = fopen(filename, "r");//Check if file opened successfullyif (file == NULL) {printf("Error: Failed to open file '%s'.\n", filename);return 1;}// Read file character by characterint c;while ((c = fgetc(file)) != EOF) {// If buffer is full, resize itif (i >= buffer_size) {buffer_size += 1000; // increase buffer size by 1000 bytesbuffer = realloc(buffer, buffer_size); // resize bufferif (buffer == NULL) {printf("Error: Memory allocation failed.\n");return 1;}}buffer[i] = c;i++;}// Close filefclose(file);// Print the character arrayprintf("%s", buffer);// Free the dynamically allocated bufferfree(buffer);return 0;
}
相关文章:
将文件读入C中的字符数组
当您使用 C 编程语言时,您可能会遇到一些需要将文件读入字符数组的问题,例如分析每个字符的频率,或者将所有句子的每个起始词从小写转换为大写,反之亦然。该解决方案非常简单,但对于不太了解文件读取或写入的人来说可能…...

不小心删除了短信,如何在 Android 上恢复已删除的短信
不小心删除了文字消息在 Android 手机上使用可能会是一种令人痛苦的体验。这些消息可能包含有价值的信息、珍贵的回忆或重要的细节。幸运的是,您可以探索多种方法来恢复这些丢失的消息。在本文中,我们将深入研究可用于检索已删除短信的选项,并…...

Java电子招投标采购系统源码-适合于招标代理、政府采购、企业采购、等业务的企业
项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及审…...

springBoot的实现原理;SpringBoot是什么;使用SpringBoot的核心功能;springBoot核心注解以及核心配置文件
文章目录 springBootspringBoot的实现原理什么是 Spring Boot?SpringBoot是什么为什么要使用springBootSpring Boot的核心功能Spring Boot 主要有如下优点: SpringBoot启动过程-流程Spring Boot 的核心注解是哪个?什么是 JavaConfigÿ…...
logback-spring.xml详解
《springboot使用logback日志框架超详细教程》文中,filter中最重要的两个过滤器LevelFilter(日志级别精确匹配)、ThresholdFilter(阈值过滤) 的描述非常准确: springboot使用logback日志框架超详细教程_sp…...
【Python】nn.BCEWithLogitsLoss函数详解
nn.BCEWithLogitsLoss() 是 PyTorch 中一个用于二元分类问题的损失函数,它结合了 Sigmoid 层(将输出映射到 [0,1] 范围内)和 Binary Cross Entropy(BCE)损失。这可以避免在正向和反向传播过程中可能出现梯度爆炸或梯度…...
【C++】日期类的实现
在上篇博客中我们已经学习了C中的运算符重载,我们说,操作符只能对于内置类型进行操作,对自定义类型我们需要自己定义函数去实现一系列的操作 那么这篇博客我们就专门把日期这个类单独拿出来写一下它都有哪些有意义的可以重载的运算符…...

带残差连接的ResNet18
目录 1 模型构建 1.1 残差单元 1.2 残差网络的整体结构 2 没有残差连接的ResNet18 2.1 模型训练 2.2 模型评价 3 带残差连接的ResNet18 3.1 模型训练 3.2 模型评价 4 与高层API实现版本的对比实验 总结 残差网络(Residual Network,ResNet)…...

【深入解析git和gdb:版本控制与调试利器的终极指南】
【本节目标】 1. 掌握简单gdb使用于调试 2. 学习 git 命令行的简单操作, 能够将代码上传到 Github 上 1.Linux调试器-gdb使用 1.1.背景 程序的发布方式有两种,debug模式和release模式release模式不可被调试,debug模式可被调试Linux gcc/g出来的二进制…...

CGAN原理讲解与源码
1.CGAN原理 生成器,输入的是c和z,z是随机噪声,c是条件,对应MNIST数据集,要求规定生成数字是几。 输出是生成的虚假图片。 生成器生成的图片被判别器认为是真实图片,那么标签就是1 其实判别器模型输出的是…...

C#实体类与XML互转以及List和DataTable转XML的使用
引言 在C#开发中,数据的存储和传输是非常常见的需求。使用XML作为数据格式有很多优点,例如可读性强、易于解析等。而实体类、List和DataTable是表示数据模型的常用方式。本文将介绍如何在C#中实现实体类、List和DataTable与XML之间的相互转换,…...
uniapp的vue3的模版的setup函数内使用uniapp内置方法
vue2使用方式直接在method同级使用就行,但是在vue3的setup函数内直接使用会报错,本人找了好久,发现vue3需要导入uniapp模块才能使用,具体如下 使用uniapp上拉加载更多方法 <script>import {onReachBottom} from dcloudio/uni-apponReachBottom(() > {console.log(&qu…...
UI自动化的基本知识
一、UI自动化测试介绍 1、什么是自动化测试 概念:由程序代替人工进行系统校验的过程 1.1自动化测试能解决的问题? 回归测试 (冒烟测试) 针对之前老的功能进行测试 通过自动化的代码来实现。 针对上一个版本的问题的回归 兼容性测试 web实例化不同的浏…...

python实现C++简易自动压行
突发奇想,想要将自己的c压行之后交上去。但是苦于手动压行效率太低,在网上搜索压行网站没有找到,突然发现压行不就是检查检查去个换行符吗。于是心血来潮,用python实现了一个简易压行程序。 首先,宏定义等带#的文件不…...

京东数据分析(京东大数据采集):2023年线上珍珠市场销售数据采集
在珠宝首饰市场,从黄金到钻石,如今年轻人的新风潮又转向了珍珠。珍珠热潮并非刚刚兴起,早在前两年,抖音、快手等短视频台的珍珠开蚌直播内容,就掀起了一波珍珠热潮。 此后,随着珍珠饰品被越来越多社交平台的…...

亚信科技AntDB数据库与库瀚存储方案完成兼容性互认证
近日,亚信科技AntDB数据库与苏州库瀚信息科技有限公司自主研发的RISC-V数据库存储解决方案进行了产品兼容测试。经过双方团队的严格测试,亚信科技AntDB数据库与库瀚数据库存储解决方案完全兼容、运行稳定。除高可用性测试外,双方进一步开展TP…...

现代C++之万能引用、完美转发、引用折叠
现代C之万能引用、完美转发、引用折叠 0.导语1.问题引入2.引入万能引用3.万能引用出现场合4.理解左值与右值4.1 精简版4.2 完整版4.3 生命周期延长4.4 生命周期延长应用5.区分万能引用6.表达式的左右值性与类型无关7.引用折叠和完美转发7.1 引用折叠之本质细节7.2 示例与使用7.…...

ELK日志收集系统-filbeat
filebeat日志收集工具 elk:filebeat日志收集工具和logstash相同 filebeat是一个轻量级的日志收集工具,所使用的系统资源比logstash部署和启动时使用的资源要小的多 filebeat可以运行在非Java环境,它可以代理logstash在非java环境上收集日志…...

Python小知识
个人学习笔记,用于记录使用过程中好用的技巧、好用的库。 1 小知识 1.1 相对路径 1.2 打包Exe文件 命令: pyinstaller -F main.py其中-F:覆盖之前打包的文件 mian.py:需要打包的Python文件 PS:使用pyinstaller 5.1…...

如何在Ubuntu系统上安装Redis
Redis的下载 Redis安装包分为windows版和Linux版当前示例中介绍的是Linux版本Linux的下载地址:Index of /releases/ (redis.io)本次下载的压缩包为:redis-6.2.14.tar.gzRedis的安装 将压缩包通过ssh远程工具上传到Linux服务器中解压压缩包 tar -zxvf red…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...