【转载】C语言入门到精通,这一篇就够了(13万字笔记)7
本文最后更新于 97 天前,其中的信息可能已经过时,如有错误请发送邮件到 shikeAB@outlook.com。

【转载】C 语言入门到精通,这一篇就够了(13 万字笔记)7

一次读写一行字符

  • 什么是行
  • 行是文本编辑器中的概念,文件流中就是一个字符。这个在不同的平台是有差异的。window 平台 ‘\r\n’,linux 平台是’\n’
  • 平台差异
    • windows 平台在写入’\n’是会体现为’\r\n’,linux 平台在写入’\n’时会体现为’\n’。windows 平台在读入’\r\n’时,体现为一个字符’\n’,linux 平台在读入’\n’时,体现为一个字符’\n’
    • linux 读 windows 中的换行,则会多读一个字符,windows 读 linux 中的换行,则没有问题
#include
int main()
{
FILE *fw = fopen("test.txt", "w+");
fputc('a', fw);
fputc('\n', fw);
fputc('b', fw);
fclose(fw);
return 0;
}


  • 写入一行
函数声明 int fputs(char *str,FILE *fp)
所在文件 stdio.h
函数功能 把 str 指向的字符串写入 fp 指向的文件中。
参数及返回解析
参数 char * str : 表示指向的字符串的指针。
参数 FILE *fp : 指向文件流结构的指针。
返回值 int 正常,返 0;出错返 EOF。
#include
int main()
{
FILE *fw = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fw);
fputs("it666\n", fw);
fclose(fw);
return 0;
}
  • 遇到 \0 自动终止写入
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs写入时遇到\0就会自动终止写入
fputs("lnj\0it666\n", fp);
fclose(fp);
return 0;
}

  • 读取一行
函数声明 char *fgets(char *str,int length,FILE *fp)
所在文件 stdio.h
函数功能 从 fp 所指向的文件中,至多读 length-1 个字符,送入字符数组 str 中, 如果在读入 length-1 个字符结束前遇 \n 或 EOF,读入即结束,字符串读入后在最后加一个‘\0’字符。
参数及返回解析
参数 char * str : 指向需要读入数据的缓冲区。
参数 int length : 每一次读数字符的字数。
参数 FILE* fp : 文件流指针。
返回值 char * 正常,返 str 指针;出错或遇到文件结尾 返空指针 NULL。
  • 最多只能读取 N-1 个字符
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("it666\n", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 从fp中读取4个字符, 存入到str中
// 最多只能读取N-1个字符, 会在最后自动添加\0
fgets(str, 4, fp);
printf("str = %s", str); // it6
fclose(fp);
return 0;
}
  • 遇到 \n 自动结束
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fp);
fputs("it666\n", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 从fp中读取1024个字符, 存入到str中
// 但是读到第4个就是\n了, 函数会自动停止读取
// 注意点: \n会被读取进来
fgets(str, 1024, fp);
printf("str = %s", str); // lnj
fclose(fp);
return 0;
}
  • 读取到 EOF 自动结束
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("lnj\n", fp);
fputs("it666", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 每次从fp中读取1024个字符, 存入到str中
// 读取到文件末尾自动结束
while(fgets(str, 1024, fp)){
printf("str = %s", str);
}
fclose(fp);
return 0;
}
  • 注意点:
    • 企业开发中能不用 feof 函数就不用 feof 函数
    • 如果最后一行,没有行‘\n’的话则少读一行
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
// 注意: fputs不会自动添加\n
fputs("12345678910\n", fp);
fputs("12345678910\n", fp);
fputs("12345678910", fp);
// 将FILE结构体中的读写指针重新移动到最前面
// 注意: FILE结构体中读写指针每读或写一个字符后都会往后移动
rewind(fp);
char str[1024];
// 每次从fp中读取1024个字符, 存入到str中
// 读取到文件末尾自动结束
while(fgets(str, 1024, fp) && !feof(fp)){
printf("str = %s", str);
}
fclose(fp);
return 0;
}
  • 作业:
    • 利用 fgets (str, 5, fp) 读取下列文本会读取多少次?
