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 功 能: 使 ...
随机推荐
- python2.1-原理之琐碎技巧
本系列依据<python学习手册第四版>而写,也算是个学习笔记吧,选择本书的原因在于它不同于第三版,它强调介绍python3.0 ,而会在不同的地方给出2.6版本的区别,:本书侧重介绍原理 ...
- Theano3.4-练习之多层感知机
来自http://deeplearning.net/tutorial/mlp.html#mlp Multilayer Perceptron note:这部分假设读者已经通读之前的一个练习 Classi ...
- 端口被占用的解决方案 sql server 10048 错误
一大早发现sql server服务无法启动,10048错误,一查是端口占用. 先找到哪个进程,结束即可. cmd命令, netstat /ano|findset "1433" 出现 ...
- WPF 小技巧
在使用mvvm模式开发时,对于Command的绑定是一件很伤脑筋的事情,尽管有强大的Blend类库支持: xmlns:Custom="http://www.galasoft.ch/mvvml ...
- CoordinatorLayout自定义Bahavior特效及其源码分析
@[CoordinatorLayout, Bahavior] CoordinatorLayout是android support design包中可以算是最重要的一个东西,运用它可以做出一些不错的特效 ...
- MATLAB axis和axes的区别
axis中文为“轴”之意,在matlab中用于控制坐标轴的范围和样式(颜色等). axis([XMIN XMAX YMIN YMAX]) 设置当前所绘图像的x轴和y轴的范围.axis([XMIN XM ...
- 【JavaEE企业应用学习记录】验证配置
package sanglp; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.validat ...
- 通过HttpUrlConnection下载文件并显示进度条
实现效果: 核心下载块: int count = 0; URL url = new URL("http://hezuo.downxunlei.com/xunlei_hezuo/thunder ...
- ( 转 ) Android自绘字体大小paint.settextsize随分辨率大小变化
1.获取当前设备的屏幕大小 DisplayMetrics displayMetrics = new DisplayMetrics(); this.getWindowManager().getDefau ...
- 【CodeVS 1163】访问艺术馆
http://codevs.cn/submission/2367697/ loli蜜汁(面向高一)树形dp是这道题的改编. 改编后的题目中每个展览厅的有多个不同的画,偷画的时间和画的价值也不同,求最大 ...
