欢迎光临散文网 会员登陆 & 注册

P87-P90

2023-07-08 23:58 作者:取法于一  | 我要投稿

https://www.bilibili.com/video/BV18p4y167Md?p=87&vd_source=90f77914d35a141cd8083716ada7726e

有关llist_travel(handler,print_s)遍历链表打印输出的代码:

llist.h
    typedef void llist_op(const void *);
    void llist_travel(LLIST *,llist_op *);

main.c
    static void print_s(const void *record)
    {
        const struct score_st *r = record;
        printf("%d %s %d %d\n",r->id,r->name,r->math,r->chinese);                                                                  
    }

    llist_travel(handler,print_s);

llist.c
    void llist_travel(LLIST *ptr,llist_op *op)
    {
        struct llist_node_st *cur;

        for(cur = ptr->head.next; cur != &ptr->head; cur = cur->next)
                op(cur->data);
       
    }


考虑通用性,llist_travel()在遍历链表之后会遇到问题,不知道*data里面的成员是什么,因为是用户创建的,无法提前定义。
所以需要用户提供一个输出每个成员的函数。将用户提供的函数作为参数,就可以解决这个问题。这就是回调函数。这就得有一个接口,告诉用户回调函数的形式。

首先来看llist.h里的typedef void llist_op(const void *);这行代码,这是接口函数的声明,为什么这么写,考虑到是打印输出,默认不需要返回值,所以形式是void (),那么里面的参数呢?考虑到接口要打印输出各种类型的值,所以参数是指针,因为指针可以指向各种类型的数据,并且指针指向的类型是不确定的,用void。那么形式就是void   (void *);然后取一别名,llist_op。

那么用户就可以指定打印输出的数据类型和成员名也就是print_s();函数里面两行。

llist_travel();函数也可以通过回调函数打印输出无法提前定义类型的*data。

理解了这个,后面的find,delete,fetch就容易了。下面是这几节视频的代码。

llist.h
    #ifndef LLIST_H__                                                                                                                     
    #define LLIST_H__

    #define LLIST_FORWARD   1
    #define LLIST_BACKWARD  2

    typedef void llist_op(const void *);
    typedef int llist_cmp(const void *,const void *);

    struct llist_node_st
    {
        void *data;
        struct llist_node_st *prev;
        struct llist_node_st *next;
    };

    typedef struct
    {
        int size;
        struct llist_node_st head;
    }LLIST;

    LLIST *llist_create(int initsize);

    int llist_insert(LLIST *,const void *data,int mode);


    void *llist_find(LLIST *,const void *key,llist_cmp *);

    int llist_delete(LLIST *,const void *key,llist_cmp *);

    int llist_fetch(LLIST *,const void *key,llist_cmp *,void *data);

                                                                                                                                              
    void llist_travel(LLIST *,llist_op *);

    void llist_destroy(LLIST *);

    #endif

