C语言高级数据表示

通常,程序开发最重要的部分是找到程序中表示数据的好方法

  • 选择数据类型
  • 如何存储数据
  • 设计管理数据的函数

算法:操控数据的方法

/*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);//List == Node *,那么 List * = Node * * plist,plist是指向指针的指针 

//操作: 确定链表是否为空定义,plist指向一个已经初始化的链表
//后置条件: 如果链表为空,该函数返回true,否则返回false
bool ListIsEmpty(const List * plist);

//操作:	确定链表是否已满,plist指向一个已初始化的链表
//后置条件:  如果链表已满,该函数返回true,否则返回false
bool ListIsFull(const List *plist);

//操作:	确定链表中的项数
//后置条件: 该函数返回链表中的项数
unsigned int ListItemCount(const List * plist);

//操作:	在链表中添加项
//前提条件: item是一个待添加的项,plist是一个已初始化的链表
//后置条件: 如果添加成功返回true,否则返回false
bool AddItem(Item item, List * plist);

//操作:	把函数作用于链表中的每一项,pfun指向一个函数,该函数接受一个Item类型的参数,且无返回值
void Traverse(const List *plist, void(*pfun)(Item item));

//操作:	释放已分配的内存
//后置条件: 释放了为链表分配的所有内存,链表设置为空
void EmptyTheList(List * plist);

#endif 
/*
list.h --- 定义数据结构提供用户接口的原型
lsit.c --- 提供函数代码实现接口
main.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)
{
	//*plist指向的地址为空 
	if( *plist == NULL)
		return true;
	else
		return false;	
} 

//如果链表已满,返回true
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 * current = *plist;
	
	while(current != NULL)//从头指针开始判断,如果头指针为空,说明count==0 
	{
		current = current->next;
		count++;
	}
	return count;
}

//创建储存项的节点,并将其添加至由plist指向的链表末尾
bool AddItem(Item item, List * plist)
{
	Node * pnew;
	Node * scan = *plist;
	pnew = (Node *)malloc(sizeof(Node));
	if(pnew == NULL)
		return false;//内存分配失败
	 
	pnew->item = item;
	pnew->next = NULL;
	
	if(scan == NULL)//头指针为空,说明是空链表
		*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;	
	}	
} 

/*
	处理多个链表是都把const List * list作为形参,表明这些函数不会更改链表,const防止了*plist(即plist所指向的量被修改),
	在该程序中,plist指向movies,所以const防止这些函数修改movies。
	所以不能出现:
		*plist = (*plsit)->next; //如果*plist是const,不允许这样做
	但是
		(*plsit)->item.rating = 3; //即使*plist是const,也可以这样做
	上面代码并未修改*plist,而是修改的*plist指向的数据 
*/
#include <stdio.h>
#include <stdlib.h>
#include"list.h"
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, "No memory available! Bye!\n");
		exit(1);
	} 
	
	//获取用户输入并储存
	puts("Enter first movie title:");
	while (s_gets(temp.title, TSIZE) != 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, "No memory available! Bye!\n");
			break;
		}
		if (ListIsFull(&movies)) 
		{
			puts("The list is now full ");
			break;
		}
		puts("Enter next movie title (empty line to stop):");
	} 
	
	//显示
	if(ListIsEmpty(&movies)) 
		printf("No data entered.\n");
	else
	{
		printf("Here is the movie list:\n");
		Traverse(&movies, showmovies);
	}
	printf("You entered %d movies.\n", ListItemCount(&movies));
	
	//清理
	EmptyTheList(&movies);
	puts("Bye!\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;
	char * find;
	ret_val = fgets(st, n, stdin);
	if(ret_val)
	{
		find = strchr(st, '\n');//查找换行符
		if (find)//如果地址不是NULL 
			*find = '\0'; //在此书放置一个空字符 
		else
			while (getchar() != '\n')
				continue;  //处理输入行中其他字符			 
	}
	return ret_val; 	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SOC罗三炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值