【darknet 源码解析-01】list.h 与 list.c

本文深入解析Darknet源码中的链表实现,包括初始化、插入、删除等核心操作,以及节点存储空间的释放方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列为darknet源码解析,本次解析src/list.h 与 src/list.c 两个。

list.h 中的包含的代码如下:

#ifndef LIST_H
#define LIST_H
#include "darknet.h"

list *make_list(); // 初始化链表
// 按值查找,注意这里的值是 void类型空指针,emmmm, list.c未定义,
int list_find(list *l, void *val); 

//
void list_insert(list *, void *);


void free_list_contents(list *l);

#endif

首先,我们分析list.h 中的源码,基础数据结构list 定义在 darknet.h 中,其定义如下:

typedef struct node{
    void *val; // 当前节点的内容是一个void类型的空指针
    struct node *next; // 指向当前节点的下一节点
    struct node *prev; //  指向当前节点的上一节点
} node;

typedef struct list{
    int size; // 当前list 的长度
    node *front; // 头指针,指针链表第一个节点
    node *back;  //尾指针,指针链表最后一个节点
} list;

可以发现,list就是我们熟悉的链表,可以发现在 list.h 中定义了4个函数,下面我们分别对解析这4个函数,我们将注解写在 list.c中,如下:

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


// 初始化链表
list *make_list()
{
        // 分配存储空间
	list *l = malloc(sizeof(list));
        // 初始化链表长度、头指针、尾指针
	l->size = 0; 
	l->front = 0;
	l->back = 0;
	return l;
}

/*
void transfer_node(list *s, list *d, node *n)
{
    node *prev, *next;
    prev = n->prev;
    next = n->next;
    if(prev) prev->next = next;
    if(next) next->prev = prev;
    --s->size;
    if(s->front == n) s->front = next;
    if(s->back == n) s->back = prev;
}
*/

// 链表的删除操作,删除尾指针所指节点,即最后一个节点
void *list_pop(list *l){
    // 如果链表为空
    if(!l->back) return 0;
    // node *b 指向最后一个节点
    node *b = l->back;
    void *val = b->val;
    // 更新尾指针,尾指针指向b的前一节点,即倒数第二节点。
    l->back = b->prev;
    // 如果倒数第二节点存在
    if(l->back) l->back->next = 0; //尾指针next置为null
    free(b); // 释放最后一个节点的存储空间
    --l->size; // 链表长度 -1
    
    return val; // 返回被删除节点保存的值
}

// 链表按序插入操作
void list_insert(list *l, void *val)
{
        // 为新节点申请存储空间
	node *new = malloc(sizeof(node));
        // 赋值
	new->val = val;
	new->next = 0; // next置null
        
        // 如果链表l 尾指针为空,则说明此时链表l长度为0
	if(!l->back){
		l->front = new; // 更新头指针
		new->prev = 0; // 此时该节点为头节点,故头节点的上一节点为null
	}else{ //如果链表l 尾指针非空,则说明此时l长度 >=1
		l->back->next = new; // 更新当前节点的上一节点的next指针域
		new->prev = l->back; // 更新当前节点的prev指针域
	}
	l->back = new; // 更新链表l的尾指针
	++l->size; // 链表长度 +1 
}

// 释放链表节点的存储空间,从节点n开始释放,一直释放到最后一个节点。
void free_node(node *n)
{
	node *next;
	while(n) {
		next = n->next; // 获取下一节点地址
		free(n); // 释放当前节点存储空间
		n = next; //更新n,n指向下一节点
	}
}

// 释放整个链表l的存储空间
void free_list(list *l)
{
	free_node(l->front);
	free(l);
}

// 对链表所有节点的值【节点中值为void 类型指针】 的存储空间释放
void free_list_contents(list *l)
{
	node *n = l->front;
	while(n){
		free(n->val);
		n = n->next;
	}
}

// 二维指针,这里的操作是将链表l中所有节点的值进行保存,
// 因为每个节点里保存的值是 void类型的指针,故指针的指针,即二维指针
void **list_to_array(list *l)
{
    // 分配存储空间,长度l-size, 每个空间大小为一个void类型指针
    void **a = calloc(l->size, sizeof(void*));
    int count = 0;
    node *n = l->front; // 工作指针n指向头节点
    while(n){
        // 将工作指针n指向节点的值保存到a中
        a[count++] = n->val;
        n = n->next;// 更新工作指针
    }
    return a;
}

完,

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值