C语言:链表实现的一个实例
问题:写一个程序输入你一年看过的所有电影以及每部电影的各种信息(简化问题:每部电影只要求输入片名和评价)
链表实现:
#include<stdio.h>
#include<stdlib.h>//提供malloc()原型
#include<string.h>
#define TSIZE 45
struct film{
char title[TSIZE];
int rating;
struct film * next;
};
int main()
{
struct film * head = NULL;
struct film * prev, *current;
char input[TSIZE];
//收集并储存信息
puts("Enter first movie title:");
while(gets(input)!=NULL&&input[0]!='\0'){
current = (struct film *)malloc(sizeof(struct film));
if(head==NULL)
head=current;
else
prev->next=current;
current->next=NULL;
strcpy(current->title, input);
puts("Enter your rating <0-10>:");
scanf("%d",¤t->rating);
while(getchar()!='\n')
continue;
puts("Enter next movie title(empty line to stop):");
prev=current;
}
//给出电影列表
if(head==NULL)
printf("No data entered.");
else
printf("Here is the movie list:\n");
current=head;
while(current!=NULL){
printf("Movie:%s Rating:%d\n",current->title,current->rating);
current=current->next;
}
//释放所分配的内存
current=head;
while(current!=NULL){
free(current);
current=current->next;
}
printf("Bye!\n");
return 0;
}
程序分析:
不使用head遍历整个列表而使用一个新指针current是因为head会改变head的值,这样程序将不再能找到列表的开始处。
由malloc()分配的内存在程序终止时虽然会自动清理,但仍要记得调用free()来释放malloc()分配的内存,养成良好的习惯。
反思:
程序没有检查malloc()是否找到需要的内存,并且没有提供删除列表中项目的功能。
抽象数据类型实现:
1.构造接口
list.h接口文件
#ifndef LIST_H_
#define LIST_H_
#include<stdbool.h>
/*特定程序的声明*/
#define TSIZE 45
struct film
{
char title[TSIZE];
int rating;
};
/*一般类型定义*/
typedef struct film Item;
typedef struct node
{
Item item;
struct node * next;
}Node;
typedef Node * List;
/*函数原型*/
/*操作:初始化一个列表*/
/*操作前:plist指向一个列表*/
/*操作后:该列表被初始化为空列表*/
void InitializeList(List * plist);
/*操作:确定列表是否为空列表*/
/*操作前:plist指向一个已初始化的列表*/
/*操作后:如果该列表为空则返回true;否则返回false*/
bool ListIsEmpty(const List * plist);
/*操作:确定列表是否已满*/
/*操作前:plist指向一个已初始化的列表*/
/*操作后:如果该列表为空则返回true;否则返回false*/
bool ListIsFull(const List * plist);
/*操作:确定列表中项目的个数*/
/*操作前:plist指向一个已初始化的列表*/
/*操作后:返回该列表中项目的个数*/
unsigned int ListItemCount(const List * plist);
/*操作:在列表尾部添加一个项目*/
/*操作前:item是要被增加到列表的项目 plist指向一个已初始化的列表*/
/*操作后:如果可能的话,在列表尾部添加一个新项目,函数返回true,否则函数返回false*/
bool AddItem(Item item,List * plist);
/*操作:把一个函数作用于列表中的每个项目*/
/*操作前:plist指向一个已初始化的列表 pfun指向一个函数,该函数接受一个Item参数并且无返回值*/
/*操作后:pfun指向的函数被作用到列表中的每个项目一次*/
void Traverse(const List * plist,void(* pfun)(Item item));
/*操作:释放已分配的内存(如果有)*/
/*操作前:plist指向一个已初始化的列表*/
/*操作后:为该列表分配的内存已被释放并且该列表被置为空列表*/
void EmptyTheList(List * plist);
#endif
2.实现接口:
list.c文件
#include<stdio.h>
#include<stdlib.h>
#include "list.h"
/*局部函数原型*/
static void CopyToNode(Item item,Node * pnode);
/*接口函数*/
/*把列表设置为空列表*/
void InitializeList(List * plist)
{
* plist = NULL;
}
/*如果列表为空则返回真*/
bool ListIsEmpty(const List * plist)
{
if(* plist == NULL)
return true;
else
return false;
}
/*如果列表已满则返回真*/
bool ListIsFull(const List * plist)
{
Node * pt;
bool full;
pt = (Node *)malloc(sizeof(Node));
if(pt==NULL)
full=true;
else
full=false;
free(pt);
return full;
}
/*返回节点数*/
unsigned int ListItemCount(const List * plist)
{
unsigned int count = 0;
Node * pnode = *plist;
while(pnode!=NULL)
{
++count;
pnode=pnode->next;
}
return count;
}
/*创建存放项目的节点,并把它添加到由plist指向的列表(较慢的实现方法)尾部*/
bool AddItem(Item item,List * plist)
{
Node * pnew;
Node * scan = *plist;
pnew = (Node *)malloc(sizeof(Node));
if(pnew==NULL)
return false;
CopyToNode(item,pnew);
pnew->next=NULL;
if(scan==NULL)
*plist=pnew;
else
{
while(scan->next!=NULL)
scan=scan->next;
scan->next=pnew;
}
return true;
}
/*访问每个节点并对它们分别执行由pfun指向的函数*/
void Traverse(const List * plist,void(*pfun)(Item item))
{
Node *pnode=*plist;
while(pnode!=NULL)
{
(*pfun)(pnode->item);
pnode=pnode->next;
}
}
/*释放由malloc()分配的内存*/
/*把列表指针设置为NULL*/
void EmptyTheList(List * plist)
{
Node * psave;
while(*plist!=NULL)
{
psave=(*plist)->next;
free(*plist);
*plist=psave;
}
}
/*局部函数定义*/
/*把一个项目复制到一个节点中*/
static void CopyToNode(Item item,Node *pnode)
{
pnode->item=item;
}
3.使用接口:
film.c
#include<stdio.h>
#include<stdlib.h>
#include "list.h"
void showmovies(Item item);
int main(void)
{
List movies;
Item temp;
/*初始化*/
InitializeList(&movies);
if(ListIsFull(movies))
{
fprintf(stderr, "No memory available!Bye!\n");
exit(1);
}
/*收集并存储*/
puts("Enter first movie title:");
while(gets(temp.title)!=NULL && temp.title[0]!='\0')
{
puts("Enter your rating<0-10>:");
scanf("%d",&temp.rating);
while(getchar()!='\n')
continue;
if(AddItem(temp,&movies)==false)
{
fprintf(stderr,"Problem allocating memory\n");
break;
}
if(ListIsFull(movies))
{
puts("The list if now full.");
break;
}
puts("Enter next movie title(empty line to stop):");
}
/*显示*/
if(ListIsEmpty(movies))
printf("No data entered.");
else
{
printf("Here is the movie list:\n");
Traverse(&movies,showmovies);
}
printf("You entered %d movies.\n",ListItemCount(&movies));
/*清除*/
EmptyTheList(&movies);
printf("Bye!\n");
return 0;
}
void showmovies(Item item)
{
printf("Movies:%s Rating:%d\n",item.title,item.rating);
}
注意:
整个程序由三个文件组成,要运行这个程序,必须编译并链接film.c和list.c(关于编译多文件程序),工程建立如下:
反思:
使用ADT方法带来了什么?
1.使用链表的方式暴露了所有编程的细节,而使用ADT方法则隐藏了这些细节,并用与任务直接相关的语言来表达程序。
2.list.h和list.c文件共同组成可重用的资源。如果需要另一个简单列表,仍可用这些头文件。
程序新知:
1.“C预处理器和C库”中的#ifndef技术对多次包含一个文件提供保护
2.“文件输入输出”fprintfgetc()函数等的使用
3.编译多文件程序
C语言:链表实现的一个实例的更多相关文章
- C语言入门(17)——C语言数组应用的一个实例
本篇通过一个实例介绍使用数组的一些基本模式.问题是这样的:首先生成一列0-9的随机数保存在数组中,然后统计其中每个数字出现的次数并打印,检查这些数字的随机性如何.随机数在某些场合(例如游戏程序)中是非 ...
- C语言链表实例--玩转链表
下图为最一简单链表的示意图: 第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量.以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号 num,姓名 n ...
- 一步一步教你从零开始写C语言链表---构建一个链表
版权声明:本文为博主原创文章,如有需要,请注明转载地址:http://blog.csdn.net/morixinguan.若是侵权用于商业用途,请联系博主,否则将追究责任 https://blog ...
- 转 C# 只允许运行一个实例
来源:http://blog.csdn.net/jin20000/article/details/3136791 互斥进程(程序), 简单点说,就是在系统中只能有该程序的一个实例运行. 现在很多软件都 ...
- 苹果公司的新的编程语言 Swift 高级语言(十一)--初始化类的析构函数的一个实例
一 .实例的初始化 实例的初始化是准备一个类.结构或枚举的实例以便使用的过程. 初始化包含设置一个实例的每个存储属性为一个初始值,以及运行不论什么其他新的实例可以使用之前须要的设置或 ...
- C语言 链表
原文:C语言 链表 最近在复习数据结构,想把数据结构里面涉及的都自己实现一下,完全是用C语言实现的. 自己编写的不是很好,大家可以参考,有错误希望帮忙指正,现在正处于编写阶段,一共将要实现19个功能. ...
- C语言库函数大全及应用实例十四
原文:C语言库函数大全及应用实例十四 [编程资料]C语言库函数大全及应用实例十四 函数名: strset 功 能: 将一个串 ...
- C语言库函数大全及应用实例十三
原文:C语言库函数大全及应用实例十三 [编程资料]C语言库函数大全及应用实例十三 函数名: stat 功 能: 读取打 ...
- C语言库函数大全及应用实例十
原文:C语言库函数大全及应用实例十 [编程资料]C语言库函数大全及应用实例十 函数名: qsort 功 能: 使 ...
随机推荐
- 代码重构之 —— 一堆if、esle 逻辑的处理
这几天,接手一个同事的代码,关于微信接口开发的,那一堆的 if,看得哥蛋痛了,这个毛病也是很多新手容易犯的,所以特地把这次重构写出来. 下面来我们看看这个代码的问题所在,if else 里面的代码块逻 ...
- Myeclipse 2015 stable 2.0 完美破解方法
2015-08-21 以前写了一篇<Myeclipse 2015 stable 1.0 完美破解方法>,现 在跟新一下Myeclipse 2015 stable 2.0 破解方法,此方法 ...
- 东大OJ-1051-旅行家的预算
1051: 旅行家的预算 时间限制: 1 Sec 内存限制: 128 MB 提交: 27 解决: 7 [提交][状态][讨论版] 题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市( ...
- void与void之间没有隐式转换(纯属恶搞,请勿在意)
强大的vs弹出了这个提示:.有没有觉得强大的vs不应该出现该提示. 但就是出现了. 看客,您知道怎么让vs弹出这个提示吗^~^
- android第三方框架 xlistview 的使用
如今上拉刷新,下拉加载更多已经是浩如烟海的app的标配了 最近正好有相关的需要就去学习了一下,还是那句老话凡事都靠自己来 搞实在不是一件好事,费时费力不说可能还是在做无用功,不过自己研究学习 还是很有 ...
- Java--笔记(1)
1.Swing 是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充.AWT 是基于本地方法的C/C++程序, ...
- 【转】深入浅出Java三大框架SSH与MVC的设计模式
原文链接:http://www.cnblogs.com/itao/archive/2011/08/22/2148844.html 在许许多多的初学者和程序员,都在趋之若鹜地学习Web开发的宝典级框架: ...
- Shell脚本_备份/etc数据
vim backup_etc.sh chmod 755 backup_etc.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2 ...
- JS模块化编程之加载器原理
世面上有好多JavaScript的加载器,比如 sea.js, require.js, yui loader, labJs...., 加载器的使用范围是一些比较大的项目, 个人感觉如果是小项目的话可以 ...
- java.lang.ClassCastException: com.sun.proxy.$Proxy32 cannot be cast to com.bkc.bpmp.core.cache.MemcachedManager
java.lang.ClassCastException: com.sun.proxy.$Proxy32 cannot be cast to com.bkc.bpmp.core.cache.Memca ...
