邱俊的空间

Simple is beautiful.
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C和指针(续)

Posted on 2009-05-25 23:41  abruzzi  阅读(1561)  评论(3编辑  收藏  举报

前言

上一篇《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 insert(node);//插入一个新的节点到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 
*= list->_this->
head;
    Node 
*=
 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

 

可以看出,程序正如预期的那样运行(前一项为节点在内存中的地址,后一项为节点的值),如果大家有兴趣,可以将上一篇《C和指针》s中的Executor装入一个List实现一个Executor的管理器,加入get方法,同时考虑多线程的状态,即可自己完成一个线程池的实现。