12345678910
12345
123

一次读写一块数据

  • C 语言己经从接口的层面区分了,文本的读写方式和二进制的读写方式。前面我们讲的是文本的读写方式。
  • 所有的文件接口函数,要么以 ‘\0’,表示输入结束,要么以 ‘\n’, EOF (0xFF) 表示读取结束。 ‘\0’ ‘\n’ 等都是文本文件的重要标识,而所有的二进制接口对于这些标识,是不敏感的。
    + 二进制的接口可以读文本,而文本的接口不可以读二进制
  • 一次写入一块数据
函数声明 int fwrite(void *buffer, int num_bytes, int count, FILE *fp)
所在文件 stdio.h
函数功能 把 buffer 指向的数据写入 fp 指向的文件中
参数 char * buffer : 指向要写入数据存储区的首地址的指针
int num_bytes: 每个要写的字段的字节数 count
int count : 要写的字段的个数
FILE* fp : 要写的文件指针
返回值 int 成功,返回写的字段数;出错或文件结束,返回 0。
#include
#include
int main()
{
FILE *fp = fopen("test.txt", "wb+");
// 注意: fwrite不会关心写入数据的格式
char *str = "lnj\0it666";
/*
* 第一个参数: 被写入数据指针
* 第二个参数: 每次写入多少个字节
* 第三个参数: 需要写入多少次
* 第四个参数: 已打开文件结构体指针
*/
fwrite((void *)str, 9, 1, fp);
fclose(fp);
return 0;
}
  • 一次读取一块数据
函数声明 int fread(void *buffer, int num_bytes, int count, FILE *fp)
所在文件 stdio.h
函数功能 把 fp 指向的文件中的数据读到 buffer 中。
参数 char * buffer : 指向要读入数据存储区的首地址的指针
int num_bytes: 每个要读的字段的字节数 count
int count : 要读的字段的个数
FILE* fp : 要读的文件指针
返回值 int 成功,返回读的字段数;出错或文件结束,返回 0。
#include
int main()
{
// test.txt中存放的是"lnj\0it666"
FILE *fr = fopen("test.txt", "rb+");
char buf[1024] = {0};
// fread函数读取成功返回读取到的字节数, 读取失败返回0
/*
* 第一个参数: 存储读取到数据的容器
* 第二个参数: 每次读取多少个字节
* 第三个参数: 需要读取多少次
* 第四个参数: 已打开文件结构体指针
*/
int n = fread(buf, 1, 1024, fr);
printf("%i\n", n);
for(int i = 0; i < n; i++){
printf("%c", buf[i]);
}
fclose(fr);
return 0;
}
  • 注意点:
  • 读取时 num_bytes 应该填写读取数据类型的最小单位,而 count 可以随意写
  • 如果读取时 num_bytes 不是读取数据类型最小单位,会引发读取失败
  • 例如:存储的是 char 类型 6C 6E 6A 00 69 74 36 36 36
    如果 num_bytes 等于 1, count 等于 1024, 那么依次取出 6C 6E 6A 00 69 74 36 36 36 , 直到取不到为止
    如果 num_bytes 等于 4, count 等于 1024, 那么依次取出 [6C 6E 6A 00][69 74 36 36] , 但是最后还剩下一个 36, 但又不满足 4 个字节,那么最后一个 36 则取不到
#include
#include
int main()
{
// test.txt中存放的是"lnj\0it666"
FILE *fr = fopen("test.txt", "rb+");
char buf[1024] = {0};
/*
while(fread(buf, 4, 1, fr) > 0){
printf("%c\n", buf[0]);
printf("%c\n", buf[1]);
printf("%c\n", buf[2]);
printf("%c\n", buf[3]);
}
*/
/*
while(fread(buf, 1, 4, fr) > 0){
printf("%c\n", buf[0]);
printf("%c\n", buf[1]);
printf("%c\n", buf[2]);
printf("%c\n", buf[3]);
}
*/
while(fread(buf, 1, 1, fr) > 0){
printf("%c\n", buf[0]);
}
fclose(fr);
return 0;
}
  • 注意: fwrite 和 fread 本质是用来操作二进制的
  • 所以下面用法才是它们的正确打开姿势
