linux 标准io笔记+简单的账户管理系统

====标准IO
标准IO:由标准C库提供的函数接口
头文件:stdio.h

常用的文件操作接口:
1、打开文件:fopen
函数原型:
FILE *fopen(const char *path, const char *mode );
参数:
const char *path:要打开的文件的路径名
const char *mode:以什么方式打开文件
- r 以只读的方式打开,且定位在文件开头
- r+ 以可读可写的方式打开,且定位在文件开头
- w 以只写的方式打开文件,如果文件存在就清空,不存在就创建,定位在文件开头
- w+ 以可读可写的方式打开文件,如果文件存在就清空,不存在就创建,定位在文件开头
- a 以只写且追加的方式打开文件,如果文件不存在就创建,定位在文件末尾
- a+ 以可读可写的方式打开文件,如果文件不存在就创建,如果是读取文件则定位在文件开头,如果是写入则定位在文件末尾

返回值:
成功:FILE *指针,文件流指针
失败:NULL

2、关闭文件:fclose
int fclose(FILE *stream);
参数:要关闭文件的流指针

3、读取文件:fread
函数原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:保存读取数据的内存的地址
size_t size:每一块数据的字节数
size_t nmemb:要读取的块数
FILE *stream:文件流指针
返回值:
成功:读取的块数
失败:小于读取的块数

思考:设两个文件分别有24字节和21字节,按每块5字节的方式读取5块数据,返回值为多少?
结果:返回值为4,但还是读取了24字节和21字节
原因:fread的返回值只返回读满的块数,没有读满的不算一块

4、写入文件:fwrite
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
const void *ptr:保存要写入的数据的内存的地址
size_t size:每一块数据的字节数
size_t nmemb:要写入的块数
FILE *stream:文件流指针
返回值:
成功:写入的块数
失败:小于写入的块数

思考:设buf中有24字节和21字节两种情况,按每块5字节的方式写入5块数据,结果如何?
结果:返回值为5,多写入NULL数据或乱码

5、移动光标:fseek
函数原型:
int fseek(FILE *stream, long offset, int whence);
参数:
FILE *stream:文件流指针
long offset:偏移量(>0 <0 =0)
int whence:从哪里开始偏移
SEEK_SET 文件开头
SEEK_CUR 光标当前
SEEK_END 文件末尾
返回值:
成功:0
失败:-1

6、获取光标距离文件开头位置:ftell
函数原型:
long ftell(FILE *stream);
参数:
FILE *stream:文件流指针
返回值:
成功:光标当前距离文件开头的字节数
失败:-1

练习:使用标准IO函数实现文件的复制

7、判断文件是否到达末尾:feof
int feof(FILE *stream);
返回值:
光标位于文件末尾:1
光标没有到达文件末尾:0

==============================
常用数据输入输出函数:
思考:printf的双引号中没有\n时,内容能否输出?
不能正常输出,直到遇到\n才会输出,或者在程序结束,清空缓冲区是才会被输出
原因:printf的缓冲区是行缓冲机制,即遇到换行符才输出一次

缓冲区的三种机制:
全缓冲:当缓冲区全满以后才输出
行缓冲:遇到换行符才输出:printf、scanf
无缓冲:直接输出,不停留:perror

printf家族:
printf:往标准输出缓冲区进行输出
fprintf:往文件中输出内容
sprintf:往字符串中输出

往文件中输出:
函数原型:
int fprintf(FILE *stream, const char *format, …);
参数:
FILE *stream:要输出对象的文件流指针
const char *format:以字符串的形式输出
…:变参函数的标志,表示后面的参数个数及类型由前面的参数决定
引用场合:
将不同类型的数据以字符串的形式保存到文件中

补充:三个标准文件,即进程初始化时就会打开的三个文件的文件流指针
标准输入(stdin)、标准输出(stdout)、标准出错(stderr)

往字符串中输出
这里的字符串指的是字符型数组,如果填字符型指针,那么这个指针必须指向的是可写入数据的内存地址
函数原型:
int sprintf(char *str, const char *format, …);
参数:
char *str:一个可输入数据的内存的地址
const char *format:要输出的数据
…:如果有格式控制符就要添加对应类型的变量
应用场合:
将不同类型的数据拼接成一个字符串,并保存到一个字符型数组中

scanf家族:
scanf:从标准输入缓冲区中获取数据保存到对应的变量中
fscanf:从文件中获取数据保存到对应类型的变量中
sscanf:从字符串中获取数据保存到对应类型的变量中

提取文件数据:fscanf
int fscanf(FILE *stream, const char *format, …);
参数:
FILE *stream:文件流指针
const char *format:要输入的格式
…:根据格式控制符来决定变量的数量及类型

