C实现简单列表

C primer快看完了,今天自己试着实现书上简单列表的例子,遇到了一些坑,稍微总结一下。

在C里面,数组是内存块,通过下标访问这些内存块。因此,在C里面的数组只能使用整数且有序的键值,像PHP中那样简单便捷的关联数组在C中是不存在的。所以,想要处理复杂的数据集的时候,就需要使用数据结构,链表就是其中之一。

链表

虽然C提供了struct(结构)这种数据类型,可以使用结构数组来处理复杂的数据集,如果事先声明了结构数组的大小,那么存少了浪费空间,存多了又会不够,如果用的时候再使用malloc来申请内存空间,又不能保证内存连续,所以,使用结构数组不够灵活。

#define TSIZE 45
struct film{
    char title[TSIZE];
    int rating;
    struct film * next;    //存放下一个元素的地址。 
};

如上结构,就是一个链表的简单结构,每次拿到链表中的一个元素,就可以根据next属性拿到下一个元素。
也可以增加一个pre属性,用于存储该元素上一个元素的地址,即双向链表。

#define TSIZE 45
struct film{
    char title[TSIZE];
    int rating;
    struct film * pre;  //上一个元素的地址
    struct film * next; //下一个元素的地址
};

抽象数据类型(ADT),从链表到列表

一个列表需要有以下方法:
1. 初始化列表
2. 向列表末尾添加元素
3. 判断列表是否为空
4. 获取列表元素数量
5. 访问列表中每个项目来做操作
6. 在列表中任意位置插入元素
7. 从列表中删除一个元素
8. 取出列表中的一个元素
9. 替换列表中的一个元素
10. 在列表中搜索一个元素

需要注意的

  1. 在处理列表时,需要用一个临时变量存储当前的元素
  2. 列表的第一个元素的地址需要一直记录着,如果直接操作原始变量,会导致指针混乱

最后

PHP的数组功能强大,使用起来简单便捷,这些都是底层C的功劳,学好C,是通往PHP大神的必经之路!

代码

list.h头文件

#ifndef LIST_H_
#define LIST_H_

#include <stdbool.h>

#define LSIZE 45

struct film{
    char title[LSIZE];
    int rating;
};

typedef struct film Item;

typedef struct node{
    Item item;
    struct node * next;
}Node;

typedef Node * List;

void initList(List * plist);
bool listIsEmpty(List * plist);
bool listIsFull(List * plist);
bool addItem(List * plist, Item item);
void traverse(List * plist, void (*func)(Item item, int index));
unsigned int itemCount(List * plist);
void emptyList(List * plist);
Item * getItem(List * plist, int index);
#endif

list.c接口实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include "list.h"

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

void initList(List * plist){
    *plist = NULL;
}

bool listIsEmpty(List * plist){
    if(*plist == NULL){
        return true;
    }
    return false;
}

bool listIsFull(List * plist){
    Node * pt;
    pt = (Node *) malloc(sizeof(Node));
    if(pt == NULL){
        free(pt);
        return true;
    }else{
        free(pt);
        return false;
    }
}

bool addItem(List * plist, Item item){
    Node * pnode;
    Node * current = *plist;
    pnode = (Node *)malloc(sizeof(Node));
    if(pnode == NULL){
        return false;
    }
    copyItemToNode(item, pnode);

    pnode->next = NULL;
    if(*plist == NULL){ //如果列表中没有项目,则添加的是第一个项目
        *plist = pnode;
    }else{
        //如果不是第一个项目,则找到列表中节点为空的项目,将新项目的地址存进去
        while(current->next != NULL){
            current = current->next;
        }
        current->next = pnode;
    }
    return true;
}

void traverse(List * plist, void (*func)(Item item, int index)){
    Node * current = *plist;
    int count = 0;
    while(current != NULL){
        (*func)(current->item, count + 1);
        current = current->next;
        count++;
    }
}

unsigned int itemCount(List * plist){
    unsigned int count = 0;
    Node * current = *plist;
    while(current != NULL){
        count++;
        current = current->next;
    }
    return count;
}

Item * getItem(List * plist, int index){
    Node * current = *plist;
    int count = 0;
    while((current != NULL)){
        if(count == index) {
            return &current->item;
        }
        current = current->next;
        count++;
    }
    return NULL;
}

void emptyList(List * plist){
    Node * temp;
    while((*plist) != NULL){
        temp = *plist;
        free(*plist);
        *plist = temp->next;
    }
}

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

main.c主文件

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

void showItem(Item item, int index);
int main(){
    List film_list;
    Item film;

    initList(&film_list);

    if(listIsFull(&film_list)){
        fprintf(stderr, "列表已满!\n");
        exit(1);
    }

    puts("请输入电影名称:");
    while(gets(film.title) != NULL && film.title[0] != '\0'){
        puts("请输入电影评分<1-10>:");
        scanf("%d", &film.rating);
        while(getchar() != '\n'){
            continue;
        }

        if(!addItem(&film_list, film)){
            fprintf(stderr, "添加失败!\n");
            break;
        }

        if(listIsFull(&film_list)){
            fprintf(stderr, "列表已满!\n");
            break;
        }

        puts("下一个电影的名称(输入空行退出):");
    }

    if(listIsEmpty(&film_list)){
        puts("电影列表为空!");
    }else{
        puts("当前的电影列表:");
        traverse(&film_list,showItem);
    }

    printf("当前电影数量:%u\n", itemCount(&film_list));
    showItem(*getItem(&film_list, 2), 3);
    emptyList(&film_list);
    return 0;
}

void showItem(Item item, int index){
    printf("第%d部:<%s> 评分:%d\n", index, item.title, item.rating);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值