第一章 从双向链表学习设计

1.3 Wirte once, run anywhere (WORA)

  • 让C++可以调用
# ifdef __cplusplus
extern "C" {
#endif

//.....

# ifdef __cplusplus
}
#endif

1.4 拥抱变化

/*
 * File:    dlist.h
 */

#ifndef DLIST_H
#define DLIST_H

#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/

typedef enum _DListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_STOP,
	DLIST_RET_PARAMS,
	DLIST_RET_FAIL
}DListRet;

struct _DList;
typedef struct _DList DList;

typedef DListRet (*DListDataPrintFunc)(void* data);

DList* dlist_create(void);

DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
DListRet dlist_print(DList* thiz, DListDataPrintFunc print);

void dlist_destroy(DList* thiz);

#ifdef __cplusplus
}
#endif/*__cplusplus*/

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
};

static DListNode* dlist_node_create(void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_node_destroy(DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		free(node);
	}
	return;
}

DList* dlist_create(void)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL){
		thiz->first = NULL;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0){
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	if((node = dlist_node_create(data)) == NULL) {
		return DLIST_RET_OOM; 
	}

	if(thiz->first == NULL) {
		thiz->first = node;
		return DLIST_RET_OK;
	}

	cursor = dlist_get_node(thiz, index, 1);
	
	if(index < dlist_length(thiz)) {
		if(thiz->first == cursor) {
			thiz->first = node;
		}else{
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	}else{
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		if(cursor == thiz->first){
			thiz->first = cursor->next;
		}

		if(cursor->next != NULL){
			cursor->next->prev = cursor->prev;
		}

		if(cursor->prev != NULL){
			cursor->prev->next = cursor->next;
		}

		dlist_node_destroy(cursor);
	}

	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		*data = cursor->data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		cursor->data = data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		length++;
		iter = iter->next;
	}

	return length;
}

DListRet dlist_print(DList* thiz, DListDataPrintFunc print)
{
	DListRet ret = DLIST_RET_OK;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		print(iter->data);
		iter = iter->next;
	}

	return ret;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = thiz->first;
	DListNode* next = NULL;

	while(iter != NULL){
		next = iter->next;
		dlist_node_destroy(iter);
		iter = next;
	}

	thiz->first = NULL;
	free(thiz);

	return;
}
/*
* 1.4 拥抱拜变化 
*/

/* 
 * File:    dlist.c
 */

#include <stdio.h>
#include <assert.h>
#include "dlist.h"

static DListRet print_int(void* data)
{
	printf("%d ", (int)data);

	return DLIST_RET_OK;
}

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 100;
	DList* dlist = dlist_create();

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
	}
	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == DLIST_RET_OK);
	}

	dlist_print(dlist, print_int);
	printf("\n");

	dlist_destroy(dlist);

	return 0;
}

all:
	gcc -g -m32 dlist.c main.c -o demo
clean:
	rm -f demo

1.5 Don't Repeat Yourself(DRY)

需求描述

  • 对一个存放整数的的双向链表,找出链表中的最大值.
  • 对一个存放整数的的双向链表,累加链表中的所有整数.
/*
 * File:    dlist.h
 */


#ifndef DLIST_H
#define DLIST_H

#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/

typedef enum _DListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_STOP,
	DLIST_RET_PARAMS,
	DLIST_RET_FAIL
}DListRet;

struct _DList;
typedef struct _DList DList;

typedef int (*DListDataCompareFunc)(void* ctx, void* data);
typedef DListRet (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(void);

DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

#ifdef __cplusplus
}
#endif/*__cplusplus*/

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
};

static DListNode* dlist_node_create(void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_node_destroy(DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		free(node);
	}

	return;
}

DList* dlist_create(void)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL) {
		thiz->first = NULL;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0){
		iter = iter->next;
		index--;
	}

	if(!fail_return_last){
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	if((node = dlist_node_create(data)) == NULL){
		return DLIST_RET_OOM; 
	}

	if(thiz->first == NULL){
		thiz->first = node;
		return DLIST_RET_OK;
	}

	cursor = dlist_get_node(thiz, index, 1);
	
	if(index < dlist_length(thiz)) {
		if(thiz->first == cursor){
			thiz->first = node;
		}else{
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	}else{
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		if(cursor == thiz->first){
			thiz->first = cursor->next;
		}

		if(cursor->next != NULL){
			cursor->next->prev = cursor->prev;
		}

		if(cursor->prev != NULL){
			cursor->prev->next = cursor->next;
		}

		dlist_node_destroy(cursor);
	}

	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		*data = cursor->data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		cursor->data = data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		length++;
		iter = iter->next;
	}

	return length;
}

DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	DListRet ret = DLIST_RET_OK;
	DListNode* iter = thiz->first;

	while(iter != NULL && ret != DLIST_RET_STOP){
		ret = visit(ctx, iter->data);
		iter = iter->next;
	}

	return ret;
}