llist.c

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

    #include "llist.h"

    LLIST *llist_create(int initsize)
    {
        LLIST *new;

        new = malloc(sizeof(*new));
        if(new == NULL)
                return NULL;

        new->size =  initsize;
        new->head.data = NULL;
        new->head.prev = &new->head;
        new->head.next = &new->head;

        return new;
    }

    int llist_insert(LLIST *ptr,const void *data,int mode)
    {
        struct llist_node_st *newnode;
        
        newnode = malloc(sizeof(*newnode));
        if(newnode == NULL)
                return -1;

        newnode->data = malloc(ptr->size);
        
        //if(newnode->data == NULL);一个分号找半个小时。
        if(newnode->data == NULL)
                return -2;
        memcpy(newnode->data,data,ptr->size);
                                                                                                                                              
        if(mode == LLIST_FORWARD)
        {
                newnode->prev = &ptr->head;
                newnode->next = ptr->head.next;
    //              newnode->prev->next = newnode;
    //              newnode->next->prev = newnode;
        }
        else    if(mode == LLIST_BACKWARD)
                {
                        newnode->prev = ptr->head.prev;
                        newnode->next = &ptr->head;
    //                      newnode->prev->next = newnode;
    //                      newnode->next->prev = newnode;
                }
                else    //error
                {
                        return -3;
                }
        newnode->prev->next = newnode;
        newnode->next->prev = newnode;
        
        return 0;
    }
                                                                                                                                              
    static struct llist_node_st * find_(LLIST *ptr,const void *key,llist_cmp *cmp)
    {
        struct llist_node_st *cur;
        for(cur = ptr->head.next; cur != &ptr->head; cur = cur->next)
        {
                if(cmp(key,cur->data) == 0)
                        break;
        }

        return cur;
    }

    void *llist_find(LLIST *ptr,const void *key,llist_cmp *cmp)
    {
        return find_(ptr,key,cmp)->data;
    }

    int llist_delete(LLIST *ptr,const void *key,llist_cmp *cmp)
    {
        struct llist_node_st *node;
        node = find_(ptr,key,cmp);

        if(node == &ptr->head)
                return -1;                                                                                                                    

        node->prev->next = node->next;
        node->next->prev = node->prev;
        free(node->data);
        free(node);

        return 0;
    }


    int llist_fetch(LLIST *ptr,const void *key,llist_cmp *cmp,void *data)
    {
        struct llist_node_st *node;
        node = find_(ptr,key,cmp);

        if(node == &ptr->head)
                return -1;
        
        node->prev->next = node->next;
        node->next->prev = node->prev;

        if(data != NULL)
                memcpy(data,node->data,ptr->size);

        free(node->data);                                                                                                                     
        free(node);

        return 0;
    }

    void llist_travel(LLIST *ptr,llist_op *op)
    {
        struct llist_node_st *cur;

        for(cur = ptr->head.next; cur != &ptr->head; cur = cur->next)
                op(cur->data);
        
    }

    void llist_destroy(LLIST *ptr)
    {
        struct llist_node_st *cur,*next;

        for(cur = ptr->head.next; cur != &ptr->head; cur = next)
        {
                next = cur->next;
                free(cur->data);
                free(cur);
        }                                                                                                                                     
        free(ptr);
    }

main.c

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

    #include "llist.h"

    #define NAMESIZE        32

    struct score_st
    {
        int id;
        char name[NAMESIZE];
        int math;
        int chinese;
    };              

    static void print_s(const void *record)
    {
        const struct score_st *r = record;

        printf("%d %s %d %d\n",r->id,r->name,r->math,r->chinese);
    }

    static int id_cmp(const void *key,const void *record)
    {
        const int *k = key;
        const struct score_st *r = record;
        
        return (*k - r->id);
    }

    static int name_cmp(const void *key,const void *record)
    {
        const char *k = key;
        const struct score_st *r = record;
        return strcmp(k,r->name);
    }

    int main()
    {                                                                                                                                             

        LLIST *handler;
        struct score_st tmp;
        int ret,i;
        int id = 3;
        char *del_name = "std6";
        struct score_st *data;

        handler = llist_create(sizeof(struct score_st));
        if(handler == NULL)
                exit(1);

        for(i = 0; i < 7; i++)
        {
                tmp.id = i;
                snprintf(tmp.name,NAMESIZE,"std%d",i);
                tmp.math = rand()%100;
                tmp.chinese = rand()%100;

                ret = llist_insert(handler,&tmp,LLIST_FORWARD);
                if(ret)                                                                                                                       
                        exit(1);

        }

        llist_travel(handler,print_s);

        printf("\n\n");

        ret = llist_delete(handler,&id,id_cmp);
        if(ret)
                printf("llist_delete failed!\n");
        llist_travel(handler,print_s);

        printf("\n\n");

        ret = llist_delete(handler,del_name,name_cmp);//compile
        if(ret)
                printf("llist_delete failed!\n");
        llist_travel(handler,print_s);

    #if 0
        data = llist_find(handler,&id,id_cmp);
        if(data == NULL)
                printf("Can not find!\n");                                                                                                    
        else
                print_s(data);
    #endif
        llist_destroy(handler);

        exit(0);
    }

P87-P90的评论 (共 条)

分享到微博请遵守国家法律