[链表] 对链表与文件的结合使用的一点看法

概要:

     指针、链表和文件是C语言中比较重要的三块内容,经过一年的学习,我们大多人已经比较好的掌握了这三个方面的使用。但是将链表和文件结合使用,好像还没有哪道题中有过,或者还没有哪个人做过。于是,我写这篇论文——链表与文件的结合使用,并尽自己所能介绍一些比较方便易懂的方法和实例,将它们较好的呈献在大多人面前,以增加大家对链表、指针和文件的理解,提高大家学习C的兴趣。

正文:

用数组存放数据的时候,需要事先确定数组的长度,并分配连续的内存空间,其长度不能动态的改变,在面临实际的情况时,如对某公司的员工数据进行记录时,当员工数目变化时,数组很难相应变化。而使用链表,可以动态的分配空间,可以解决这些问题。谈到链表,就必须说到数据结构。链表是一种比较简单的线性数据结构,它可以实现对存储空间动态分配(首先要指明的是数组里的数据是连续存放,而链表里的数据是非连续存放的)。

链表是由许许多多的链表节点串联起来的,且每一个节点都应是相同的结构体类型。

对于链表的操作主要是:1.建立链表 2.数据的查找和输出 3.求链表节点的个数 4.插入和删除一个节点 3.链表的合并。

首先建立链表(以学生信息管理为例):

#include <malloc.h>   //建立链表是需要动态开辟空间,其函数属于malloc.h头文件

#include <stdio.h>

Int NUM = 0;         //NUM 记录链表的节点数,即学生的个数

Struct stu {

Long num;

Float score;

Struct stu *next;

};

Typedef  struct stu Stu_link;

1.建立链表的方法有两种:尾插法和头插法,在此我就以尾插法为例。

其函数模块为:

Stu_link *cre_link () {

//当前链表的头指针和为指针,表明链表的状态为空

Stu_link *head = NULL, *last = NULL;

Stu_link *p;

P = (Stu_link *)malloc(sizeof(Stu_link));   //开辟节点

Printf("input the number : ");

Scanf("%d", &p->num);

Printf("input the score : ");

Scanf("%d", &p->score);

While(p->num)

{

If(head == NULL)

{

Head = p;

Last = p;

}

Else

{

Last->next = p;

Last = p;

}

P = (Stu_link *)malloc(sizeof(Stu_link));   //重新开辟一个节点

Printf("input the number : ");

Scanf("%d", &p->num);

If(p->num)

{

Printf("input the score : ");

Scanf("%d", &p->score);

P->next = NULL;

}

}

Return head;

}

这个函数在主函数中被调用,会产生许多连接的链表节点,直到num输入0结束。

此时就可以用文件操作了。在输入节点信息的时候就一同将学生信息存入到文件中去了。

操作如下:

void  cre_link () {

//当前链表的头指针和为指针,表明链表的状态为空

Stu_link *head = NULL, *last = NULL;

FILE *stu;

Stu_link *p;

/*文件名应由用户自定义,可用下面注视语句,为了下面叙述方便,暂时由我来定义*/

/*Char filename[30];

Printf("input file path and name.dat : ");

Gets(filename);*/

 

/*以写的方式打开一个二进制文件*/

If((stu = fopen("D:\\tc\\stuinfo.dat", "wb")) == NULL)

{

Printf("cannot open this file .");

Exit(0);

}

P = (Stu_link *)malloc(sizeof(Stu_link));   //开辟节点

Printf("input the number : ");

Scanf("%d", &p->num);

Printf("input the score : ");

Scanf("%d", &p->score);

While(p->num)

{

Fwrite(p, sizeof(Stu_link), 1, stu); 

NUM++;        //记录链表的节点

If(head == NULL)

{

Head = p;

Last = p;

}

Else

{

Last->next = p;

Last = p;

}

P = (Stu_link *)malloc(sizeof(Stu_link));   //重新开辟一个节点

Printf("input the number : ");

Scanf("%d", &p->num);

If(p->num)

{

Printf("input the score : ");

Scanf("%d", &p->score);

P->next = NULL;

}

}

Fclose(stu);

}

这样就实现了在建立链表并输入学生信息的时候,同时也将信息写入文件了。

2.单链表元素的遍历:

单链表元素的遍历,即将每个链表元素的内容都输出来。其函数模块比较简单,如下:

Void print_link(Stu_link *head)

{

Stu_link *p;

P = head;

While(p)

{

Printf("num: %5d score:%5.1f\n", p->num, p->score);

P = p->next;

}

Printf("\n");

}

因为上面已经对输入的学生信息写入了文件,所以链表的输出可以打开那个文件进行读操作。

Void print_link()

