linux 内核的链表操作方法
来源:互联网 发布:php调用 编辑:程序博客网 时间:2024/06/05 15:59
/* *************************************************************** * File Name: list_head_struct.c * Declaration: * linux 内核中的链表操作 * struct lish_head 双向链表结构 * 链表结构中不包含用户数据结构,而是用户数据结构包含链表结构 * 可以在一个链表中有不同的数据类型 * 也可以不同的数据类型链表中用同一套链表操作函数 * 而不需要根据不同类型做多一套链表函数 * 主要由宏实现 * list_entry() 宏返回节点的宿主结构指针 * * c学习理解: * value = ({代码段}); * value = 代码段中最后一个语句的值??? * 相当于汇编里 ax eax rax 寄存器传值??? * * 这个程序用同一套宏或函数操作两个不同的用户自定义结构 * Point 坐标X Y * Pet 宠物名及类型 * * 1: 输入3个坐标加入坐标链表 * 2: 输入3个宠物加入宠物链表 * 3: 输出两个链表内容 * 4: 释放所用内存空间 * * Author: jiaga * Created Time: 2014年09月21日 星期日 11时09分14秒 *************************************************************** */#include <stdio.h>#include <stdlib.h>#define LEN 20/* linux 中不使用的内存地址??? 用于初始化??? */#define POISON_POINTER_DELTA 0#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)/** * 声明并初始化循环链表头,前后都指向自己 * 亚节点,实际表起始位置 head->next */#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)/* 用于从链表节点指针取得宿主结构类型的指针 */#define offsetof(type, member) ((size_t)&((type *)0)->member)#define container_of(ptr, type, member) ({ \ const __typeof( ((type*)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type, member) );}) \#define list_entry(ptr, type, member) \ container_of(ptr, type, member)/* 遍历链表 */#define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)#define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; \ pos != (head); \ pos = n, n = pos->next)struct list_head { struct list_head *next, *prev;};/* 用户数据结构 将list_head 嵌入其中 *//* 坐标 */typedef struct point { struct list_head point_node; float x; float y;}Point;/* 宠物名及类型 */typedef struct pet { struct list_head pet_node; char name[LEN]; char kind[LEN];}Pet;void INIT_LIST_HEAD(struct list_head *list){ list->next = list; list->prev = list;}static void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next){ next->prev = new; new->next = next; new->prev = prev; prev->next = new;}void list_add(struct list_head *new, struct list_head *head){ __list_add(new, head, head->next);}static void __list_del(struct list_head *prev, struct list_head *next){ next->prev = prev; prev->next = next;}void list_del(struct list_head *entry){ __list_del(entry->prev, entry->next); entry->next = NULL; entry->prev = NULL; /* entry->next = LIST_POISON2; entry->prev = LIST_POISON2; */}/* user for debug, print addr msg */void print_node_addr(struct list_head *head){ printf("curr: %p next: %p prev: %p\n", head, head->next, head->prev);}Point* new_point(){ Point *point; point = (Point *)malloc(sizeof(Point)); printf("Please input x and y: "); scanf(" %f %f", &point->x, &point->y); INIT_LIST_HEAD(&point->point_node); return point;}Pet* new_pet(){ Pet *pet; pet = (Pet *)malloc(sizeof(Pet)); printf("Please input pet name: "); scanf("%s", pet->name); printf("Please input pet kind: "); scanf("%s", pet->kind); INIT_LIST_HEAD(&pet->pet_node); return pet;}int main(void){ LIST_HEAD(points); /* 声明链表头结点 */ LIST_HEAD(pets); /* 声明链表头结点 */ /* 这两个可以通用,相当于for循环中的i, 为了看得明白多声明一个 */ struct list_head *point; /* 遍历索引 */ struct list_head *pet; /* 遍历索引 */ struct list_head *tmp; /* 用于释放节点时临时保存下一节点的指针 */ Point *c_point; /* 用于操作用户数据类型 */ Pet *c_pet; /* 用于操作用户数据类型 */ int i; /* 创建新结点并获取输入 */ for (i = 0; i < 3; i++) { c_point = new_point(); /* 获取输入 */ list_add(&c_point->point_node, &points); /* 加入链表 */ } for (i = 0; i < 3; i++) { c_pet = new_pet(); /* 获取输入 */ list_add(&c_pet->pet_node, &pets); /* 加入链表 */ } list_for_each(point, &points) { c_point = list_entry(point, Point, point_node); printf("x = %.2f y = %.2f\n", c_point->x, c_point->y); } list_for_each(pet, &pets) { c_pet = list_entry(pet, Pet, pet_node); printf("name: %-10s kind: %-10s\n", c_pet->name, c_pet->kind); } /* 从points链表中删除节点并释放内存空间 */ list_for_each_safe(point, tmp, &points) { c_point = list_entry(point, Point, point_node); list_del(point); free(c_point); } /* * 不用list_for_each_safe宏的删除操作 point = points.next; while (point != &points) { tmp = point->next; c_point = list_entry(point, Point, point_node); list_del(point); point = tmp; free(c_point); } */ /* 删除 pets 链表节点 */ pet = pets.next; while (pet!= &pets) { tmp = pet->next; c_pet = list_entry(pet, Pet, pet_node); list_del(pet); pet = tmp; free(c_pet); } return 0;}
运行结果:
Please input x and y: <strong>1.2 2.3</strong>Please input x and y: <strong>3.4 4.5</strong>Please input x and y: <strong>5.6 6.7</strong>Please input pet name: <strong>Mickey</strong>Please input pet kind: <strong>Mouse</strong>Please input pet name: <strong>Donald</strong>Please input pet kind: <strong>Duck</strong>Please input pet name: <strong>Xiyangyang</strong>Please input pet kind: <strong>Sheep</strong>x = 5.60 y = 6.70x = 3.40 y = 4.50x = 1.20 y = 2.30name: Xiyangyang kind: Sheep name: Donald kind: Duck name: Mickey kind: Mouse
0 0
- linux 内核的链表操作方法
- 【挖坑】[linux]markdown的操作方法
- Linux内核的链表
- Linux内核---60.linux内核链表list的使用
- 内核中的文件操作方法
- Linux驱动直接访问控制器的操作方法
- linux对于服务器的一些常用操作方法
- 更改linux用户登录shell的操作方法
- linux内核链表的实现
- linux 内核的链表操作
- linux内核链表的实现
- Linux内核链表的精彩实现
- linux 内核的链表操作
- linux内核的链表机制
- linux内核源码里的链表
- linux 内核链表的应用
- Linux内核双向链表的实现
- Linux内核链表的一点随笔
- 2014.10.03
- Java实现堆以及堆排序
- 测试技术学习
- diff 与 patch
- GestureDetector.OnGestureListener 详解
- linux 内核的链表操作方法
- Unity配合VS2012来使用的一些插件集合
- C/C++程序员必须熟练应用的开源项目
- Leetcode:reverse_integer
- 关于char 型 的 存储实质(asc2码表的)
- 如何成为一个牛逼的C/C++程序员?
- 深入理解java虚拟机系列(一):java内存区域与内存溢出异常
- java7K面试题之银行业务调度系统
- 【Android开发经验】android:windowSoftInputMode属性详解