int   dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		if(cmp(ctx, iter->data) == 0){
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = thiz->first;
	DListNode* next = NULL;

	while(iter != NULL){
		next = iter->next;
		dlist_node_destroy(iter);
		iter = next;
	}

	thiz->first = NULL;
	free(thiz);

	return;
}


/*
 * File:    main.c
 */

#include <stdio.h>
#include "dlist.h"
#include <assert.h>

static DListRet sum_cb(void* ctx, void* data)
{
	long long* result = ctx;
	*result += (int)data;

	return DLIST_RET_OK;
}

typedef struct _MaxCtx
{
	int is_first;
	int max;
}MaxCtx;

static DListRet max_cb(void* ctx, void* data)
{
	MaxCtx* max_ctx = ctx;
	if(max_ctx->is_first) {
		max_ctx->is_first = 0;
		max_ctx->max = (int)data;
	}else if(max_ctx->max < (int)data){
		max_ctx->max = (int)data;
	}

	return DLIST_RET_OK;
}

static DListRet print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return DLIST_RET_OK;
}

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 100;
	long long sum = 0;
	MaxCtx max_ctx = {.is_first = 1, 0};
	DList* dlist = dlist_create();

	for(i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
	}

	dlist_foreach(dlist, print_int, NULL);
	dlist_foreach(dlist, max_cb, &max_ctx);
	dlist_foreach(dlist, sum_cb, &sum);

	printf("\nsum=%lld max=%d\n", sum, max_ctx.max);
	dlist_destroy(dlist);

	return 0;
}

all:
	gcc -g -m32 dlist.c main.c -o demo

clean:
	rm -f demo

1.6 你的数据放在哪里

需求描述

对一个存放字符串的双向链表,把存放在其中的字符串转换成大写字母.


/*
 * File: dlist_toupper.c
 */

#include "dlist.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>

static DListRet str_toupper(void* ctx, void* data)
{
	char* p = (char*)data;
	if(p != NULL){
		while(*p != '\0'){
			if(islower((*p))){
				*p = toupper(*p);
			}
			p++;
		}
	}

	return DLIST_RET_OK;
}

static DListRet str_print(void* ctx, void* data)
{
	printf("%s\n", (char *)data);
	
	return DLIST_RET_OK;
}

/* 双向链表中存放常量字符串,转换时出现段错误*/
static void demo_const(void)
{
	DList* dlist = dlist_create(NULL, NULL);
	dlist_append(dlist, "It");
	dlist_append(dlist, "is");
	dlist_append(dlist, "OK");
	dlist_append(dlist, "!");
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_destroy(dlist);

	return ;
}

/* 双向链表中存放的是临时变量,转换后发现所有字符串都一样*/
static void demo_temp(void)
{
	char str[256] = {0};
	DList* dlist = dlist_create(NULL, NULL);
	strcpy(str, "It");
	dlist_append(dlist, str);
	strcpy(str, "is");
	dlist_append(dlist, str);
	strcpy(str, "OK");
	dlist_append(dlist, str);
	strcpy(str, "!");
	dlist_append(dlist, str);
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_foreach(dlist, str_print, NULL);
	dlist_destroy(dlist);

	return ;
}

static void data_free(void* ctx, void* data)
{
	free(data);

	return;
}

/*存放时,复制了数据,但没有释放所分配的内存*/
static void demo_heap(void)
{
	DList* dlist = dlist_create(data_free, NULL);
	dlist_append(dlist, strdup("It"));
	dlist_append(dlist, strdup("is"));
	dlist_append(dlist, strdup("OK"));
	dlist_append(dlist, strdup("!"));
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_foreach(dlist, str_print, NULL);
	dlist_destroy(dlist);

	return ;
}

int main(int argc, char* argv[])
{
	demo_temp();
	demo_heap();
	demo_const();

	return 0;
}
/* 
 * bss.c 
 * */

/* 未初始化的全局变量(.bss段) */
int bss_array[1024 * 1024];

int main(int argc, char* argv[])
{
	return 0;
}
/*
 * data.c
 */

/* 初始化过的全局变量(.data段) */
int data_array[1024 * 1024] = {1};

int main(int argc, char* argv[])
{
	return 0;
}
/*
 * File: heap_error.c
 */
 
#include <stdlib.h>
#include <string.h>

/*# valgrind --tool=memcheck --leak-check=full ./heap_error */

int main(int argc, char* argv[])
{
	/*memory leak and buffer overflow.*/
	char* str = malloc(10);
	strcpy(str, "123456788900");

	return 0;
}
ARCH=-m32
all:
	gcc -g ${ARCH} toupper.c -o toupper_test
	gcc -g ${ARCH} dlist.c dlist_toupper.c -o dlist_toupper_test
	gcc -g ${ARCH} bss.c -o bss.exe
	gcc -g ${ARCH} data.c -o data.exe
	gcc -g ${ARCH} heap_error.c -o heap_error_test
clean:
	rm -f *test *.exe