今日收获(C语言)

一.文件的打开

有这样一个结构体,它内部是文件信息区,文件信息区中的变化可以影响到硬盘中的数据。这个结构体的名字是FILE。我们如果想要写代码对文件进行各种操作,就需要一个指向文件信息区的指针,这个指针的类型是FILE*,通过它就可以间接对硬盘中的数据进行各种操作。

打开文件需要用到fopen函数,同时还需要确定打开方式,代码如下:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//创建一个FILE类型的指针变量,指向打开的文件text.txt
	if (pf == NULL) //如果文件不存在,即pf为空指针
	{
		printf("%s", strerror(errno));
		return 1;
	}
	return 0;
}

其中printf("%s", strerror(errno));是用来打印错误信息的,要引用string.h和erron.h两个头文件。

还有一种打印错误信息的方法:

perror("fopen");

这样写不用引用string.h和erron.h两个头文件,结果会错误信息打印出来并且在前面加上“fopen:”。

常用的打开方式分为6种:

“r”:以“只读”的方式打开文件,只能从文件中读取数据。

“w”:以“只写”的方式打开文件,只能从文件中写入数据,并且每次打开时都会把所有数据清空。

有一点要注意:如果文件并不存在,以“w”方式打开时会自动创建新文件。

“a”:以“只写”的方式打开文件,可以在之前的数据后追加。

在它们的后面加上“b”,rb,wb,ab就是以二进制的形式读,写,追加数据。

二.文件的关闭

关闭文件要用到fclose函数,用法如下:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//创建一个FILE类型的指针变量,指向打开的文件text.txt
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
    fclose(pf);//关闭文件
    pf=NULL;   //为防止pf成为野指针,将其赋为空指针
	return 0;
}

三.文件的常规读写

fputc和fgetc函数:

fputc函数用于将单个字符写入文件,一般是从键盘获取字符。这里可能有些让人疑惑,在以往的经验中,put应该是用于输出的,但这里似乎是“输入”。其实,可以把它理解成:从键盘中输入数据,输出到文件中,又称“写入”。用法如下:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");  //注意这里是“只写”的形式
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	fputc('a', pf);  //把字符a写入pf指向的文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

写入一串字符串也是没问题的:

char i = 0;
for (i = 'a';i <= 'z';i++)
{
	fputc(i, pf);
}

fgetc函数用于将字符从文件中读出,在以往的经验中get似乎是用来输出的,这里可以理解为把字符从文件中输出(读出)。用法如下:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//注意这里是“只读”的形式
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	char ch = 0;
	ch = fgetc(pf);     //从文件中读出一个字符,存到ch里
	printf("%c", ch);   //输出读到的字符
	fclose(pf);
	pf = NULL;
	return 0;
}

读出一串字符串也是没问题的:

char ch = 0;
while ((ch = fgetc(pf)) != EOF)//直到没有字符才停止
{
	printf("%c ", ch);
}

fputs和fgets函数

它们和上面的fputc,fgetc很像,只是把“c”变成了“s”,c代表单个字符,s代表字符串。所以它们分别用来向文件中写入或从文件中读出字符串。用法如下:

fputs:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	fputs("abcdef", pf);//将“abcdef”写入文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

fgets和fputs不同,它有三个参数。分别是:地址(用来存从文件中读出的数据),最大读取字符个数(一般是数组的大小)和输入流。用法如下:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	char arr[20] = { 0 };
	fgets(arr, 20, pf);
	puts(arr);
	fclose(pf);
	pf = NULL;
	return 0;
}

fprintf和fscanf函数

这两个函数专门用于格式化数据处理,fprintf可以理解为向文件中打印数据,即“写入”;fscanf可以理解为从文件中输出数据,即“读出”。

用法如下:

fprintf:

#include<stdio.h>
struct stu   //创建一个结构体
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { "zhangsan",23 };//定义结构体变量并初始化
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fprintf(pf, "%s %d", s.name, s.age);
	fclose(pf);
	pf = NULL;
	return 0;
}

对比printf,fprintf多了一个参数:

fprintf(pf, "%s %d", s.name, s.age);

第一个参数是输出流(决定了应该把数据打印到哪里),第三个是要写入的数据,第二个参数是它们的格式。

fscanf:

把上面的代码稍微修改一下:

