书上的代码 链表存储抽象数据类型,VS2017编译通过,输入一个项目后再输入第二个项目列表出错
[附件]1[/附件]//list.c 实现函数文件
#include "stdafx.h"
#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) //空列表,把pnew放在列表头部
* plist = pnew;
else
{
while (scan->next != NULL)
scan = scan->next;
scan->next = pnew; //寻找尾节点,添加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; //结构复制
}
// films3.cpp : 定义控制台应用程序的入口点。
//使用ADT风格的链表
//和list.c一同编译
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>//提供exit()原型
#include"list.h" //定义List,Item
void showmovies(Item item);
char * s_gets(char * st, int n);
int main(void)
{
List movies;
Item temp;
//初始化
InitializeList(&movies);
if (ListIsFull(&movies))
{
fprintf(stderr,"没有足够内存");
exit(1);
}
//收集并存储数据
puts("Enter first movie title: ");
while (s_gets(temp.title,TSIZE) != NULL && temp.title[0] != '\0')
{
puts("enter your tating<0-10>");
scanf("%d",&temp.rating);
while (getchar() != '\n')
continue;
if (AddItem(temp, &movies) == false)
{
fprintf(stderr,"内存出问题");
break;
}
if (ListIsFull(&movies))
{
puts("列表满");
break;
}
puts("enter next movie title (empty line to stop): ");
}
//显示
if (ListIsEmpty(&movies))
printf("无数据输入 \n");
else
{
printf("here is the movie list: \n");
Traverse(&movies,showmovies);
}
printf("you enterd %d movies,\n",ListItemCount(&movies));
//清除
EmptyTheList(&movies);
printf("再见!\n");
return 0;
}
void showmovies(Item item)
{
printf("Movie:%s Rating: %d\n",item.title,item.rating);
}
char * s_gets(char * st, int n)
{
char * ret_val, *find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n');
if (find)
*find = '\0';
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
//list.h头文件
#pragma once
#ifndef LIST_H_
#define LIST_H_
#include<stdbool.h> //C99特性
//特定于程序的声明
#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