补充:
scanf中遇到空格是算作一次输入,如果要将空格一起获取,可以使用这个格式控制符:%[^\n]
这样一来,只有输入了\n才算一次输入的结束

拆分字符串:sscanf
int sscanf(const char *str, const char *format, …);
参数:
const char *str:要进行拆分的字符串
const char *format:按什么格式拆分
…:保存拆分出的数据的变量

思考:有字符串:“hello-123-3.14"和字符串"123-3.14-hello”,试着拆分这两个字符串
结果:前一个字符串不能拆分,后一个字符串可以拆分,因为前一个字符串在获取hello这部分时,
将后面的’-'当做了字符串的一部分,所以连带着后面的也一起获取了
总结:要拆分的字符串中如果有子串存在,要注意这个子串和其他数据之间只能用空格或\n隔开

练习:做一个简单的管理系统,有注册功能,将数据保存到一个文件里面,运行程序都能读取文件内容

#include<stdio.h>
#include<stdlib.h>
#include <strings.h>
#include <string.h>

#define ACCOUNT_INIT 2000

typedef unsigned int uint;

typedef struct list{
	uint account;
	char number[15];
	char password[15];
	struct list *next;
}List,*LIST;

/*
	description: Create a head node
	return value: head address
*/
LIST creat_head()
{
	LIST head = (LIST)malloc(sizeof(List));
	if(head==NULL)
	{
		printf("head malloc failed!");
		return NULL;
	}
	head->next=NULL;
	return head;
}

/*
	description: Create a node
	return value: node address
*/
LIST creat_node(uint account,char *number,char * password)
{
	LIST node = (LIST)malloc(sizeof(List));
	if(node==NULL)
	{
		printf("head malloc failed!");
		return NULL;
	}
	node->account=account;
	stpcpy(node->number,number);
	stpcpy(node->password,password);
	node->next=NULL;
	return node;
}

/*
	description: Insert from the head into the linked list
*/
void push_head(LIST head,LIST node)
{
	node->next=head->next;
	
	head->next=node;
}

/*
	description: Insert from the tail into the linked list
*/
void push_tail(LIST head,LIST node)
{
	LIST p=head;
	while(p->next!=NULL)
	{
		p=p->next;
	}
	
	p->next=node;
	
}

/*
	description: Register an account using number
*/
void register_account(LIST head,char *number,char *password)
{
	LIST p =head;
	uint account;
	if(p->next==NULL)
	{
		account=ACCOUNT_INIT;
	}
	else
	{
		while(p->next!=NULL)
		{
			p=p->next;
		}
		account = p->account+1;
	}
	LIST node = creat_node(account,number,password);//Create a new node
	push_tail(head,node);//Insert node into linked list
}

void show(LIST head)
{
	LIST p=head->next;
	while(p!=NULL)
	{
		printf("%d  %s  %s\n",p->account,p->number,p->password);
		p=p->next;
	}
}

void display()
{
	printf("==================\n");
	printf("1、register\n2、quit\n3、display list\n");
}

/*
	description: List Initialization
*/
FILE * list_Init(LIST head)
{
	LIST node = NULL;
	uint account=0;
	char number[15]={0};
	char password[15]={0};
	char *str=malloc(50);
	FILE *fb=fopen("4.txt","r+");
	if(fb==NULL)
	{
		printf("file open error\n");
		return NULL;
	}
	//fseek(fb,0,SEEK_SET);
	while(fscanf(fb,"%[^\n]\n",str)==1)
	{
		sscanf(str,"%d %s %s",&account,number,password);
		node =creat_node(account,number,password);
		push_tail(head,node);
		account=0;
		bzero(number,sizeof(number));
	}
	free(str);
	return fb;
} 

/*
	description: Save data in a file
*/
void save(LIST head,FILE *fb)
{
	
	fseek(fb,0,SEEK_SET);
	
	LIST p=head->next;
	while(p!=NULL)
	{
		
		fprintf(fb,"%d %s %s\n",p->account,p->number,p->password);
		p=p->next;
	}
	fclose(fb);
}

int main()
{
	LIST head =creat_head();
	FILE *fb=list_Init(head);
	int key=0;
	char number[15]={0};
	char password[15]={0};
	while(1)
	{
		display();
		scanf("%d",&key);
		if(key==1)
		{
			printf("please input a phone number and your account password");
			scanf("%s %s",number,password);
			register_account(head,number,password);
			bzero(number,sizeof(number));
		}
		else if(key==2)
		{
			save(head,fb);
			break;
		}
		else if(key==3)
		{
			show(head);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值