#include<stdio.h>
struct stu   //创建一个结构体
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { 0 };//定义结构体变量并初始化为0
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fscanf(pf, "%s %d", s.name, &s.age);//name本身是字符串数组名,不用取地址
	printf("%s %d", s.name, s.age);
	fclose(pf);
	pf = NULL;
	return 0;
}

fscanf第一个参数是输入流(决定了从哪里读取数据),第三个是用来存放读出的数据的地址,第二个是它们的格式。

fread和fwrite函数

这两个函数专门用来进行二进制的读写数据,如果以二进制的形式写入数据,就一定要以二进制的形式读出。用法如下:

fwrite:

#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { "zhangsan",34 };
	FILE* pf = fopen("text.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fwrite(&s, sizeof(struct stu), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

fwrite有四个参数:需要被写入的数据所在的地址,每个数据的字节大小,写入的数据的数量,输出流。(如果是结构体,就以结构体为单位)。

fread:

#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { 0 };
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fread(&s, sizeof(struct stu), 1, pf);
	printf("%s %d", s.name, s.age);
	fclose(pf);
	pf = NULL;
	return 0;
}

fread也有四个参数:用来存放读出的数据的地址,每个数据的字节大小,读出的数据的数量,输入流。

四.标准输入流和标准输出流

在上面的函数参数中出现了输入流,输出流这种陌生的概念,下面来解释一下:

标准输入流:FILE* stdin。标准输出流:FILE* stdout 。

所谓“标准”,其实就是键盘和屏幕。标准输入流是键盘(从键盘读取数据),标准输出流是屏幕(将数据输出(打印)到屏幕上)。去掉“标准”,输入流和输出流也可以是指向文件的指针,可以从文件中读取数据而非键盘,可以将数据输出(打印)到文件中而非屏幕。

还记得上面这串代码吗:

fprintf(pf, "%s %d", s.name, s.age);

如果我把它改一下:

fprintf(stdout , "%s %d", s.name, s.age);

它就不会把数据打印(写入)文件中,而是直接打印在屏幕上,因为我第一个参数用的是标准输出流。

再看这串代码:

fgets(arr, 20, pf);

这是在从文件中读取一串字符存到数组arr中。

但是如果我改一下:

fgets(arr, 20, stdin);

现在它就变成从键盘中读取一串字符存到数组arr中了,因为我把第三个参数改成了标准输入流。

实际上,与文件无关的代码也经常会用到fgets函数来读取字符串,因为它比gets函数安全。

五.文件的随机读写

正常情况下,读取文件数据总是从第一个字符开始的,但有些时候我们更想从某一个位置或末尾读取数据。这时候就要用到fseek,ftell 和 rewind 函数了。

fseek

首先搞明白3个概念:SEEK_SET(起始位置),SEEK_CUR(当前位置),SEEK_END(末尾)。

它们分别被宏定义为0(起始),1(当前位置),2(末尾)。

看下面的代码:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, 2, SEEK_SET);
	char ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

如果我文件里存的是“abcdefg”,那输出的结果应该是 c。

fseek一共有3个参数,第一个参数是文件指针(不要理解成"流"),第三个参数代表是从哪一个位置开始,第二个参数是偏移位置。

在上面的代码中,想象有一个“指针”,起始位置是a,往后偏移两位就指向了c,所以此时输出的就是c。

如果想让文件中的“指针”以现在的位置为起点继续偏移,只需要将SEEK_SET改成SEEK_CUR就可以了。

再看下面的代码:

这回从末尾开始偏移。

往左偏移相当于是反方向,偏移距离要用负数。

这两个结果其实是有些让人疑惑的:文件里存的是“abcdefg”,假如末尾指向的是 f,那往左偏移2个距离得到的应该是 e,但输出的居然是 f !下面用一张画明白:

第二个结果是“g”,这是因为输出 f 后“箭头”自动向后面移动了 1位。

ftell:

如果我想知道现在箭头离起始位置有多远,就要用到ftell函数了。

如果在上面代码的基础上加上

printf("%d", ftell(pf));

那输出的结果应该是7,因为此时箭头指向末尾。

rewind:

如果我突然想让箭头回到起始位置,就可以用到这个函数。用法如下:

rewind(pf);

六.sprintf和sscanf函数:

