C Primer Plus (第六版) 第十七章_编程练习答案

本章内容较难,涉及到很多内容,其中很多都需要多文件编译

下面每一道题,我都将几个文本合在一起,注意看注释说明

no1.c

//修改程序清代17.2,让该程序既能正序也能逆序显示电影列表.一种方法是修改链表的定义.
//可以双向遍历链表,另一种方法是用递归.
# include <stdio.h>
# include <stdlib.h>
# include <string.h>

# define TSIZE 45

struct film
{
	char title[TSIZE] ;
	int rating ;
	struct film * next ;
};

char * s_gets(char * st , int n);
void reverse_print(const struct film * ps);			//添加逆序输出的函数

int main(void)
{
	struct film * head = NULL ;
	struct film * prev , * current ;
	char input[TSIZE] ;

	puts("Enter first movie title :");
	while (s_gets(input , TSIZE) != 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" , &current->rating);
		while (getchar() != '\n') ;
		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 ;
	}

	//no1.c  修改17.2程序清单  添加逆序输出的代码,使用递归方式
	puts("==============================================");
	//reverse_print(head);

	// 切记切记 一定不要忘记释放内存, 不然程序稍大一点内存泄露问题就会很严重
	current = head ;
	while (current != NULL)
	{
		/*原17.2程序清单 代码有错
		free(current);
		current = current->next ;
		*/

		head = head->next ;		//先使头指针指向下一个节点
		free(current);			//释放掉当前指向的节点
		current = head ;		//当前指针指向头指针
	}
	printf("Bye!\n");

	return 0 ;
}

char * s_gets(char * st , int n)
{
	char * ret_val ;
	char * find ;

	if (ret_val = fgets(st , n , stdin))
	{
		if (find = strchr(st , '\n'))
			*find = '\0' ;
		else
			while (getchar() != '\n') ;
	}

	return ret_val ;
}

//逆序输出(递归)
//ps指向链表
void reverse_print(const struct film * ps)
{
	if (ps->next != NULL)
		reverse_print(ps->next);

	printf("Movie: %s Rating : %d\n" , ps->title , ps->rating);
}

no2.c

/*no2.c文件如下*/
/*注意需要和list.c文件一起编译*/
//假设 list.h(程序清单17.3)使用下面的list定义
//typedef struct list 
//{
//	Node * head ;
//	Node * end ;
//}List ;
//重写list.c(程序清单17.5)中的函数以适应新的定义,并通过films.c(程序清单17.4)
//测试最终代码
# include <stdio.h>
# include <stdlib.h>
# include <string.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') ;

		if (AddItem(temp , &movies) == false)
		{
			fprintf(stderr , "Problem allocating memory\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.");
	}
	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);
}

char * s_gets(char * st , int n)
{
	char * ret_val = NULL ;
	char * find = NULL ;

	if (ret_val = fgets(st , n , stdin))
	{
		if (find = strchr(st , '\n'))
			*find = '\0' ;
		else
			while (getchar() != '\n') ;
	}

	return ret_val ;
}

/*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 ;

/* no2.c 修改代码 重新定义List类型
typedef Node * List ;
*/
// no2.c 修改代码如下
typedef struct list
{
	Node * head ;
	Node * end ;
}List ;

//操作:		初始化链表
//前提条件:	plist指向一个链表
//后置条件:	链表初始化为空
void InitializeList(List * plist);

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

/*list.c文件*/
/*注意需要和no2.c文件一起编译*/
# include <stdio.h>
# include <stdlib.h>
# include "list.h"

static void CopyToNode(Item item , Node * pnode);

void InitializeList(List * plist)
{
	/* no2.c 修改代码
	*plist = NULL ;
	*/
	// no2.c 修改初始化代码如下
	plist->head = plist->end = NULL ;
}

bool ListIsEmpty(const List * plist)
{
	/* no2.c 修改代码
	return (*plist == NULL) ;
	*/
	// no2.c 修改代码如下
	return ((plist->head == NULL) && (plist->end == NULL));
}

// 此函数不需要修改,它只是尝试着分配了一个空间,去判断磁盘是否已满
// 并无最大限
bool ListIsFull(const List * plist)
{
	Node * pt ; 
	bool full = false  ;

	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 ;

	/* no2.c 修改代码 节点指针指向头节点
	Node * pnode = *plist ;
	*/
	// no2.c 修改代码如下
	Node * pnode = plist->head ;

	while (pnode != NULL)
	{
		++count ;
		pnode = pnode->next ;
	}
	
	return count ;
}

bool AddItem(Item item , List * plist)
{
	Node * pnew ;
	/* no2.c 修改代码 不需要scan节点指针
	Node * scan = *plist ;
	*/

	pnew = (Node *)malloc(sizeof(Node)) ;
	if (pnew == NULL)
		return false ;

	CopyToNode(item , pnew);
	pnew->next = NULL ;

	/* no2.c 修改代码 判断头是否为空
	 * 如果为空,头指向新节点
	 * 否则在最后一个节点指向新节点
	if (scan == NULL)
		*plist = pnew ;
	else 
	{
		while (scan->next != NULL)
			scan = scan->next ;
		scan->next = pnew ;
	}
	*/

	if (plist->head == NULL)
		plist->head = plist->end = pnew ; 
	else 
	{
		plist->end->next = pnew ;
		plist->end = plist->end->next ;
	}

	return true ;
}

void Traverse(const List * plist , void (*pfun)(Item item))
{
	/* no2.c 修改代码 pnode 指向头节点
	Node * pnode = *plist ;
	*/
	// no2.c 修改代码如下
	Node * pnode = plist->head ;

	while (pnode != NULL)
	{
		(*pfun)(pnode->item);
		pnode = pnode->next ;
	}
}

void EmptyTheList(List * plist)
{
	Node * psave ;

	while (plist->head != NULL)
	{
		/* no2.c 修改代码 psave 每次指向头节点的下一个节点
		psave = (*plist)->next ;
		free(*plist);
		*plist = psave ;
		*/
		// no2.c 修改代码如下
		psave = plist->head->next ;
		free(plist->head);
		plist->head = psave ;
	}
}

static void CopyToNode(Item item , Node * pnode)
{
	pnode->item = item ;
}

no3.c

/*no3.c文件*/
/*注意需要和list.c文件一起编译*/
//假设list.h(程序清单17.3)使用下面的list定义
//# define MAXSIZE 100
//typedef struct list
//{
//	Item entrise[MAXSIZE];
//	int items ;
//}List ;
//重写list.c(程序清单17.5)中的函数以适应新的定义,并通过films.c(程序清单17.4)
//测试最终代码
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "list.h"

// no3.c 修改代码
//void showmovies(Item item) ;
// no3.c 重新声明函数
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') ;

		if (AddItem(temp , &movies) == false)
		{
			fprintf(stderr , "Problem allocating memory\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.");
	}
	else
	{
		printf("Here is the movie list:\n");
		Traverse(&am
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值