C语言进阶 您所在的位置:网站首页 睿信是什么软件 C语言进阶

C语言进阶

2023-04-02 08:45| 来源: 网络整理| 查看: 265

目录

文件的随机读写

函数fseek

 效果如下:

画图分析: 

效果如下:

函数ftell

画图分析: 

效果如下:

函数rewind

效果如下: 

文本文件和二进制文件

简单介绍:

二进制文件:

文件读取结束的判定

被错误使用的feof

利用fgetc的返回值来判断循环是否结束: 

 效果如下:

若是想要判断是因为什么结束的 ,以下是文本文件的例子

效果如下: 

二进制文件的例子: 

 效果如下:

文件缓冲区

在低版本vs可以用fflush 

VS2022 WIN11环境下测试的一段代码 

效果如下: 

下面我们给出一个解决方案 

 在VS2022 WIN11环境下,使用rewind(stdin)可以解决问题,效果如下:

如果深入了解scanf的用法也可以解决

文件的随机读写

注明:点击函数可以跳转cplusplus网站!!! 

函数fseek

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream, long int offset, int origin );

#include int main() { FILE* pf = fopen("text.txt", "r "); if (pf == NULL) { perror(pf); return; } //读文件 //fgetc返回指定流的内部文件位置指示符当前指向的字符,然后,内部文件位置指示器将前进到下一个字符。 int ch = fgetc(pf); printf("%c", ch);//a ch = fgetc(pf); printf("%c", ch);//b ch = fgetc(pf); printf("%c", ch);//c ch = fgetc(pf); printf("%c", ch);//d ch = fgetc(pf); printf("%c", ch);//e //关闭文件 fclose(pf); pf = NULL; return 0; }

 

 

 效果如下:

 现在指示器已经在f的位置,如果我们想要打印c,而不是按顺序读下去。那么就要用fseek

 

 

 

#include int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror(pf); return; } //读文件 //fgetc返回指定流的内部文件位置指示符当前指向的字符,然后,内部文件位置指示器将前进到下一个字符。 int ch = fgetc(pf); printf("%c", ch);//a ch = fgetc(pf); printf("%c", ch);//b ch = fgetc(pf); printf("%c", ch);//c ch = fgetc(pf); printf("%c", ch);//d ch = fgetc(pf); printf("%c", ch);//e //fseek(pf, 2, SEEK_SET);//起始位置开始 fseek(pf, -3, SEEK_CUR);//当前位置开始 //fseek(pf, -5, SEEK_END);//末尾开始 ch = fgetc(pf); printf("%c", ch); //关闭文件 fclose(pf); pf = NULL; return 0; } 画图分析: 

 

 

效果如下:

 

 

函数ftell

返回文件指针相对于起始位置的偏移量 

long int ftell ( FILE * stream );

#include int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror(pf); return; } //读文件 //fgetc返回指定流的内部文件位置指示符当前指向的字符,然后,内部文件位置指示器将前进到下一个字符。 int ch = fgetc(pf); printf("%c", ch);//a ch = fgetc(pf); printf("%c", ch);//b ch = fgetc(pf); printf("%c", ch);//c ch = fgetc(pf); printf("%c", ch);//d ch = fgetc(pf); printf("%c", ch);//e int a=ftell(pf); printf("%d", a); //关闭文件 fclose(pf); pf = NULL; return 0; } 画图分析: 

 

当前指向的是f,相对于起始位置的偏移量为5 

效果如下:

 

 

 

函数rewind

让文件指针的位置回到文件的起始位置 。

void rewind ( FILE * stream );

 

#include int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror(pf); return; } //读文件 //fgetc返回指定流的内部文件位置指示符当前指向的字符,然后,内部文件位置指示器将前进到下一个字符。 int ch = fgetc(pf); printf("%c", ch);//a ch = fgetc(pf); printf("%c", ch);//b ch = fgetc(pf); printf("%c", ch);//c ch = fgetc(pf); printf("%c", ch);//d ch = fgetc(pf); printf("%c", ch);//e //用rewind返回起始位置 rewind(pf); int a=ftell(pf); printf("%d\n", a); ch = fgetc(pf); printf("%c", ch);//打印的应该是a //关闭文件 fclose(pf); pf = NULL; return 0; } 效果如下: 

 

