注:以下示例摘自《C Prime Plus》第17章。
本文为《C语言链表—基础篇》的姊妹篇,主要完成链表的实现。
回顾一下程序需求:
编写一个程序,让用户输入一年内看过的所有电影。要存储每部电影的各种信息,如片名、发行年份、导演、主演、影片种类等等。建议使用一个结构存储每部电影,一个数组存储一年内看过的电影。为了简单起见,我们规定结构中只有两个成员:片名和等级(1~10)。
1. 主程序
#include <stdio.h>
#include <stdlib.h> /* 提供 malloc 原型 */
#include <string.h> /* 提供 strcpy 原型 */
#define MAX_SIZE 5
#define MAX_NAME_LEN 50
struct film {
char name[MAX_NAME_LEN];
int rating;
struct film * next_ptr;
};
char * s_gets(char * st, int n);
int main(){
struct film * head = NULL;
struct film * pre, * curr;
int i = 0;
char input[MAX_NAME_LEN];
puts("Enter first film title:");
/* 收集和存储链表 */
while( s_gets(input, MAX_NAME_LEN) != NULL && input[0] != '\0'){
curr = (struct film *) malloc(sizeof(struct film));
if (head == NULL) /* 第一个结构 */
head = curr;
else /* 后续结构 */
pre->next_ptr = curr;
curr->next_ptr = NULL;
strcpy(curr->name, input);
puts("enter your rating <0-10>: ");
scanf("%d", &curr->rating);
while (getchar() != '\n'){
continue;
}
puts("enter next Film name (empty line to stop):");
pre = curr;
}
if(head == NULL)
printf("No data entered \n");
else
printf("Here is the movie list: \n");
/* 显示链表 */
curr = head;
while (curr != NULL)
{
printf("Film: %s, Rating %d \n", curr->name, curr->rating);
curr = curr->next_ptr;
}
/* 释放链表 */
curr = head;
while(curr != NULL){
free(curr);
curr = curr->next_ptr;
}
puts("Happy solstice!");
return 0;
}
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)
*find = '\0';
else
while(getchar() != '\n')
continue;
}
return ret_val;
}
2. 程序解读
下边我们针对程序的结构进行解读。程序主要分为三部分:创建链表,显示链表和释放链表。
2.1 创建链表
主要有以下三个步骤:
(1)使用 malloc() 分配空间。
curr = (struct film *) malloc(sizeof(struct film));
(2)储存结构的地址。
链表的第一个结构的地址应该储存在指针变量 head 中。随后每个结构的地址应存储在其前一个结构的 next_ptr 成员中。
if (head == NULL)
head = curr;
else
pre->next_ptr = curr;
为当前结构成员设置合适的值,尤其是把 next_ptr 成员设置成 NULL,表明当前结构是链表的最后一个结构。
curr->next_ptr = NULL;
(3)把用户输入信息拷贝到结构中。
strcpy(curr->name, input);
puts("enter your rating <0-10>: ");
scanf("%d", &curr->rating);
2.2 显示链表
显示链表从设置一个指向第一个结构的指针开始。由于头指针(head)已经指向链表中第一个结构,可以将头指针(head)赋值给当前指针(curr):
curr = head;
通过一个 while 循环将链表中的全部值打印出来。在循环中,通过指针取出当前结构的 name 和 rating 成员,同时将 next_ptr 赋值给 curr。如果此循环,直到链表的最后一个机构中 next_ptr 的值为 NULL, while 循环将结束。
while (curr != NULL){
printf("Film: %s, Rating %d \n", curr->name, curr->rating);
curr = curr->next_ptr;
}
遍历链表时,为何不直接使用 head 指针,而要重新创建一个新指针(current)?如果直接使用 head 会改变 head 的值,程序便找不到电影链表的第一个结构了。
2.3 释放链表
在许多环境中,程序结束时都会自动释放 malloc( ) 分配的内存。但是,最好还是成对调用 malloc( ) 和 free( )。
curr = head;
while(curr != NULL){
free(curr);
curr = curr->next_ptr;
}
程序运行结果:
总结
如此,一个简单的链表便实现了,但是有很多不足。比如:程序没有检查 malloc( ) 是否成功请求到内存,也不支持删除链表中的项。后边,可以通过建立抽象,来实现一个通用性更强的链表。