1. double_list.h
# ifndef __DOUBLE_LIST_H__
# define __DOUBLE_LIST_H__
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <errno.h>
# ifdef __cplusplus
extern "C" {
# endif
typedef struct list_node_s {
char * data;
int data_count;
} list_node_t;
typedef struct double_list_s {
struct double_list_s * prev;
struct double_list_s * next;
list_node_t * node;
} double_list_t;
double_list_t * init_list ( ) ;
int is_list_empty ( const double_list_t * head) ;
int get_list_size ( const double_list_t * head) ;
void print_list_info ( const double_list_t * head) ;
void push_front ( double_list_t * head, const char * data) ;
void push_back ( double_list_t * head, const char * data) ;
void insert ( double_list_t * pos, const char * data) ;
void pop_front ( double_list_t * head) ;
void pop_back ( double_list_t * head) ;
void erase ( double_list_t * pos) ;
void remove_list_by_data ( double_list_t * head, const char * data) ;
void remove_list_by_all_data ( double_list_t * head, const char * data) ;
void destroy_list ( double_list_t * head) ;
# ifdef __cplusplus
}
# endif
# endif
2. double_list.c
# include "double_list.h"
static int s_list_size = 0 ;
static double_list_t * create_list_node ( const char * data)
{
double_list_t * new_list = NULL ;
do {
new_list = ( double_list_t * ) calloc ( 1 , sizeof ( double_list_t) ) ;
if ( NULL == new_list) {
perror ( "calloc new_list fail" ) ;
break ;
}
list_node_t * new_node = NULL ;
new_node = ( list_node_t * ) calloc ( 1 , sizeof ( list_node_t) ) ;
if ( NULL == new_node) {
perror ( "calloc new_node fail" ) ;
if ( new_list) {
free ( new_list) ;
new_list = NULL ;
}
break ;
}
new_node-> data = ( char * ) calloc ( 1 , strlen ( data) + 1 ) ;
if ( NULL == new_node-> data) {
perror ( "calloc new_node->data fail" ) ;
if ( new_node) {
free ( new_node) ;
new_node = NULL ;
}
if ( new_list) {
free ( new_list) ;
new_list = NULL ;
}
break ;
}
new_node-> data_count = ++ s_list_size;
strcpy ( new_node-> data, data) ;
new_list-> node = new_node;
new_list-> prev = NULL ;
new_list-> next = NULL ;
} while ( 0 ) ;
return new_list;
}
double_list_t * init_list ( )
{
char * null_data = "null_data" ;
double_list_t * head = create_list_node ( null_data) ;
head-> prev = head;
head-> next = head;
return head;
}
int is_list_empty ( const double_list_t * head)
{
if ( NULL == head) {
return 1 ;
}
double_list_t * prev_list = head-> prev;
double_list_t * next_list = head-> next;
return head == prev_list && head == next_list;
}
int get_list_size ( const double_list_t * head)
{
int list_size = 0 ;
if ( head && head-> next && head-> next-> node) {
list_size = head-> next-> node-> data_count;
}
return list_size;
}
void print_list_info ( const double_list_t * head)
{
if ( NULL == head) {
return ;
}
if ( head-> node) {
printf ( "\t%-s -> " , head-> node-> data) ;
}
const double_list_t * cur = head;
for ( cur = head-> next; cur != head; cur = cur-> next) {
if ( cur-> node) {
printf ( "%-s -> " , cur-> node-> data) ;
}
}
if ( cur-> node) {
printf ( "%-s\n" , cur-> node-> data) ;
}
}
void push_front ( double_list_t * head, const char * data)
{
# ifndef USE_INTERNEL
double_list_t * new_list = create_list_node ( data) ;
if ( NULL == new_list || NULL == head) {
return ;
}
double_list_t * next_list = head-> next;
head-> next = new_list;
new_list-> prev = head;
new_list-> next = next_list;
next_list-> prev = new_list;
# else
insert ( head-> next, data) ;
# endif
}
void push_back ( double_list_t * head, const char * data)
{
# ifndef USE_INTERNEL
double_list_t * new_list = create_list_node ( data) ;
if ( NULL == new_list || NULL == head) {
return ;
}
double_list_t * tail_list = head-> prev;
tail_list-> next = new_list;
new_list-> prev = tail_list;
new_list-> next = head;
head-> prev = new_list;
# else
insert ( head-> prev, data) ;
# endif
}
void insert ( double_list_t * pos, const char * data)
{
double_list_t * new_list = create_list_node ( data) ;
if ( NULL == new_list || NULL == pos) {
return ;
}
double_list_t * pos_prev_list = pos-> prev;
pos_prev_list-> next = new_list;
new_list-> prev = pos_prev_list;
new_list-> next = pos;
pos-> prev = new_list;
}
static double_list_t * find_list_by_data ( double_list_t * head, const char * data)
{
if ( is_list_empty ( head) || NULL == data) {
return NULL ;
}
double_list_t * cur = head;
for ( cur = head-> next; head != cur; cur = cur-> next) {
if ( cur-> node) {
if ( 0 == strcmp ( cur-> node-> data, data) ) {
return cur;
}
}
}
return NULL ;
}
static void free_list_node ( double_list_t * pos)
{
if ( NULL == pos) {
return ;
}
if ( pos-> node && pos-> node-> data) {
pos-> node-> data_count -= 1 ;
free ( pos-> node-> data) ;
pos-> node-> data = NULL ;
free ( pos-> node) ;
pos-> node = NULL ;
}
free ( pos) ;
pos = NULL ;
}
void pop_front ( double_list_t * head)
{
if ( NULL == head || is_list_empty ( head) ) {
return ;
}
# ifndef USE_INTERNEL
double_list_t * next_list = head-> next;
double_list_t * next_next_list = next_list-> next;
head-> next = next_next_list;
next_next_list-> prev = head;
free_list_node ( next_list) ;
# else
erase ( head-> next) ;
# endif
}
void pop_back ( double_list_t * head)
{
if ( NULL == head || is_list_empty ( head) ) {
return ;
}
# ifndef USE_INTERNEL
double_list_t * tail_list = head-> prev;
double_list_t * tail_prev_list = tail_list-> prev;
tail_prev_list-> next = head;
head-> prev = tail_prev_list;
free_list_node ( tail_list) ;
# else
erase ( head-> prev) ;
# endif
}
void erase ( double_list_t * pos)
{
if ( NULL == pos) {
return ;
}
double_list_t * pos_prev_list = pos-> prev;
double_list_t * pos_next_list = pos-> next;
pos_prev_list-> next = pos_next_list;
pos_next_list-> prev = pos_prev_list;
free_list_node ( pos) ;
}
void remove_list_by_data ( double_list_t * head, const char * data)
{
double_list_t * pos = find_list_by_data ( head, data) ;
erase ( pos) ;
}
void remove_list_by_all_data ( double_list_t * head, const char * data)
{
if ( NULL == head || NULL == data) {
return ;
}
double_list_t * cur = head-> next;
double_list_t * next_list = NULL ;
double_list_t * prev_list = NULL ;
while ( head != cur) {
next_list = cur-> next;
if ( cur-> node && 0 == strcmp ( cur-> node-> data, data) ) {
prev_list = cur-> prev;
prev_list-> next = next_list;
next_list-> prev = prev_list;
free_list_node ( cur) ;
}
cur = next_list;
}
}
static void clear_list ( double_list_t * head)
{
if ( NULL == head) {
return ;
}
double_list_t * cur = head-> next;
double_list_t * next_list = NULL ;
for ( ; head != cur; cur = next_list) {
next_list = cur-> next;
free_list_node ( cur) ;
}
free_list_node ( cur) ;
}
void destroy_list ( double_list_t * head)
{
clear_list ( head) ;
}
3. test_double_list.c
# include "double_list.h"
void test ( )
{
printf ( "init list\n" ) ;
double_list_t * list_head = init_list ( ) ;
printf ( "list size : %d\n" , get_list_size ( list_head) ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
if ( is_list_empty ( list_head) ) {
printf ( "\nlist is empty\n" ) ;
} else {
printf ( "\nlist is not empty\n" ) ;
}
printf ( "\npush_front hello\n" ) ;
push_front ( list_head, "hello" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\npush_back world\n" ) ;
push_back ( list_head, "world" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\ninsert list_head hi\n" ) ;
insert ( list_head, "hi" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\ninsert list_head->next->next emo\n" ) ;
insert ( list_head-> next-> next, "emo" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\ninsert list_head->next orz\n" ) ;
insert ( list_head-> next, "orz" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\npush_front emo\n" ) ;
push_front ( list_head, "emo" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\npush_front emo\n" ) ;
push_front ( list_head, "emo" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
if ( is_list_empty ( list_head) ) {
printf ( "\nlist is empty\n" ) ;
} else {
printf ( "\nlist is not empty\n" ) ;
}
printf ( "list size : %d\n" , get_list_size ( list_head) ) ;
printf ( "\nremove_list_by_data emo\n" ) ;
remove_list_by_data ( list_head, "emo" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\nremove_list_by_all_data emo\n" ) ;
remove_list_by_all_data ( list_head, "emo" ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\npop_front\n" ) ;
pop_front ( list_head) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
printf ( "\npop_back\n" ) ;
pop_back ( list_head) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
if ( ! is_list_empty ( list_head) ) {
printf ( "\nerase list_head->next\n" ) ;
erase ( list_head-> next) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
}
printf ( "\ndestroy list\n" ) ;
destroy_list ( list_head) ;
list_head = NULL ;
printf ( "list size : %d\n" , get_list_size ( list_head) ) ;
printf ( "\nlist info :\n" ) ;
print_list_info ( list_head) ;
if ( is_list_empty ( list_head) ) {
printf ( "\nlist is empty\n" ) ;
} else {
printf ( "\nlist is not empty\n" ) ;
}
}
int main ( void )
{
test ( ) ;
return 0 ;
}
4. Makefile
.PHONY: clean
CC = gcc
CFLAGS = -g -Wall -DDEBUG
EXTRA_FLAGS = -DUSE_INTERNEL
# match *.c
SOURCE = $(wildcard ./*.c)
# replace * with *.c
BIN = $(patsubst %.c, %, $(notdir $(SOURCE)))
$(BIN): $(SOURCE)
$(CC) $(CFLAGS) $(EXTRA_FLAGS) $(SOURCE) -o $@
clean:
rm -rf $(BIN)