文本文件和二进制文件 简单介绍:

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。

以ASCII字符的形式存储的文件就是文本文件。

一个数据在内存中是怎么存储的呢?

字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而 二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。

如有整数1,如果以ASCII码的形式输出到磁盘,则磁盘中占用1个字节(每个字符一个字节),而 二进制形式输出,则在磁盘上需要4个字节(VS2013测试)。

所以并不是说二进制的形式更省空间,而是要根据情况判断

二进制文件:

我们以二进制形式将一个数写入文档

#include int main() { FILE* pf = fopen("test1.txt", "wb"); int num = 10000; fwrite(&num, 4, 1, pf); return 0; }

可以发现,写入的数据我们是看不懂的 

  

这里我们给一种查看的方式 ,流程如下:

点击现有项并添加刚刚创建的文件 

 

点击打开方式:

选择二进制编辑器:

 

 画图分析:

文件读取结束的判定 被错误使用的feof

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。

而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 

例如:

fgetc 判断是否为 EOF .

fgets 判断返回值是否为 NULL .

2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如

: fread判断返回值是否小于实际要读的个数。 

fgetc函数的返回值分析 :

读取失败返回EOF

1.遇到文件末尾,返回EOF,同时设置一个状态,遇到了文件末尾,使用feof来检测这个状态

2.遇到错误,返回EOF,同时设置一个状态,遇到了错误,使用ferror来检查这个状态

利用fgetc的返回值来判断循环是否结束:  #include int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { return 1; } int a = 0; while ((a = fgetc(pf)) != EOF) { printf("%c ", a); } fclose(pf); pf = NULL; return 0; }  效果如下:

若是想要判断是因为什么结束的 ,以下是文本文件的例子 #include int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { return 1; } int a = 0; while ((a = fgetc(pf)) != EOF) { printf("%c ", a); //putchar(a); } //判断是什么原因结束的 if (ferror(pf)) { puts("I/O error when reading"); } else if (feof(pf)) { puts("I/O error when reading"); } fclose(pf); pf = NULL; return 0; } 效果如下: 

二进制文件的例子:  #include enum { SIZE = 5 }; int main(void) { double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 }; FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式 fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组 fclose(fp); double b[SIZE]; fp = fopen("test.bin", "rb"); size_t ret_code = fread(b, sizeof(*b), SIZE, fp); // 读 double 的数组 if (ret_code == SIZE) { puts("Array read successfully, contents: "); for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]); putchar('\n'); } //判断结束的原因 else { if (feof(fp)) printf("Error reading test.bin: unexpected end of file\n"); else if (ferror(fp)) { perror("Error reading test.bin"); } } fclose(fp); }  效果如下:

 

 

文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序 中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓 冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根 据C编译系统决定的。

 

在低版本vs可以用fflush  #include #include //VS2013 WIN10环境测试 int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n"); Sleep(10000); printf("刷新缓冲区\n"); fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n"); Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0; } VS2022 WIN11环境下测试的一段代码 

 

#include int main(void) { //VS2022 WIN11环境 int a, b; while (1) { a = scanf("%d", &b); printf("%d\n", a); fflush(stdin); } return 0; }

读取时输入缓冲区的内容会被scanf函数逐个取走,在正常情况下,scanf函数可以根据返回值判断成功取走的个数。若是应该读取一个整型,但是缓冲区里是一个字符,那么就会发生异常读取,而fflush函数并不支持高版本vs,缓冲区不会刷新,由于缓冲区的内容并未被取走,那么下次循环,scanf函数发现缓冲区有内容,不会等使用者输入内容,会再一次读取,发生异常读取,如此反复。

效果如下: 

 

下面我们给出一个解决方案  #include int main(void) { int a, b; while (1) { a= scanf("%d", &b); printf("%d\n", a); //fflush(stdin); rewind(stdin); } return 0; }  在VS2022 WIN11环境下,使用rewind(stdin)可以解决问题,效果如下:

如果深入了解scanf的用法也可以解决

链接1:C 清空输入缓冲区,以及fflush(stdin)的使用误区和解决方法_fflush(stdin)换行错误_hjtcn的博客-CSDN博客

链接2: https://zhidao.baidu.com/question/191469857.html?fr=qrl&cid=866&index=1&fr2=query

 感兴趣的同学可以了解一下

 

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有