网站建设linux,搭建微信网站怎么做,江门市城乡建设局网站,全国最新工商企业名录写在前面#xff1a;
本系列专栏主要介绍C语言的相关知识#xff0c;思路以下面的参考链接教程为主#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外#xff0c;笔者还参考了其它的一些C语言教材#xff0c;笔者认为重要的部分大多都会用粗体标注#xf… 写在前面
本系列专栏主要介绍C语言的相关知识思路以下面的参考链接教程为主大部分笔记也出自该教程。除了参考下面的链接教程以外笔者还参考了其它的一些C语言教材笔者认为重要的部分大多都会用粗体标注未被标注出的部分可能全是重点可根据相关部分的示例代码量和注释量判断或者根据实际经验判断。如有错漏欢迎指出。
参考教程C语言程序设计从入门到进阶【比特鹏哥c语言2024完整版视频教程】c语言基础入门c语言软件安装C语言指针c语言考研C语言专升本C语言期末计算机二级C语言c语言_哔哩哔哩_bilibili
一、概述
1、为什么使用文件 使用文件我们可以将数据直接存放在电脑的硬盘上做到数据的持久化。
2、什么是文件 磁盘上的文件是文件但是在程序设计中一般涉及到的文件有两种程序文件、数据文件从文件功能的角度来分类。
1程序文件 包括源程序文件后缀为.c、目标文件windows环境后缀为.obj、可执行程序windows环境后缀为.exe。
2数据文件 文件的内容不一定是程序而是程序运行时读写的数据比如程序运行需要从中读取数据的文件或者输出内容的文件本章讨论的是数据文件。 在以前各章所处理数据的输入输出都是以终端为对象的即从终端的键盘输入数据运行结果显示到显示器上。其实有时候需要把信息输出到磁盘上当需要的时候再从磁盘上把数据读取到内存中使用这时处理的就是磁盘上文件。
3、文件名
1一个文件要有一个唯一的文件标识以便用户识别和引用。
2文件名包含文件路径、文件名主干、文件后缀3部分例如“c:\code\test.txt”。
二、文件的打开和关闭
1、文件指针
1缓冲文件系统中关键的概念是“文件类型指针”简称“文件指针”。
2每个被使用的文件都会在内存中开辟了一个相应的文件信息区用来存放文件的相关信息如文件的名字文件状态及文件当前的位置等这些信息是保存在一个结构体变量中的该结构体类型是有系统声明的取名FILE。不同的C编译器的FILE类型包含的内容不完全相同但是大同小异如VS2013编译环境提供的stdio.h头文件中有以下的文件类型声明 struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE; 3每当打开一个文件的时候系统会根据文件的情况自动创建一个FILE结构的变量并填充其中的信息使用者不必关心细节。一般都是通过一个FILE的指针来维护这个FILE结构的变量这样使用起来更加方便。
4可以创建一个FILE*类型的指针变量——“FILE* pf;”定义pf是一个指向FILE类型数据的指针变量使pf指向某个文件的文件信息区一个结构体变量通过该文件信息区中的信息就能够访问该文件也就是说通过文件指针变量能够找到与它关联的文件。 2、文件的打开和关闭
1文件在读写之前应该先打开文件在使用结束之后应该关闭文件。
2在编写程序的时候在打开文件的同时都会返回一个FILE*的指针变量指向该文件也相当于建立了指针和文件的关系。
3ANSIC规定使用fopen函数来打开文件使用fclose函数来关闭文件。mode是文件的打开方式 //打开文件 FILE * fopen ( const char * filename, const char * mode ); //只读文件时如果找不到文件会返回一个空指针 //关闭文件 int fclose ( FILE * stream ); 4文件的打开方式有下面几种 文件使用方式 含义 如果指定文件不存在 “r”只读 为了输入数据打开一个已经存在的文本文件 出错 “w”只写 为了输出数据打开一个文本文件 建立一个新的文件 “a”追加 向文本文件尾添加数据 建立一个新的文件 “rb”只读 为了输入数据打开一个二进制文件 出错 “wb”只写 为了输出数据打开一个二进制文件 建立一个新的文件 “ab”追加 向一个二进制文件尾添加数据 出错 “r”读写 为了读和写打开一个文本文件 出错 “w”读写 为了读和写打开一个新的文本文件 建立一个新的文件 “a”读写 打开一个文件在文件尾进行读写 建立一个新的文件 “rb”读写 为了读和写打开一个二进制文件 出错 “wb”读写 为了读和写新建一个新的二进制文件 建立一个新的文件 “ab”读写 打开一个二进制文件在文件尾进行读和写 建立一个新的文件
三、文件的顺序读写
1、与文件读写有关的函数 1文本行输入函数char *fgets(char *str, int n, FILE *stream); 从指定的流stream读取一行并把它存储在str所指向的字符串内。当读取(n-1)个字符时或者读取到换行符时或者到达文件末尾时它会停止具体视情况而定。
2文本行输出函数int fputs(const char *str, FILE *stream); 向指定的文件写入一个字符串不自动写入字符串结束标记符’\0’。成功写入一个字符串后文件的位置指针会自动后移函数返回值为非负整数否则返回EOF符号常量其值为-1。
3格式化输入函数 int fscanf( FILE * stream, const char * format, [ argument...]); 根据数据格式format从输入流stream中读入数据存储到argument中遇到空格和换行时结束。
4格式化输出函数int fprintf( FILE *stream, const char * format, [ argument...]); 根据指定的格式format向输出流stream写入数据argument。
5二进制输入函数size_t fread( void *restrict buffer, size_t size, size_t count, FILE *restrict stream ); 从给定输入流stream读取最多count个对象到数组buffer中相当于对每个对象调用size次fgetc把buffer当作unsigned char数组并顺序保存结果流的文件位置指示器前进读取的字节数若出现错误则流的文件位置指示器的位置不确定若没有完整地读入最后一个元素则其值不确定。
6二进制输出函数size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream); 向指定的文件中写入若干数据块如成功执行则返回实际写入的数据块数目。
7读取格式化的字符串中的数据int sscanf(const char *buffer, const char *format, [argument...] );
8把格式化的数据写入某字符串int sprintf(char *string, char *format, [argument...]);
2、举例
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.hint main()
{FILE * pFile;//打开文件pFile fopen(myfile.txt, w); //只写会清除原本的数据如要保留则需选择追加方式//文件操作if (pFile ! NULL){fputs(fopen example, pFile);//关闭文件fclose(pFile);}return 0;
}
四、文件的随机读写
1、fseek函数
1函数原型 int fseek ( FILE * stream, long int offset, int origin ); 2函数作用根据文件指针的位置和偏移量来定位文件指针。
3举例
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.hint main()
{FILE * pFile;pFile fopen(example.txt, wb);fputs(This is an apple., pFile);fseek(pFile, 9, SEEK_SET);//SEEK_SET 从文件的起始位置开始算起//SEEK_END 从文件的结束位置开始算起 //SEEK_CUR 从文件指针的当前位置开始算起fputs( sam, pFile);fclose(pFile);return 0;
}
2、ftell函数
1函数原型 long int ftell ( FILE * stream ); 2函数作用返回文件指针相对于起始位置的偏移量。
3举例
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.hint main()
{FILE * pFile;long size;pFile fopen(myfile.txt, rb);if (pFile NULL) perror(Error opening file);else{fseek(pFile, 0, SEEK_END);size ftell(pFile);fclose(pFile);printf(Size of myfile.txt: %ld bytes.\n, size);}return 0;
}
3、rewind函数
1函数原型 void rewind ( FILE * stream ); 2函数作用让文件指针的位置回到文件的起始位置。
3举例
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.hint main()
{int n;FILE * pFile;char buffer[27];pFile fopen(myfile.txt, w);for (n A; n Z; n)fputc(n, pFile);rewind(pFile);fread(buffer, 1, 26, pFile);fclose(pFile);buffer[26] \0;puts(buffer);return 0;
}
五、文本文件和二进制文件 根据数据的组织形式数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储如果不加转换地输出到外存就是二进制文件如果要求在外存上以ASCII码的形式存储则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。 字符一律以ASCII形式存储数值型数据既可以用ASCII形式存储也可以使用二进制形式存储。如整数10000如果以ASCII码的形式输出到磁盘则磁盘中占用5个字节每个字符一个字节而二进制形式输出则在磁盘上只占4个字节VS2013测试。
六、文件读取结束的判定
1、feof函数
1在文件读取过程中不能用feof函数的返回值直接用来判断文件的是否结束。
2feof应用于当文件读取结束的时候判断是读取失败结束还是遇到文件尾结束。
①使用fgetc函数输入的话则是判断返回值是否为EOF。
②使用fgets函数输入的话则是判断返回值是否为NULL。
③使用fread函数输入的话则是判断返回值是否小于实际要读的个数。
2、文本文件读取结束的判定
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
#include stdlib.hint main(void)
{int c; //不是char因为要处理EOFFILE* fp fopen(test.txt, r);if (!fp) {perror(File opening failed);return EXIT_FAILURE;} //fgetc 当读取失败的时候或者遇到文件结束的时候都会返回EOFwhile ((c fgetc(fp)) ! EOF) // 标准C I/O读取文件循环{putchar(c);}//判断是什么原因结束的if (ferror(fp))puts(I/O error when reading);else if (feof(fp))puts(End of file reached successfully);fclose(fp);
}
3、二进制文件读取结束的判定
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.henum { SIZE 5 };
int main(void)
{double a[SIZE] { 1.,2.,3.,4.,5. };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 { // error handlingif (feof(fp))printf(Error reading test.bin: unexpected end of file\n);else if (ferror(fp)) {perror(Error reading test.bin);}}fclose(fp);
}
七、文件缓冲区
1、概述
1ANSIC标准采用“缓冲文件系统”处理的数据文件的所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。
2从内存向磁盘输出数据会先送到内存中的缓冲区装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据则从磁盘文件中读取数据输入到内存缓冲区充满缓冲区然后再从缓冲区逐个地将数据送到程序数据区程序变量等。
3缓冲区的大小由C编译系统决定。
4因为有缓冲区的存在C语言在操作文件的时候需要刷新缓冲区或者在文件操作结束的时候关闭文件如果不做这些操作可能会导致读写文件出现问题。 2、举例
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
#include windows.h
//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;
}
八、案例——通讯录项目重写
1、main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include contact.hvoid menu()
{printf(***********************************************\n);printf(******* 1. add 2. del ********\n);printf(******* 3. search 4. modify ********\n);printf(******* 5. show 6. sort ********\n);printf(******* 0. exit ********\n);printf(***********************************************\n);
}int main()
{int input 0;Contact contact;InitContact(contact);do{system(cls);menu();printf(请输入您的选择);scanf(%d, input);switch (input){case 1:AddContact(contact);break;case 2:DelContact(contact);break;case 3:SearchContact(contact);break;case 4:ModifyContact(contact);break;case 5:ShowContact(contact);break;case 6:SortContact(contact);break;case 0:save(contact);printf(正在退出系统\n);break;default:printf(输入有误\n);break;}system(pause);} while (input);return 0;
}
2、contact.h
#pragma once
#include stdio.h
#include assert.h
#include stdlib.h
#include string.h
#include errno.h#define MAX_NAME 20
#define MAX_TEL 12
#define MAX_SEX 14
#define MAX_ADDR 30
#define FILE_NAME text.txttypedef struct People
{char name[MAX_NAME];int age;char telephone[MAX_TEL];char sex[MAX_SEX];char addr[MAX_ADDR];
}People;typedef struct Contact
{People *data;int count;int capacity;
}Contact;void InitContact(Contact* cp);
void AddContact(Contact* cp);
void DelContact(Contact* cp);
void SearchContact(const Contact* cp);
void ModifyContact(Contact* cp);
void ShowContact(const Contact* cp);
void SortContact(Contact* cp);
void save(Contact* cp);
3、contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include contact.hvoid InitContact(Contact* cp)
{assert(cp);cp-count 0;cp-data (People*)calloc(3, sizeof(People));cp-capacity 3;FILE *pf fopen(FILE_NAME, r);if (pf NULL){printf(InitContact:%s\n, strerror(errno));return;}int flag 5;while (flag 5){if (cp-count cp-capacity){People *ptr (People*)realloc(cp-data, sizeof(People)*(cp-capacity 2));if (ptr NULL){printf(InitContact:%s\n, strerror(errno));return;}cp-data ptr;ptr NULL;cp-capacity cp-capacity 2;}flag fscanf(pf, %s %d %s %s %s, cp-data[cp-count].name, (cp-data[cp-count].age),cp-data[cp-count].telephone, cp-data[cp-count].sex, cp-data[cp-count].addr);if(flag5)cp-count;}fclose(pf);pf NULL;
}void AddContact(Contact* cp)
{assert(cp);if (cp-count cp-capacity){People *ptr (People*)realloc(cp-data, sizeof(People)*(cp-capacity 2));if (ptr NULL){printf(AddContact:%s\n, strerror(errno));return;}cp-data ptr;ptr NULL;cp-capacity cp-capacity 2;}printf(请输入姓名);scanf(%s, cp-data[cp-count].name);printf(请输入年龄);scanf(%d, (cp-data[cp-count].age));printf(请输入性别);scanf(%s, cp-data[cp-count].sex);printf(请输入电话号码);scanf(%s, cp-data[cp-count].telephone);printf(请输入地址);scanf(%s, cp-data[cp-count].addr);cp-count;printf(添加成功\n);
}int FindName(const Contact* cp ,const char* name)
{assert(cp);int i 0;while (i cp-count){if (strcmp(cp-data[i].name, name) 0){return i;}i;}return -1;
}void DelContact(Contact* cp)
{assert(cp);char name[MAX_NAME];if (cp-count 0){printf(通讯录为空\n);return;}printf(请输入需要删除联系人的姓名);scanf(%s, name);int pos FindName(cp, name);if (pos -1){printf(未找到该联系人\n);}else{while (pos cp-count){cp-data[pos] cp-data[pos 1];pos;}cp-count--;printf(删除成功\n);}
}void SearchContact(const Contact* cp)
{assert(cp);char name[MAX_NAME];if (cp-count 0){printf(通讯录为空\n);return;}printf(请输入需要查找联系人的姓名);scanf(%s, name);int pos FindName(cp, name);if (pos -1){printf(未找到该联系人\n);}else{printf(%-20s\t %-5s\t %-15s\t %-13s\t %-30s\n,姓名, 年龄, 性别, 电话号码, 地址);printf(%-20s\t %-5d\t %-15s\t %-13s\t %-30s\n,cp-data[pos].name, cp-data[pos].age, cp-data[pos].sex,cp-data[pos].telephone, cp-data[pos].addr);}
}void ShowContact(const Contact* cp)
{assert(cp);if (cp-count 0){printf(通讯录为空\n);return;}printf(%-20s\t %-5s\t %-15s\t %-13s\t %-30s\n, 姓名, 年龄, 性别, 电话号码, 地址);for (int i 0; i cp-count; i){printf(%-20s\t %-5d\t %-15s\t %-13s\t %-30s\n,cp-data[i].name, cp-data[i].age, cp-data[i].sex,cp-data[i].telephone, cp-data[i].addr);}
}void ModifyContact(Contact* cp)
{assert(cp);char name[MAX_NAME];if (cp-count 0){printf(通讯录为空\n);return;}printf(请输入需要修改联系人的姓名);scanf(%s, name);int pos FindName(cp, name);if (pos -1){printf(未找到该联系人\n);}else{printf(请输入姓名);scanf(%s, cp-data[pos].name);printf(请输入年龄);scanf(%d, (cp-data[pos].age));printf(请输入性别);scanf(%s, cp-data[pos].sex);printf(请输入电话号码);scanf(%s, cp-data[pos].telephone);printf(请输入地址);scanf(%s, cp-data[pos].addr);printf(修改成功);}
}
int cmpName(const void* p1, const void* p2)
{return strcmp(((People*)p1)-name, ((People*)p2)-name);
}
int cmpAge(const void* p1, const void* p2)
{return (((People*)p1)-age - ((People*)p2)-age);
}
int cmpSex(const void* p1, const void* p2)
{return strcmp(((People*)p1)-sex, ((People*)p2)-sex);
}void SortContact(Contact* cp)
{assert(cp);if (cp-count 0){printf(通讯录为空\n);return;}int(*fun[3])(const void* p1, const void* p2) { cmpName,cmpAge,cmpSex };int i;printf(输入0——按姓名排序输入1——按年龄排序输入2——按性别排序\n请输入);do{scanf(%d, i);if (!(i 0 i 2))printf(输入无效数字请重新输入);} while (!(i 0 i 2));qsort(cp-data, cp-count, sizeof(People), fun[i]);ShowContact(cp);
}void save(Contact* cp)
{assert(cp);FILE *pf fopen(FILE_NAME, w);if (pf NULL){printf(save:%s\n, strerror(errno));return;}int i 0;while (i cp-count){fprintf(pf, %s %d %s %s %s\n, cp-data[i].name, cp-data[i].age,cp-data[i].telephone, cp-data[i].sex, cp-data[i].addr);i;}fclose(pf);pf NULL;free(cp-data);cp-data NULL;
}