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 功 能: 使 ...
随机推荐
- Openwrt dnsmasq 设置要点
之前设置dnsmasq,一直没有奏效,后来摸索了一下,初步发现它的原理: 正常的流程应该是像这样的,先由client来发送DNS请求到网关,然后网关的dnsmasq处理这个请求, 再根据设置决定如何处 ...
- JavaScript的一些知识碎片(2)-反射-全局变量-回调
JavaScript中的反射:编程语言中的反射原理都一样,就是通过操作metadata(描述语言的语言)来完成一些不具备反射功能的语言很难实现的功能.在静态语言中,反射是一个高大上的东西,比如在运行时 ...
- HoloLens开发手记 - 应用程序模型 App model
HoloLens使用Universal Windows Platform (UWP)提供的应用模型.UWP应用模型定义了应用如何被安全和完全地安装.更新.版本控制和移除.它管理了应用生命周期 - 应用 ...
- 东大OJ-1430-PrimeNumbers
题目描述 I'll give you a number , please tell me how many different prime factors in this number. 输入 The ...
- 100726A
迭代深搜,从最深的地方搜,然后一个数被搜过了,标记用过,以后不再访问 #include<iostream> #include<cstring> #include<map& ...
- git初体验(四)git标签
1.git 标题(tag) 关于git标签的描述,参考这里 2.标题管理 创建: 切换到需要打标签的分支上,如: git checkout master git tag v1.0 # 默认标签是打在最 ...
- selenium+webdriver+python 中警告框的处理方法
在自动化测试过程中,经常会遇到弹出警告框的情况,如图所示: 在 WebDriver 中处理 JavaScript 所生成的 alert.confirm 以及 prompt 是很简单的.具体做法是使用 ...
- selenium3各种报错解决办法
解决办法全在这个链接里 http://learn-automation.com/use-firefox-selenium-using-geckodriver-selenium-3
- Linux的vim三种模式及命令
一般模式:在Linux终端中输入"vim 文件名"就进入了一般模式,但不能输入文字.编辑模式:在一般模式下按i就会进入编辑模式,此时就可以写程式,按Esc可回到一般模式. 命令模式 ...
- 【CCCC天梯赛决赛】
cccc的天梯赛决赛,水题一样的水,中档题以上的还是没做出来.补了一下题,觉得其实也不是很难,主要是练的少. L2-1:红色预警 并查集 我做的时候想不到并查集,想到了也不一定做的出来,都是其实不难. ...