#include
int main()
{
FILE *fp = fopen("test.txt", "wb+");
int ages[4] = {1, 3, 5, 6};
fwrite(ages, sizeof(ages), 1, fp);
rewind(fp);
int data;
while(fread(&data, sizeof(int), 1, fp) > 0){
printf("data = %i\n", data);
}
return 0;
}

读写结构体

  • 结构体中的数据类型不统一,此时最适合用二进制的方式进行读写
  • 读写单个结构体
#include
typedef struct{
char *name;
int age;
double height;
} Person;
int main()
{
Person p1 = {"lnj", 35, 1.88};
// printf("name = %s\n", p1.name);
// printf("age = %i\n", p1.age);
// printf("height = %lf\n", p1.height);
FILE *fp = fopen("person.stu", "wb+");
fwrite(&p1, sizeof(p1), 1, fp);
rewind(fp);
Person p2;
fread(&p2, sizeof(p2), 1, fp);
printf("name = %s\n", p2.name);
printf("age = %i\n", p2.age);
printf("height = %lf\n", p2.height);
return 0;
}
  • 读写结构体数组
#include
typedef struct{
char *name;
int age;
double height;
} Person;
int main()
{
Person ps[] = {
{"zs", 18, 1.65},
{"ls", 21, 1.88},
{"ww", 33, 1.9}
};
FILE *fp = fopen("person.stu", "wb+");
fwrite(&ps, sizeof(ps), 1, fp);
rewind(fp);
Person p;
while(fread(&p, sizeof(p), 1, fp) > 0){
printf("name = %s\n", p.name);
printf("age = %i\n", p.age);
printf("height = %lf\n", p.height);
}
return 0;
}
  • 读写结构体链表
#include
#include
typedef struct person{
char *name;
int age;
double height;
struct person* next;
} Person;
Person *createEmpty();
void insertNode(Person *head, char *name, int age, double height);
void printfList(Person *head);
int saveList(Person *head, char *name);
Person *loadList(char *name);
int main()
{
// Person *head = createEmpty();
// insertNode(head, "zs", 18, 1.9);
// insertNode(head, "ls", 22, 1.65);
// insertNode(head, "ws", 31, 1.78);
// printfList(head);
// saveList(head, "person.list");
Person *head = loadList("person.list");
printfList(head);
return 0;
}
/**
* @brief loadList 从文件加载链表
* @param name 文件名称
* @return 加载好的链表头指针
*/
Person *loadList(char *name){
// 1.打开文件
FILE *fp = fopen(name, "rb+");
if(fp == NULL){
return NULL;
}
// 2.创建一个空链表
Person *head = createEmpty();
// 3.创建一个节点
Person *node = (Person *)malloc(sizeof(Person));
while(fread(node, sizeof(Person), 1, fp) > 0){
// 3.进行插入
// 3.1让新节点的下一个节点 等于 头节点的下一个节点
node->next = head->next;
// 3.2让头结点的下一个节点 等于 新节点
head->next = node;
// 给下一个节点申请空间
node = (Person *)malloc(sizeof(Person));
}
// 释放多余的节点空间
free(node);
fclose(fp);
return head;
}
/**
* @brief saveList 存储链表到文件
* @param head 链表头指针
* @param name 存储的文件名称
* @return 是否存储成功 -1失败 0成功
*/
int saveList(Person *head, char *name){
// 1.打开文件
FILE *fp = fopen(name, "wb+");
if(fp == NULL){
return -1;
}
// 2.取出头节点的下一个节点
Person *cur = head->next;
// 3.将所有有效节点保存到文件中
while(cur != NULL){
fwrite(cur, sizeof(Person), 1, fp);
cur = cur->next;
}
fclose(fp);
return 0;
}
/**
* @brief printfList 遍历链表
* @param head 链表的头指针
*/
void printfList(Person *head){
// 1.取出头节点的下一个节点
Person *cur = head->next;
// 2.判断是否为NULL, 如果不为NULL就开始遍历
while(cur != NULL){
// 2.1取出当前节点的数据, 打印
printf("name = %s\n", cur->name);
printf("age = %i\n", cur->age);
printf("height = %lf\n", cur->height);
printf("next = %x\n", cur->next);
printf("-----------\n");
// 2.2让当前节点往后移动
cur = cur->next;
}
}
/**
* @brief insertNode 插入新的节点
* @param head 链表的头指针
* @param p 需要插入的结构体
*/
void insertNode(Person *head, char *name, int age, double height){
// 1.创建一个新的节点
Person *node = (Person *)malloc(sizeof(Person));
// 2.将数据保存到新节点中
node->name = name;
node->age = age;
node->height = height;
// 3.进行插入
// 3.1让新节点的下一个节点 等于 头节点的下一个节点
node->next = head->next;
// 3.2让头结点的下一个节点 等于 新节点
head->next = node;
}
/**
* @brief createEmpty 创建一个空链表
* @return 链表头指针, 创建失败返回NULL
*/
Person *createEmpty(){
// 1.定义头指针
Person *head = NULL;
// 2.创建一个空节点, 并且赋值给头指针
head = (Person *)malloc(sizeof(Person));
if(head == NULL){
return head;
}
head->next = NULL;
// 3.返回头指针
return head;
}

