今日收获(C语言)

一.文件的打开

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

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

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{FILE* pf = fopen("text.txt", "r");//创建一个FILE类型的指针变量,指向打开的文件text.txtif (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.txtif (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 };//定义结构体变量并初始化为0FILE* 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结构体的成员中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

node.js卸载并重新安装(超详细图文步骤)

卸载node.js 重新安装nodejs 一、卸载 1、首先进入控制面板卸载程序 2、卸载后 到文件夹中进行进一步的删除 删除上述的几个文件夹 每个人可能不一样&#xff0c;总之是找到自己的nodejs安装路径&#xff0c;下面是我的 ①删除C:UsersAdminAppDataRoaming路径下的npm相关文件…

仓颉编程语言:编程世界的 “文化瑰宝”

我的个人主页 在当今编程领域百花齐放的时代&#xff0c;各种编程语言争奇斗艳&#xff0c;服务于不同的应用场景和开发者群体。然而&#xff0c;有这样一种编程语言&#xff0c;它承载着独特的文化内涵&#xff0c;宛如编程世界里一颗熠熠生辉的“文化瑰宝”&#xff0c;那就…

Android使用JAVA调用JNI原生C++方法

1.native-lib.cpp为要生成so库的源码文件 2.JNI函数声明说明 NewStringUTF函数会返回jstring JNI函数声明规则 3.JAVA中声明及调用JNI函数 声明&#xff1a; 调用

DAY178内网渗透之内网对抗:横向移动篇入口差异切换上线IPC管道ATSC任务Impacket套件UI插件

1.内网横向移动 1、横向移动篇-入口点分析-域内域外打点 2、横向移动篇-IPC利用-连接通讯&计划任务, 3、横向移动篇-IPC利用-命令模式&工具套件 1.1 横向移动入口知识点 收集到域内用户和凭据后&#xff0c;为后续利用各种协议密码喷射通讯上线提供条件&#xff0c;…

宠物行业的出路:在爱与陪伴中寻找增长新机遇

在当下的消费市场中&#xff0c;如果说有什么领域能够逆势而上&#xff0c;宠物行业无疑是一个亮点。当人们越来越注重生活品质和精神寄托时&#xff0c;宠物成为了许多人的重要伴侣。它们不仅仅是家庭的一员&#xff0c;更是情感的寄托和生活的调剂。然而&#xff0c;随着行业…

MySQL数据库——索引结构之B+树

本文先介绍数据结构中树的演化过程&#xff0c;之后介绍为什么MySQL数据库选择了B树作为索引结构。 文章目录 树的演化为什么其他树结构不行&#xff1f;为什么不使用二叉查找树&#xff08;BST&#xff09;&#xff1f;为什么不使用平衡二叉树&#xff08;AVL树&#xff09;&a…

大模型—Ollama 结构化输出

Ollama 结构化输出 Ollama现在支持结构化输出,使得可以按照由JSON模式定义的特定格式来约束模型的输出。Ollama的Python和JavaScript库已经更新,以支持结构化输出。 结构化输出的用例包括: 从文档中解析数据从图像中提取数据结构化所有语言模型响应比JSON模式更可靠和一致开…

欧拉计划 Project Euler 35 题解

欧拉计划 Problem 35 题解 题干思路code暴力筛法rotate函数使用语法示例代码 题干 思路 一个很自然的思路就是暴力找&#xff0c;遍历一百万之内的所有数&#xff0c;也可以先把一百万以内所有的素数筛出来然后从中取选。这里我使用的是暴力算法。 code 暴力 #include <…

pytorch基础之注解的使用--003

Title 1.学习目标2.定义3.使用步骤4.结果 1.学习目标 针对源码中出现一些注解的问题&#xff0c;这里专门写一篇文章进行讲解。包括如何自定义注解&#xff0c;以及注意事项&#xff0c;相信JAVA中很多朋友业写过&#xff0c;但是今天写的是Python哦。。。 2.定义 在 Python…

C#编写的金鱼趣味小应用 - 开源研究系列文章

今天逛网&#xff0c;在GitHub中文网上发现一个源码&#xff0c;里面有这个金鱼小应用&#xff0c;于是就下载下来&#xff0c;根据自己的C#架构模板进行了更改&#xff0c;最终形成了这个例子。 1、 项目目录&#xff1b; 2、 源码介绍&#xff1b; 1) 初始化&#xff1b; 将样…

高效搭建Nacos:实现微服务的服务注册与配置中心

一、关于Nacos 1.1 简介 Nacos&#xff08;Dynamic Naming and Configuration Service&#xff09;是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台。它旨在帮助开发者更轻松地构建、部署和管理分布式系统&#xff0c;特别是在微服务架构中。Nacos 提供了简单易用…

112、Qt MSVC编译Qtxlsx

先参考103、QT搭建Excel表环境-使用Qtxlsx库文档&#xff0c;下载xlsx源码以及安装perl环境 并配置VS2019和perl环境变量 Qtxlsx库源码下载&#xff1a;https://github.com/dbzhang800/QtXlsxWriter 解压至非中文路径下 打开Qt自带的MSVC 2019命令框进入文件夹并运行命令生成…

频域滤波为什么使用psf2otf函数?

MATLAB中circshift函数是psf2otf函数的核心&#xff0c;在MATLAB中circshift函数的原理分析——psf2otf函数的核心直观解释了为什么需要循环移位。 MATLAB提出了psf2otf函数&#xff0c;先做循环移位&#xff0c;再计算离散傅里叶变换。如果有空域的卷积核&#xff0c;通过这个…

PySide6 SQLite3 做的 电脑组装报价系统

一、数据库结构说明 1. 配件类别表 (component_categories) 字段名类型说明约束category_idINTEGER类别IDPRIMARY KEY, AUTOINCREMENTcategory_nameTEXT类别名称NOT NULL, UNIQUEdescriptionTEXT类别描述 2. 配件表 (components) 字段名类型说明约束component_idINTEGER配件…

Android 部分操作(待补充

新建的线性布局.xml文件&#xff0c;文件名是 linearlayout.xml&#xff0c;根元素设置LinearLayout&#xff1b; 对于线性布局&#xff0c;调整第一个元素相对于顶部的位置&#xff0c;通过属性 layout_marginTop 设置后调整第一个元素的位置&#xff0c;后边的元素会依次向…

Android笔试面试题AI答之Android基础(7)

Android入门请看《Android应用开发项目式教程》&#xff0c;视频、源码、答疑&#xff0c;手把手教 文章目录 1.Android开发如何提高App的兼容性&#xff1f;**1. 支持多版本 Android 系统****2. 适配不同屏幕尺寸和分辨率****3. 处理不同硬件配置****4. 适配不同语言和地区**…

CSS学习记录21

CSS 工具提示 通过CSS 创建工具提示&#xff08;Tooltip)。 当用户将鼠标指针移动到元素上时&#xff0c;工具提示通常用于提供关于某内容的额外信息&#xff1a; <style> /* Tooltip 容器 */ .tooltip {position: relative;display: inline-block;border-bottom: 1px …

2025经典的软件测试面试题(答案+文档)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 以下是软件测试相关的面试题及答案&#xff0c;希望对各位能有帮助&#xff01; 1、测试分为哪几个阶段? 一般来说分为5个阶段&#xff1a;单元测试、集成测试…

021-spring-springmvc

比较重要的部分 比较重要的部分 比较重要的部分 关于组件的部分 这里以 RequestMappingHandlerMapping 为例子 默认的3个组件是&#xff1a; org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc.method.annotation.Requ…

Facebook 上的社群文化:连接与共享

随着社交媒体的普及&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;不仅改变了人们的沟通方式&#xff0c;还塑造了独特的社群文化。在Facebook上&#xff0c;用户可以轻松地与朋友、家人保持联系&#xff0c;同时也能加入兴趣相投的群组、参与讨论和共享内容。社…