借鉴原版书的例子代码,很有参考意义。
//14.18编程练习.7(参考原著)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int count=0;//作为全局变量。
//全局变量是指在程序开头的说明部分定义和说明的量。它的作用域分为两种情况:
//(1)在全局变量和局部变量不同名时,其作用域是整个程序(即单独函数可以改变其值)。
//(2)在全局变量和局部变量同名时,全局变量的作用域不包含同名局部变量的作用域。
void read_file(struct book *,char *);//从指定的文件地址中读取结构类型的函数。
void display(struct book *);
void change(struct book *);
void reduce(struct book *);
void add(struct book *);
void write_file(struct book *,char *);//写入指定文件指针的结构类型。
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10
struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
int size = sizeof(struct book);//声明的结构的大小。
int main(void)
{
struct book library[MAXBKS];//结构数组!
char command[10];
read_file(library,"book.dat");//开始就显示文件已有的内容。
printf("select the functions:\n");//菜单展示。
printf("d:dispaly all book c:change a book\n");
printf("r:reduce a book a:add books\n");
printf("other:save and quit:");
while(1)
{
gets(command);
switch(command[0])//这个表达式可以自动屏蔽掉多余的输入字符。
{
case 'd': display(library);break;
case 'c': change(library);break;
case 'r': reduce(library);break;
case 'a': add(library);break;
default: write_file(library,"book.dat");
}
printf("select d/c/r/a/other:");
}
return 0;
}
void read_file(struct book *p,char *filename)
{
FILE *pbooks;
if((pbooks=fopen(filename,"a+b"))==NULL)//a+打开一个文本文件,可以进行更新(读取和写入);
{ //向已有的文件的尾部追加内容,如果该文件不存在则先创建之;
fputs("Can't open book.dat file\n",stderr);//可以读取整个文件,但写入时只能追加内容;b表示二进制。
exit(EXIT_FAILURE);
}
rewind(pbooks);//指定到文件初始位置。
while(count<MAXBKS && fread(&p,size,1,pbooks)==1)
count++;
fclose(pbooks);
printf("Read %s successfully! There are %d books.\n",filename,count);//此时count是文件中已存在的library结构个数。
}
void display(struct book *p)
{
if(count==0)
printf("There is no book.\n");
printf("Book list for %d books:\n",count);
for(int i=0;i<count;i++)
printf("%s by %s : $%.2f\n",p[i].title,p[i].author,p[i].value);
}
void change(struct book *p)//“修改该书目记录的内容,即替换”。
{
char title[MAXTITL];
printf("Input the name of the book which you want change: ");
gets(title);
for(int i=0;i<count;i++)//遍历已有的书目。
if(strcmp(p[i].title,title)==0)
{
puts("Please add new a book title.");
gets(p[i].title);
puts("Now enter the author.");
gets(p[i].author);
puts("Now enter the value.");
scanf("%f",&p[i].value);
while(getchar()!='\n')
continue;
printf("The book has been changed!\n");
return;
}
printf("Error! The book is not in the list!\n");
return;//因为函数类型是void,return;只是用来防止两个提示性输出同时输出。
}
//这个函数模块是核心部分,仔细思考这么进行删除并替换的!!!!
void reduce(struct book *p)//“如果删除记录,把空出来的数组空间留给下一个要记录的书目。”
{
char title[MAXTITL];
if(count==0)
printf("Error! Book list is empty!\n");
printf("Input the name of the book which you want reduce: ");
gets(title);
for(int i=0;i<count;i++)
if(strcmp(p[i].title,title)==0)
{
p[i]=p[count-1];//“最简单的方法就是对存储在该数组空间内的所有的数据进行改变。”——结构是可以直接赋值的!!!!!(但是数组之间是不可以的)
strcpy(p[count-1].title," ");
strcpy(p[count-1].author," ");
p[count-1].value=0;
count--;//这个count标明删除后的数组结构,为后续添加数据起重要重用。
printf("%s has been delete from list\n",title);
return;
}
printf("Error! %s is not in book list.\n",title);
return;
}
void add(struct book *p)
{
if(count==MAXBKS)
{
fputs("Error! The book.dat file is full.\n",stderr);
exit(EXIT_FAILURE);
}
puts("Please add new book title.");
puts("Press [enter] at the start of a line to stop.");
while(count<MAXBKS && gets(p[count].title)!=NULL && p[count].title[0]!='\0')//结构数组内部是可以乱排?只要数组下标符合规定就可以了。
{//有个隐秘的点,count标明已经表示到达某个数组了?!
puts("Now enter the author.");
gets(p[count].author);
puts("Now enter the value.");
scanf("%f",&p[count].value);
count++;
while(getchar()!='\n')
continue;
if(count<MAXBKS)
puts("Enter the next title.");
else
puts("The book list file is full.");
}
}
void write_file(struct book *p,char *filename)
{
FILE *pbooks;
pbooks=fopen(filename,"w+b");//wb打开文件,但会自动删除截断已有的内容,目的是清空所有文件!!!!——“最后再把信息集写入文件中。”
pbooks=fopen(filename,"r+b");//与w+b对应,先清空,再整体r+b写入!!!
fwrite(p,size,count,pbooks);
fclose(pbooks);
}