其它文件操作函数

  • ftell 函数
函数声明 long ftell ( FILE * stream );
所在文件 stdio.h
函数功能 得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.
参数及返回解析
参数 FILE * 流文件句柄
返回值 int 成功,返回当前读写位置偏离文件头部的字节数。失败, 返回 - 1
#include
int main()
{
char *str = "123456789";
FILE *fp = fopen("test.txt", "w+");
long cp = ftell(fp);
printf("cp = %li\n", cp); // 0
// 写入一个字节
fputc(str[0], fp);
cp = ftell(fp);
printf("cp = %li\n", cp); // 1
fclose(fp);
return 0;
}
  • rewind 函数
函数声明 void rewind ( FILE * stream );
所在文件 stdio.h
函数功能 将文件指针重新指向一个流的开头。
参数及返回解析
参数 FILE * 流文件句柄
返回值 void 无返回值
#include
int main()
{
char *str = "123456789";
FILE *fp = fopen("test.txt", "w+");
long cp = ftell(fp);
printf("cp = %li\n", cp); // 0
// 写入一个字节
fputc(str[0], fp);
cp = ftell(fp);
printf("cp = %li\n", cp); // 1
// 新指向一个流的开头
rewind(fp);
cp = ftell(fp);
printf("cp = %li\n", cp); // 0
fclose(fp);
return 0;
}
  • fseek 函数
函数声明 int fseek ( FILE * stream, long offset, int where);
所在文件 stdio.h
函数功能 偏移文件指针。
参数及返回解析
参 数 FILE * stream 文件句柄
long offset 偏移量
int where 偏移起始位置
返回值 int 成功返回 0 ,失败返回 - 1
  • 常用宏
#define SEEK_CUR 1 当前文字
#define SEEK_END 2 文件结尾
#define SEEK_SET 0 文件开头
#include
int main()
{
FILE *fp = fopen("test.txt", "w+");
fputs("123456789", fp);
// 将文件指针移动到文件结尾, 并且偏移0个单位
fseek(fp, 0, SEEK_END);
int len = ftell(fp); // 计算文件长度
printf("len = %i\n", len);
fclose(fp);
return 0;
}
#include
int main()
{
FILE *fp;
fp = fopen("file.txt","w+");
fputs("123456789", fp);
fseek( fp, 7, SEEK_SET );
fputs("lnj", fp);
fclose(fp);
return 0;
}
来自陕西
文章标题:【转载】C语言入门到精通,这一篇就够了(13万字笔记)7
文章作者:admin
文章URL:https://absozero.cn/2024/11/17/8/

评论

  1. z
    zlybq
    Windows Edge
    2024-11-17
    2024-11-17 18:44:02

    噢噢噢噢噢噢噢噢哦哦

    来自陕西
    • z
      zlybq
      zlybq
      Windows Edge
      2024-11-17
      2024-11-17 18:44:19

      来自陕西

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