sprintf用于把格式化的数据转换成字符串,用法如下:

#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { "zhangsan",23 };
	char buf[100] = { 0 };
	sprintf(buf, "%s %d", s.name, s.age);//把name和age这两个数据全部转换成字符串,存到buf里
	printf("%s", buf);
	return 0;
}

虽然输出结果还是“zhangsan 23”,但这已经变成一个字符串了。

sscanf可以从字符串中转换出格式化的数据,用法如下:

#include<stdio.h>
struct stu
{
	char name[20];
	int age;
};
int main()
{
	struct stu s = { "zhangsan",23 };
	char buf[100] = { 0 };
	sprintf(buf, "%s %d", s.name, s.age);
	struct stu tmp = { 0 };//再定义一个结构体变量
	sscanf(buf, "%s %d", tmp.name, &tmp.age);
	printf("%s %d", tmp.name, tmp.age);
	return 0;
}

从字符串中转换出格式化的数据,存到tmp结构体的成员中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945290.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】九九乘法表编程题详解与多角度对比分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目概述题目描述 &#x1f4af;老师的实现方法代码解析优点不足 &#x1f4af;我的实现方法代码解析优点不足 &#x1f4af;实现方法对比&#x1f4af;优化与扩展代码优化…

RK3568 bsp 9 - USB调试记录

文章目录 1、环境介绍2、RK3568 USB资源介绍3、配置目标4、dts配置4.1、USB3.0 OTG4.2、USB2.0 Host 2 和 USB2.0 Host 3 5、kernel配置5.1、USB PHY CONFIG5.2、USB Host CONFIG5.3、USB OTG CONFIG5.4、USB外设CONFIG5.4.1、Mass Storage Class CONFIG5.4.2、USB HID CONFIG …

图像描述/字幕开源模型与数据集全览

图像描述/字幕&#xff08;Image Captioning&#xff09;是用文字描述图像内容的任务&#xff0c;属于计算机视觉和自然语言处理的交叉领域。大多数图像描述系统采用编码器-解码器&#xff08;encoder-decoder&#xff09;框架&#xff0c;其中输入图像被编码为中间表示形式&am…

mongodb(6.0.15)安装注意事项,重装系统后数据恢复

window10系统 上周重装了系统&#xff0c;环境变量之类的都没有了。现在要恢复。 我电脑里之前的安装包没有删除&#xff08;虽然之前也没在C盘安装&#xff0c;但是找不到了&#xff0c;所以需要重新下载安装&#xff09;&#xff0c;长下图这样。这个不是最新版本&#xff0…

Redis单线程快的原因

基于内存操作&#xff1a;Redis将数据存储在内存中&#xff0c;使得数据的读写速度极快&#xff0c;这是其性能优势的主要原因。单线程避免上下文切换&#xff1a;在多线程环境下&#xff0c;CPU核数有限&#xff0c;线程上下文切换会带来性能损耗。Redis采用单线程&#xff0c…

IOS safari 播放 mp4 遇到的坎儿

起因 事情的起因是调试 IOS 手机下播放服务器接口返回的 mp4 文件流失败。对于没调试过移动端和 Safari 的我来说着实费了些功夫&#xff0c;网上和AI也没有讲明白。好在最终大概理清楚了&#xff0c;在这里整理出来供有缘人参考。 问题 因为直接用 IOS 手机的浏览器打开页面…

import org.springframework.data.jpa.repository.JpaRepository<T, ID>;

org.springframework.data.jpa.repository.JpaRepository<T, ID> 接口中的 ID 类型参数。 理解 JpaRepository<T, ID> 中的 T 和 ID&#xff1a; T (Type): T 代表的是你想要操作的 实体类 的类型。例如&#xff0c;如果你有一个名为 User 的实体类&#xff0c;那…

Ubuntu网络配置(桥接模式, nat模式, host主机模式)

windows上安装了vmware虚拟机&#xff0c; vmware虚拟机上运行着ubuntu系统。windows与虚拟机可以通过三种方式进行通信。分别是桥接模式&#xff1b;nat模式&#xff1b;host模式 一、桥接模式 所谓桥接模式&#xff0c;也就是虚拟机与宿主机处于同一个网段&#xff0c; 宿主机…

