前言
上一篇《C和指针》可能对关于C和指针的有些内容没有说透,下来写了一个链表的实现,当然,也是用C的函数指针来模拟OO的结构来做的。链表结构本身比较复杂(关于指针的使用方面),所以这个例子可能更清晰一些。之所以选List这个例子来说,是因为大家在学校里肯定接触过这个简单数据结构,从一个比较熟悉的例子入手可能比较容易理解一些。
接口定义
可以先看看接口的定义,与Java或者C#类似:
* File: IList.h
* Author: juntao.qiu
*
* Created on May 22, 2009, 2:51 PM
*/
#ifndef _ILIST_H
#define _ILIST_H
typedef struct node{
void *data;
struct node *next;
}Node; //定义List中的元素类型,void * 相当于C中的泛型,可以支持任何结构的节点
typedef struct list{
struct list *_this;
Node *head;
int size;
void (*insert)(void *node);
void (*drop)(void *node);
void (*clear)();
int (*getSize)();
void* (*get)(int index);
void (*print)();
}List; //用head (Node)来维护链表的链!
void insert(void *node);
void drop(void *node);
void clear();
int getSize();
void* get(int index);
void print();
#endif /* _ILIST_H */
接口中定义所有的公开的方法,正如所有的List结构一样,我们定义了
void drop(node);//删除一个指定的节点
void clear();//清空List
int getSize();//取到List的大小
void* get(int index);//取到指定位置的元素
void print();//打印整个List,用于调试
这样几个方法。
接口的实现
然后看看实现,同上篇一样,引入一个标记链表自身的_this指针,通过对这个指针的引用来修改真实对象中的状态。
#include <stdlib.h>
#include "IList.h"
Node *node = NULL;
List *list = NULL;
/* 函数声明块,作用已经在上边解释了*/
void insert(void *node);
void drop(void *node);
void clear();
int getSize();
void print();
void* get(int index);
/* 构造方法 */
List *ListConstruction(){
list = (List*)malloc(sizeof(List));
node = (Node*)malloc(sizeof(Node));
list->head = node;
list->insert = insert;
list->drop = drop;
list->clear = clear;
list->size = 0;
list->getSize = getSize;
list->get = get;
list->print = print;
list->_this = list;
return (List*)list;
}
void ListDeconstruction(){
}
//插入节点,size增加1
void insert(void *node){
Node *current = (Node*)malloc(sizeof(Node));
current->data = node;
current->next = list->_this->head->next;
list->_this->head->next = current;
(list->_this->size)++;
}
//删除一个节点,size减1
void drop(void *node){
Node *t = list->_this->head;
Node *d = NULL;
int i = 0;
for(i;i < list->_this->size;i++){
d = list->_this->head->next;
if(d->data == ((Node*)node)->data){
list->_this->head->next = d->next;
free(d);
(list->_this->size)--;
break;
}else{
list->_this->head = list->_this->head->next;
}
}
list->_this->head = t;
}
//取到指定index的节点
void* get(int index){
Node *node = list->_this->head;
int i = 0;
if(index > list->_this->size){
return NULL;
}else{
for(i;i < index;i++){
node = node->next;
}
if(node != (Node*)0){
return node->data;
}else{
return NULL;
}
}
}
void clear(){
Node *node = NULL;
int i = 0;
for(i;i< list->_this->size;i++){
node = list->_this->head;
list->_this->head = list->_this->head->next;
free(node);
}
list->_this->size = 0;
list = NULL;
}
int getSize(){
return list->_this->size;
}
//调试用,像这种getSize(), print()这种调用,需要注意的是在调用过程中不能对原始指针做任何修改,
//否则可能出现无法预测的错误。
void print(){
Node *node = list->_this->head;
int i = 0;
for(i;i <= list->_this->size;i++){
if(node != (Node*)0){
printf("[%p] = {%s}\n",&node->data, node->data);
node = node->next;
}
}
}
测试
/*
* File: Main.c
* Author: juntao.qiu
*
* Created on May 21, 2009, 4:05 PM
*/
#include <stdio.h>
#include <stdlib.h>
s#include "IList.h"
int main(int argc, char** argv) {
List *list = (List*)ListConstruction();//构造一个新的list
list->insert("Apple");
list->insert("Borland");
list->insert("Cisco");
list->insert("Dell");
list->insert("Electrolux");
list->insert("FireFox");
list->insert("Google");//插入一些节点
list->print();//查看是否插入正确
printf("list size = %d\n",list->getSize());
//删除两个节点,并打印结果查看。
Node node;
node.data = "Electrolux";
node.next = NULL;
list->drop(&node);
node.data = "Cisco";
node.next = NULL;
list->drop(&node);
list->print();
printf("list size = %d\n",list->getSize());
list->clear();
return 0;
}
运行结果
$./ooc
[00489760] = {Google}
[00489730] = {FireFox}
[00489700] = {Electrolux}
[004896D0] = {Dell}
[004896A0] = {Cisco}
[00489670] = {Borland}
[00489640] = {Apple}
list size = 7
[00489760] = {Google}
[00489730] = {FireFox}
[004896D0] = {Dell}
[00489670] = {Borland}
[00489640] = {Apple}
list size = 5
[00489760] = {Google}
[00489730] = {FireFox}
[00489700] = {Electrolux}
[004896D0] = {Dell}
[004896A0] = {Cisco}
[00489670] = {Borland}
[00489640] = {Apple}
list size = 7
[00489760] = {Google}
[00489730] = {FireFox}
[004896D0] = {Dell}
[00489670] = {Borland}
[00489640] = {Apple}
list size = 5
可以看出,程序正如预期的那样运行(前一项为节点在内存中的地址,后一项为节点的值),如果大家有兴趣,可以将上一篇《C和指针》s中的Executor装入一个List实现一个Executor的管理器,加入get方法,同时考虑多线程的状态,即可自己完成一个线程池的实现。