algorithm6 2022-04-04 14:08 采纳率: 76.2%
浏览 61
已结题

C语言学习链表的实现

我在编写C Primer Plus第17章的程序
list.c

//支持链表操作的函数
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

//局部函数原型
static void CopyToNode(Item item, Node *pnode);

//接口函数
//把链表设置为空
void InitializeList(List *plist)
{
   plist=NULL;
}

//如果链表为空,返回true
int ListIsEmpty(const List *plist)
{
   if (*plist==NULL)
      return 1;
   else
      return 0;
}

//如果链表已满,返回true
int ListIsFull(const List *plist)
{
   Node *pt;
   int full;

   pt=(Node *)malloc(sizeof(Node));
   if(pt==NULL)
      full=1;
   else
      full=0;
   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指向的链表末尾(较慢的实现)
int AddItem(Item item, List *plist)
{
   Node *pnew;
   Node *scan=*plist;

   pnew=(Node *)malloc(sizeof(Node));
   if (pnew==NULL)
      return 0;  //失败时退出函数

   CopyToNode(item, pnew);
   pnew->next=NULL;
   if (scan==NULL)  /*空链表*/
      *plist=pnew;  /*把pnew放在链表的开头*/
   else
   {
      while(scan->next != NULL)
         scan=scan->next;   /*找到链表的末尾*/
      scan->next=pnew;      /*把pnew添加到链表的末尾*/
   }

   return 1;
}

//访问每个节点并执行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;  //拷贝结构
}

list.h

//接口头文件,简单链表类型的头文件
#ifndef LIST_H_
#define LIST_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 InitializaList(List *plist);

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

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

//操作:确定链表中的项数,plist指向一个已初始化的链表
//后置条件:该函数返回链表中的项数
unsigned int ListItemCount(const List *plist);

//操作:在链表的末尾添加项
//前提条件:item是一个待添加至链表的项,plist指向一个已初始化的链表
//后置条件:如果可以,该函数在链表末尾添加一个项,且返回ture,否则返回false
int AddItem(Item item, List *plist);

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

//操作:释放已分配的内存(如果有的话)
//plist指向一个已初始化的链表
//后置条件:释放了为链表分配的所有内存,链表设置为空
void EmptyTheList(List *plist);

#endif
   

films3.c

//使用抽象数据类型(ADT)风格的链表
//与list.c一起编译
#include <stdio.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, "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) == 0)
      {
         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("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;
}

运行后出现下面情况:

img


好像是运行到

int AddItem(Item item, List *plist)
{
   Node *pnew;
   Node *scan=*plist;

   pnew=(Node *)malloc(sizeof(Node));
   if (pnew==NULL)
      return 0;  //失败时退出函数

   CopyToNode(item, pnew);
   pnew->next=NULL;
   if (scan==NULL)  /*空链表*/
      *plist=pnew;  /*把pnew放在链表的开头*/
   else
   {
      while(scan->next != NULL)
         scan=scan->next;   /*找到链表的末尾*/
      scan->next=pnew;      /*把pnew添加到链表的末尾*/
   }

   return 1;
}

—>运算符时出现问题。请问是什么原因,怎么解决?

  • 写回答

2条回答 默认 最新

  • 关注

    InitializeList函数初始化movies,没有起到任何作用,后面的movies是空指针。
    ListIsFull函数你的实现代码没有任何意义,传入的参数也没用到。你判断链表满的条件是什么?比如是长度到10这样的。
    InitializeList这个函数,你的.c文件中是这么写的,.h中写的是InitializaList,e你写成了a。
    InitializeList函数给你改了一下,能让你的代码继续运行了。
    如下:

    void InitializeList(List *plist)
    {
        (*plist) = (List)malloc(sizeof(Node));//修改2
        (*plist)->next = NULL;
    }
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 4月13日
  • 已采纳回答 4月5日
  • 创建了问题 4月4日

悬赏问题

  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改