{

Stu_link *p;

FILE *fp;

If((fp = fopen("D:\\tc\\stuinfo.dat", "rb")) == NULL)

{
printf("cannot open the file\n");

Exit(0);

}

While(!feof(fp))   // 将文件中的内容读出并输出来

{

P = (Stu_link *)malloc(sizeof(Stu_link));

Fseek(fp, 0, SEEK_CUR);               //保持文件内部指针在当前位置,下次

Fread(p, sizeof(Stu_link), 1, fp);           //读出时的位置就从当前位置开始

Printf("num: %5d score: %d5.1f", p->num, p->score);

Free(p);                        //释放p的空间,以节省内存,方便下次开辟

}

Fclose(fp);

}

3.链表元素的查找

具体思路是将文件中的数据读出来,然后一个个比较,若出现相等的,则找到结果。若没有出现则没有找到。

其函数模块为:

Stu_link *search(int num)   //其中num为要查找的学生的学号,在主函数中输出

{

Stu_link *p;

FILE *fp;

If((fp = (fopen("D:\\tc\\stuinfo.dat", "rb")) == NULL)

{

Printf("cannot open the file.");

Exit(0);

}

While(!feof(fp))

{

P = (Stu_link *)malloc(sizeof(Stu_link));

Fseek(fp, 0, SEEK_CUR);

Fread(p, sizeof(Stu_link), 1, fp);

If(p->num == num)

{

Printf("find the student .\n");

Fclose(fp);

Return p;

}

}

    printf("not find the student.\n");

free (p);

Fclose(fp);

Return NULL;

}

4.链表的插入

链表的插入有两种方法,节点前插入和节点后插入,在此我就以节点后插入为例,因为它比较符合习惯,简单易懂。

Void  insert(Stu_link newstu)   //将新增加的信息插入到文件结尾   

{

FILE *fp;

If((fp = fopen("D:\\tc\\stuinfo.dat", "ab")) == NULL)

{

Printf("cannot open the file.\n");

Exit(0);

}

If(fwrite(&newstu, sizeof(Stu_link), 1, fp) == sizeof(Stu_link))

{

Printf("insert successfully!");

NUM++;

}

Fclose(fp);

Return;

}

5.链表的删除

因为输入的数据都已经写入到文件中了,所以删除链表节点的基本思路是将文件中的节点一个个读出来,并与想删除的那个数据进行比较,若相同则可以删除,若没有相同的则没有该学生。

其函数模块如下:

//先把文件中的数据全部读出来,然后对信息进行删除,再将信息重新写入到文件中去

Void delete(int stunum)

{

FILE *fp;

Stu_link *stu, *p;

Int i = 0, record;

Stu = (Stu_link *)calloc(NUM, sizeof(Stu_link);

If((fp = fopen("D:\\tc\\stuinfo.dat", "rb+")) == NULL)

{

Printf("cannot open the file.\n");

Exit(0);

}

Fread(stu, sizeof(Stu_link), NUM, fp);

For(i = 0; i < NUM; i++)

{

If(stu[i].num == stunum)

{

Record = i;

Break;

}

Stu[record + 1].next = stu[record ].next;

Free(stu[record]);

Fclose(fp);

If((fp = fopen("D:\\tc\\stuinfo.dat", "wb")) == NULL)

{

Printf("cannot open the file.\n");

Exit(0);

}

Fwrite(stu, sizeof(Stu_link), NUM, fp);

Fclose(fp);

}

 

结尾:

上面所写内容只是链表与文件的结合使用的一部分,但却实现了我写这篇文章的初衷,即编写一个简单的学生成绩管理系统,可以实现简单的学生和学生成绩管理,对数据进行增删改查。大一尚未学过数据结构,所以只能以链表这个简单的数据结构来做此题。由于水平有限,对其解释仍有不够之处,还望海谅。

参考资料:《C语言宝典》

附:“自己用以上只是做的一个简单的学生管理系统”

#include <stdio.h>

#include <alloc.h>

int NUM = 0;

 

typedef struct stu

{

int  num;

float score;

struct stu *next;

}Stu_link;

 

void  cre_link()

{

Stu_link *head = NULL, *last = NULL;

FILE *stu;

Stu_link *p;

float score;

 

/*Char filename[30];   */

      /*printf("input file path and name.dat : ");     */

/*gets(filename);*/

 

if((stu = fopen("E:\\tc\\stuinfo.dat", "wb")) == NULL)

{

printf("cannot open this file .");

getch();

exit(0);

}

p = (Stu_link *)malloc(sizeof(Stu_link));

printf("input the number : ");

scanf("%d", &(p->num));

if(!(p->num))

{

printf("NULL finished !\n");

return ;

}

while(p->num)

{

printf("input the score : ");

scanf("%f", &(p->score));

fwrite(p, sizeof(Stu_link), 1, stu);

NUM++;

if(head == NULL)

{

head = p;

last = p;

}

else

{

last->next = p;

last = p;

}

p->next = NULL;

p = (Stu_link *)malloc(sizeof(Stu_link));

printf("input the number : ");

scanf("%d", &(p->num));

}

printf("create successfully!\n");

fclose(stu);

}

 

void print_link()

{

Stu_link *p;

int i=0;

FILE *fp;

if((fp = fopen("E:\\tc\\stuinfo.dat", "rb")) == NULL)

{

printf("cannot open the file\n");

getch();

exit(0);

}

while(!feof(fp) && i < NUM)

{

p = (Stu_link *)malloc(sizeof(Stu_link));

fread(p, sizeof(Stu_link), 1, fp);

i++;

printf("num: %d score: %.2f\n", p->num, p->score);

free(p);

}

fclose(fp);

}

 

void  search(int num)

{

Stu_link *p;

FILE *fp;

if((fp = fopen("E:\\tc\\stuinfo.dat", "rb")) == NULL)

{

printf("cannot open the file.");

getch();

exit(0);

}

while(!feof(fp))

{

p = (Stu_link *)malloc(sizeof(Stu_link));

fread(p, sizeof(Stu_link), 1, fp);

if(p->num == num)

{

printf("find the student .\n");

printf("num: %d  score: %.2f \n", p->num, p->score);

fclose(fp);

return;

}

}

printf("not find the student.\n");

free (p);

fclose(fp);

}

 

void  insert(Stu_link newstu)

{

FILE *fp;

if((fp = fopen("E:\\tc\\stuinfo.dat", "ab")) == NULL)

{

printf("cannot open the file.\n");

getch();

exit(0);

}

if(fwrite(&newstu, sizeof(Stu_link), 1, fp))

{

printf("insert successfully!\n");

NUM++;

}

fclose(fp);

return;

}

 

void delete(int stunum)

{

FILE *fp;

Stu_link *stu, *p;

int i = 0, record;

stu = (Stu_link *)calloc(NUM, sizeof(Stu_link));

if((fp = fopen("E:\\tc\\stuinfo.dat", "rb+")) == NULL)

{

printf("cannot open the file.\n");

getch();

exit(0);

}

fread(stu, sizeof(Stu_link), NUM, fp);

for(i = 0; i < NUM; i++)

{

if(stu[i].num == stunum)

{

record = i;

break;

}

}

NUM--;

fclose(fp);

if((fp = fopen("E:\\tc\\stuinfo.dat", "wb")) == NULL)

{

printf("cannot open the file.\n");

getch();

exit(0);

}

for(i=0;i<NUM;i++)

{

if(i==record) continue;

fwrite(stu+i, sizeof(Stu_link), 1, fp);

}

printf("Delete successfully!\n");

free(stu);

fclose(fp);

}

main()

{

int search_num, del_num, choice;

Stu_link newstu;

void cre_link();

void print_link();

void search(int);

void delete(int);

void insert(Stu_link);

clrscr();

while(1)

{

printf("-----Menu-----\n");

printf("  1. start\n");

printf("  2. search\n");

printf("  3. print\n");

printf("  4. amount of stu\n");

printf("  5. insert \n");

printf("  6. delete a stu\n");

printf("  7. save and end \n");

printf("\n");

printf("choose : ");

scanf("%d", &choice);

 

switch(choice)

{

 case 1:

printf("input num 0 to stop.\n");

cre_link();

getch();

break;

 case 2:

printf("input the number of the student: ");

scanf("%d", &search_num);

search(search_num);

getch();

break;

 case 3:

printf("all students : \n");

print_link();

getch();

break;

 case 4:

printf("All students are %d . \n", NUM);

getch();

break;

 case 5:

printf("input the new student's number: ");

scanf("%d", &newstu.num);

printf("input the new student's score: ");

scanf("%f", &newstu.score);

insert(newstu);

getch();

break;

 case 6:

printf("input the delete student's number: ");

scanf("%d", &del_num);

delete(del_num);

getch();

break;

 case 7:

printf("save successfully !\n");

getch();

exit(0);

break;

 default:

printf("select error ! again ...\n");

break;

}

}

}

该程序可以初始化学生的信息,查询学生的信息,打印学生的信息,查询学生总数,插入学生信息,删除学生信息。学生信息只需输入一次就可以多吃使用,因为它是从文件中读出学生信息。可见用文件将信息保存是个很好的方法。当然程序还有不完善的地方,比如,倘若学号输入相同,应进行提示,但这与我这篇文章的论题无关,而且进行修改很简单,在此不作赘述。

 

posted @ 2010-06-18 22:00  Velx  阅读(8002)  评论(14编辑  收藏  举报