RT-DETR融合[CVPR2020]EfficientDet中的BiFPN结构

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《EfficientDet: Scalable and Efficient Object Detection》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/1911.09070 代码链接&#xff1a;https://github.com/…

Unity 实现Canvas显示3D物体

新建一个UI相机&#xff0c;选择渲染层为UI 将主相机的渲染层去掉UI层 、 将Canvas的RenderMode设置为Screen Space - Camera,将RenderCamera设置为UI相机 新建3D物体的UI父物体&#xff0c;并将3D物体的层级设置为UI层 适当的放缩3DObjParent&#xff0c;让3D物体能显示出来…

RabbitMQ基础篇之Java客户端快速入门

文章目录 需求 项目设置与依赖管理 配置RabbitMQ的连接信息创建队列与消息发送创建消费者&#xff08;消息接收&#xff09;环境准备与操作 需求 利用控制台创建队列 simple.queue在 publisher 服务中&#xff0c;利用 SpringAMQP 直接向 simple.queue 发送消息在 consumer 服…

解决SecureCRT登录后无法用Tab键补齐命令

解决SecureCRT登录后无法用Tab键补齐命令 打开SecureCRT软件&#xff0c;选项—全局选项—常规—默认的会话设置—编辑默认的设置—连接—-右侧的协议选择为Telnet &#xff1b;在左侧&#xff0c;选择telnet&#xff0c;在右侧的高级框里“强制每次一个字符模式”勾上&#x…

音视频入门基础:MPEG2-TS专题(23)——通过FFprobe显示TS流每个packet的信息

音视频入门基础&#xff1a;MPEG2-TS专题系列文章&#xff1a; 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;1&#xff09;——MPEG2-TS官方文档下载 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;2&#xff09;——使用FFmpeg命令生成ts文件 音视频入门基础…

运行python程序报错 undefined symbol: ffi_type_uint32 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 ROS-Noetic 一、问题描述 运行 python 程序出现如下问题&#xff1a; Traceback (most recent call last):File "<string>", line 1, in <module&…

go 模拟TCP粘包和拆包,及解决方法

1. 什么是 TCP 粘包与拆包&#xff1f; 粘包&#xff08;Sticky Packet&#xff09; 粘包是指在发送多个小的数据包时&#xff0c;接收端会将这些数据包合并成一个数据包接收。由于 TCP 是面向流的协议&#xff0c;它并不会在每次数据发送时附加边界信息。所以当多个数据包按顺…

Day10补代码随想录 理论基础|232.用栈实现队列|225.用队列实现栈|20.有效的括号|1047.删除字符串中的所有相邻重复项

栈和队列理论基础 抽象认识 栈是先进后出(FIFO)&#xff0c;队列是先进先出(LIFO) 队首(先进))队尾(后进)栈顶(后进)栈底(先进) 栈(Stack) 只在一端进行进出操作(只在一端进一端出)像个篮球框&#xff0c;取用篮球从一端进出。 /进栈 int a[1000];//足够大的栈空间 int top-1…

Gemma2 2B 模型的model.safetensors.index.json文件解析

Gemma2 2B 模型的 model.safetensors.index.json 文件解析 在使用 Gemma2 2B 模型或其他大型预训练模型时&#xff0c;model.safetensors.index.json 文件起到了索引的作用&#xff0c;它帮助我们了解模型的结构、参数存储方式以及如何加载模型的具体权重。本博客将深入解析该…

大模型系列——旋转位置编码和长度外推

绝对位置编码 旋转位置编码 论文中有个很直观的图片展示了旋转变换的过程&#xff1a; 对于“我”对应的d维向量&#xff0c; 拆分成d/2组以后&#xff0c;每组对应一个角度&#xff0c;若1对应的向量为(x1,x2)&#xff0c;应用旋转位置编码&#xff0c;相当于这个分量旋转了m…

网络安全威胁2024年中报告

下载地址&#xff1a; 网络安全威胁2024年中报告-奇安信

Momentum Contrast for Unsupervised Visual Representation Learning论文笔记

文章目录 论文地址动量队列对比学习的infoNCE loss为什么需要动量编码器对比学习moco方法中的动量Encoder为什么不能与梯度Encoder完全相同为什么动量编码器和梯度编码器不能完全相同&#xff1f;总结&#xff1a; 我理解&#xff0c;正负样本应该经过同一个encoder&#xff0c…