上大学接触编程,而接触到的第一种编程语言是C语言,从此对C语言情有独钟。但最初没有深入的学习意识,只是完成老师要求顺利考完试后,就放下了。但后来学习汇编,了解到C语言的功能很强大,对硬件的编程与汇编有得一拼,所以要拾起放下的C语言的书,开始再次学习它。学了之前没有看过的链表文件以及动态内存分配,就此写了一个小程序来巩固学到的内容。程序的大体框架很容容易就实现了,但是Bug很多,调试了很久,才通过。现在,写这篇博客,记录这个程序的编写过程。
这是控制台界面的程序(现在还不会UI的设计),其功能是保存输入的姓名和手机号。信息的输入是通过链表来实现,之后将链表保存为二进制文件,然后释放链表空间。涉及到的操作有插入结点,删除结点,结点排序(按姓名),二进制文件块读写,动态内存分配。
程序中在实现从文件中读取存入的结点并建立链表环节中,使用feof()判断文件是否读完时出现了错误,虽然通过一个条件判断解决了,但是不知道为什么。在网上经牛人指点,知道了问题所在。链接:http://www.cnblogs.com/pmer/archive/2012/01/27/2330099.html
下面是程序中自定义函数的申明(struct friend是自定义链表数据类型):
//创建链表函数
//返回链表头指针
struct friend *create();
//插入结点函数
//返回链表头指针
struct friend *add_friend(struct friend *add_head);
//插入结点时的排序函数
//返回链表头指针
struct friend *paixu_friend(struct friend *paixu_head,struct friend *paixu_add);
//删除指定节点函数
//返回链表头指针
struct friend *delete_friend(struct friend *del_head);
//从文件中读取数据并生成链表
//返回链表的头指针
struct friend *readfile(char file_name[]);
//将修改后的链表写入文件中
//并且释放链表所占用的空间
int writefile(struct friend *wri_head,char wri_filename[50] );
//显示朋友信息
void display_info(char dis_filename[]);
//释放链表空间
int free_note(struct friend *free_head);
下面是主函数:
#include <stdio.h>
#include "functions_declaration.h"
int main()
{
struct friend *main_head=NULL;
char func_options,flag;
char file_name[50];
printf("****************************************************************\n");
printf("The program can help you manager your friends' infomations.\n");
printf("****************************************************************\n");
printf("****************************************************************\n");
printf("Input one of the following numbers:\n");
printf(" 0: Quit the program.\n");
printf(" 1: Create a file containing your friends' infomations.\n");
printf(" 2: Add a friend's infomation to the exited file.\n");
printf(" 3: Delete a friend from the exited file.\n");
printf(" 4: Display your friends infomations.\n");
printf("****************************************************************\n");
printf("****************************************************************\n");
scanf("%c",&func_options);
getchar();
do
{
switch (func_options)
{
case '0':
break;
case '1':
printf("Input the file name(don't over 50 chars):");
scanf("%s",file_name);
getchar();
main_head=create();
if(main_head==NULL)
{
printf("No file was created.\n");
break;
}
else
{
loop1: if(writefile(main_head,file_name)) //调用自定义函数writefile()将链表保存到文件中
goto loop1;
else
free_note(main_head); //调用自定义函数free_note()释放链表占用的动态存储区
break;
}
case '2':
printf("Input your exited file name:");
scanf("%s",file_name);
getchar();
main_head=readfile(file_name);//调用自定义函数readfile()从文件中读取数据建立链表
if(main_head==NULL)
break;
main_head=add_friend(main_head);//调用add_friend()向链表中加入新的结点
loop2: if(writefile(main_head,file_name))
goto loop2;
else
free_note(main_head);
break;
case '3':
printf("Input your exited file name:");
scanf("%s",file_name);
getchar();
main_head=readfile(file_name);
if(main_head==NULL)
break;
main_head=delete_friend(main_head);//调用delete_friend()删除指定的结点
if(main_head==NULL)
break;
else
{
loop3: if(writefile(main_head,file_name))
goto loop3;
else
free_note(main_head);
break;
}
case '4':
printf("Input your file name:");
scanf("%s",file_name);
getchar();
display_info(file_name);
break;
default:
break;
}
printf("Do you really to quit?(y or n):");
scanf("%c",&flag);
getchar();
if(flag=='y')
return 0;
else
{
printf("Input your option(0,1,2,3,4):");
scanf("%c",&func_options);
getchar();
}
}while(1);
}
下面是自定义的功能函数的实现:
/*The file is consisted of declarations and definitions of friends_info_functions*/
#include <stdlib.h>
#include <string.h>
struct friend
{
char name[20];
char cel[12];
struct friend *next;
};
//创建链表函数
//返回链表头指针
struct friend *create();
//插入结点函数
//返回链表头指针
struct friend *add_friend(struct friend *add_head);
//插入结点时的排序函数
//返回链表头指针
struct friend *paixu_friend(struct friend *paixu_head,struct friend *paixu_add);
//删除指定节点函数
//返回链表头指针
struct friend *delete_friend(struct friend *del_head);
//从文件中读取数据并生成链表
//返回链表的头指针
struct friend *readfile(char file_name[]);
//将修改后的链表写入文件中
//并且释放链表所占用的空间
int writefile(struct friend *wri_head,char wri_filename[50] );
//显示朋友信息
void display_info(char dis_filename[]);
//释放链表空间
int free_note(struct friend *free_head);
//**********************************************************
//创建链表函数
//返回链表头指针
struct friend *create()
{
struct friend *p=NULL,*head=NULL;
char cel[12];
if((p=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available!Creating file cannot continue.\n");
return NULL;
}
head=p;
printf("Input your friend's cellphone(\"end\" to end):");
scanf("%s",cel);
getchar();
if(strcmp(cel,"end")==0)
{
free(p);
return NULL;
}
else
do
{
strcpy(p->cel,cel);
printf("Input your friend's name:");
scanf("%s",p->name);
getchar();
p->next=NULL;
if(p!=head) //创建新结点时进行排序后插入(按姓名)
head=paixu_friend(head,p);
printf("Input friend cellphone(\"end\" to end):");
scanf("%s",cel);
getchar();
if(strcmp(cel,"end")!=0)
{
if((p=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available! Cannot add your friend's infomations\n");
return head;
}
}
else
return head;
} while(1);
}
//插入结点函数
//返回链表头指针
struct friend *add_friend(struct friend *add_head)
{
struct friend *add_p1=NULL;
char add_cel[12];
if((add_p1=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available!\n");
return add_head;
}
printf("Input your friend's cellphone(\"end\" to end):");
scanf("%s",add_cel);
getchar();
if(strcmp(add_cel,"end")==0)
{
free(add_p1);
return add_head;
}
else
{
do
{
strcpy(add_p1->cel,add_cel);
printf("Input your friend's name:");
scanf("%s",add_p1->name);
getchar();
add_p1->next=NULL;
add_head=paixu_friend(add_head,add_p1);
printf("Input your friend's cellphone(\"end\" to end):");
scanf("%s",add_cel);
getchar();
if(strcmp(add_cel,"end")==0)
return add_head;
else
if((add_p1=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available!\n");
return add_head;
}
}while(1);
}
}
//结点排序函数
//返回链表头指针
struct friend *paixu_friend(struct friend *paixu_head,struct friend *paixu_add)
{
struct friend *paixu_p1=paixu_head,*paixu_p2=NULL;
while(paixu_p1->next!=NULL)
{
paixu_p2=paixu_p1->next;
if(strcmp(paixu_p1->name,paixu_add->name)<=0)
if(strcmp(paixu_p2->name,paixu_add->name)>=0)
{
paixu_p1->next=paixu_add;
paixu_add->next=paixu_p2;
return paixu_head;
}
else
paixu_p1=paixu_p1->next;
else
{
paixu_add->next=paixu_p1;
paixu_head=paixu_add;
return paixu_head;
}
}
if(paixu_p1->next==NULL)
if(strcmp(paixu_p1->name,paixu_add->name)<=0)
{
paixu_p1->next=paixu_add;
return paixu_head;
}
else
paixu_add->next=paixu_p1;
paixu_head=paixu_add;
return paixu_head;
}
//删除指定节点函数
//返回链表头指针
struct friend *delete_friend(struct friend *del_head)
{
struct friend *del_p1=NULL,*del_p2=del_head;
char del_name[20];
printf("Input your friend name you want to delete:");
scanf("%s",del_name);
getchar();
while(strcmp(del_p2->name,del_name)!=0 && del_p2->next!=NULL)
{
del_p1=del_p2;
del_p2=del_p2->next;
}
if(strcmp(del_p2->name,del_name)==0)
{
if(del_p2==del_head)
{
del_head=del_p2->next;
free(del_p2);
printf("Friend %s been deleted!\n",del_name);
return del_head;
}
else
{
del_p1->next=del_p2->next;
free(del_p2);
printf("Friend %s been deleted!\n",del_name);
return del_head;
}
}
else
{
printf("Friend %s not been found!\n",del_name);
return del_head;
}
}
//从文件中读取数据并生成链表
//返回链表的头指针
struct friend *readfile(char file_name[])
{
FILE *fp=NULL;
struct friend *read_head=NULL,*read_p1=NULL,*read_p2=NULL;
if((fp=fopen(file_name,"rb"))==NULL)
{
printf("Open file error!\n");
return NULL;
}
if(feof(fp))
{
printf("No such a file!\n ");
fclose(fp);
return NULL;
}
else
{
if((read_head=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("Read file error!No space available.\n");
fclose(fp);
return NULL;
}
fread(read_head,sizeof(struct friend),1,fp);
if(ferror(fp))
{
printf("Read file error!\n");
free(read_head);
fclose(fp);
return NULL;
}
read_head->next=NULL;
read_p1=read_head;
while(!feof(fp))
{
if((read_p1->next=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available.Cannot go on.\n");
fclose(fp);
free_note(read_head);//释放已经分配的结点空间
return NULL;
}
read_p2=read_p1;
read_p1=read_p2->next;
if(fread(read_p1,sizeof(struct friend),1,fp)!=1)//虽然已经读完我文件中存的结点,但是文件
{ //没有到文件末尾,不知道为什么,只能这样
free(read_p1); //解决
read_p2->next=NULL;
break;
}
if(ferror(fp))
{
printf("Read file error!\n");
free_note(read_head);
fclose(fp);
return NULL;
}
read_p1->next=NULL;
}
fclose(fp);
}
return read_head;
}
//将修改后的链表写入文件中
//返回1表示重试写入
//返回0释放链表空间
int writefile(struct friend *wri_head,char wri_filename[] )
{
FILE *fp=NULL;
char wri_flag=NULL;
struct friend *wri_p1=wri_head;
if((fp=fopen(wri_filename,"wb"))==NULL)
{
printf("Open file error! The notes cannot been written.\n");
printf("Can you try again?(y or n):");
wri_flag=getchar();
getchar();
if(wri_flag=='y')
return 1;
else
return 0;
}
do
{
fwrite(wri_p1,sizeof(struct friend),1,fp);
//fputc('\n',fp);
if(ferror(fp))
{
fclose(fp);
printf("Error when writting!\n");
printf("Can you try again?(y or n):");
wri_flag=getchar();
getchar();
if(wri_flag=='y')
return 1;
else
return 0;
}
wri_p1=wri_p1->next;
}while(wri_p1!=NULL);
printf("changes was saved successfully.\n");
fclose(fp);
return 0;
}
//显示文件内容
void display_info(char dis_filename[])
{
struct friend *dis_head=NULL;
FILE *fp=NULL;
if((dis_head=(struct friend *)malloc(sizeof(struct friend)))==NULL)
{
printf("No space available.\n");
exit(1);
}
if((fp=fopen(dis_filename,"rb"))==NULL)
{
printf("Open file error!\n");
free(dis_head);
exit(1);
}
if(feof(fp))
{
printf("The file is NULL\n");
free(dis_head);
fclose(fp);
exit(1);
}
printf("Your file infomations as follows:\n");
while(!feof(fp))
{
if(fread(dis_head,sizeof(struct friend),1,fp)!=1)
break;
if(ferror(fp))
{
printf("Reading file error!\n");
free(dis_head);
fclose(fp);
exit(1);
}
dis_head->next=NULL;
printf("%s\t\t%s\n",dis_head->cel,dis_head->name);
}
free(dis_head);
fclose(fp);
}
//释放链表空间
int free_note(struct friend *free_head)
{
struct friend *free_p1=NULL;
while(free_head!=NULL)
{
free_p1=free_head;
free_head=free_p1->next;
free(free_p1);
}
return 0;
}