C语言中的内存管理与双向链表

【@.1 简介】

数据结构与内存管理是不可分割的,特别是在C语言中,对于指针的处理必须非常小心。通常我们在用动态内存分配时会调用malloc()函数为指针分配内存,但是在嵌入式编程时我并不喜欢使用malloc系列函数,宁可自己建立一个数组,需要使用时从数组里面分配空间。我曾经的博客《uCOS-II中的内存管理--C语言构建完整的微型动态内存管理机制》一文中介绍了在uCOS中的动态内存管理机制,那种方法的确十分好用,而且实际上我们也经常这样用。现在考虑自己构建一个简单的内存管理,主要用于对链表进行内存分配。下面循序渐进地介绍了几种方法来实现设计双向链表时的内存分配。

【方法一:简单的数组】

最简单的方法就是在全局声明一个数组,将所有链表所需涉及到的内存分配全部放在这里面。这种方法并没有深化到内存管理的地步,没有内存回收、内存分配的完整机制,仅仅是简单的将双向链表与数组链接在一起,可以实现比较初级的功能.

/************************************************************/
#include <stdio.h>

#include <stdlib.h>

void memclr(unsigned char* pdest, int size){

    while(size>0){

        *pdest++=(unsigned char)0;

        size--;

    }

}

#define MAX_SIZE  10

typedef struct {

    void* previous;

    void* next;

    int  value;

}A_Type;

static A_Type array[MAX_SIZE];



void Init_Q(void* start, int size){

    A_Type* ptr1, *ptr2;

    memclr((unsigned char*)start,sizeof(A_Type)*size);

    ptr1 = (A_Type*)start;

    ptr2 = ptr1+1;

    while(size>1){

        ptr1->next = ptr2;

        ptr2->previous = ptr1;

        ptr1++;

        ptr2++;

        size--;

    }

}

int main(void) {

    A_Type *ptr;

    Init_Q(array,MAX_SIZE);

    ptr = &array[0];

    while(ptr != (void*)0){

        printf("%d, ",ptr->value);

        ptr=(A_Type*)ptr->next;

    }

    ptr = &array[5];

    printf("\n");

    while(ptr != (void*)0){

        printf("%d, ",ptr->value);

        ptr = (A_Type*)ptr->previous;

    }

    return EXIT_SUCCESS;

}
/************************************************************/

【方法二:使用malloc动态分配内存】

这种方法是很多人比较喜欢用的。虽然我并不喜欢用它,但是还是写了些这种方法。最大的好处就是,没有了全局变量,可以让程序变得很干净。所有链表中需要用到的内存都是动态分配申请的。

/************************************************************/
#include <stdio.h>

#include <stdlib.h>

typedef struct{

    void * previous;

    void * next;

    int value;

}List_Type;

void  MemClr(unsigned char * pdest, int size){

    while(size>0){

        *pdest++ = (unsigned char)0;

        size--;

    }

}

void  Add_Node(List_Type * preNode, int newValue){

    List_Type * newNode  = (List_Type*)malloc(sizeof(List_Type));

    List_Type * nextNode ;

    if(preNode == (void*)0)

        return ;

    nextNode = (List_Type*)preNode->next;



    MemClr((unsigned char*)newNode, sizeof(List_Type));

    newNode->value = newValue;



    preNode->next = newNode;

    newNode->previous = preNode;

    newNode->next = nextNode;

    if(nextNode != (void*)0)        //if Not the end of the list

        nextNode->previous = newNode;

    //free(newNode); NEVER, EVER free this pointer!!!

}



List_Type * CreateList_Add(int nodeNum){

    List_Type * entry = (List_Type*)malloc(sizeof(List_Type));

    List_Type * ptr1;

    ptr1 = entry;

    MemClr((unsigned char*)entry,sizeof(List_Type));

    while(nodeNum>1){

        Add_Node(ptr1, 0);

        ptr1 = (List_Type*)ptr1->next;

        nodeNum--;

    }

    return entry;

}

List_Type * FindIndex_Front(List_Type *entry, int index_f){

    List_Type * ptr = entry;

    while(index_f>0){

        ptr = (List_Type* )ptr->next;

        if(ptr == (void*)0)

            return (void*)0;   //index_f overflow

        index_f--;

    }

    return ptr;

}

void Print_ToEnd(List_Type * ptr){

    while(ptr != (void*)0){

        printf("%d, ",ptr->value);

        ptr = (List_Type*)ptr->next;

    }

}

void Print_ToStart(List_Type * ptr){

    while(ptr != (void*)0){

            printf("%d, ", ptr->value);

            ptr = (List_Type*)ptr->previous;

        }

}

int main(void) {

    List_Type *pList = CreateList_Add(10);

    List_Type *ptr = pList;

    Print_ToEnd(ptr);

    printf("\n");



    ptr = FindIndex_Front(pList, 4);

    Print_ToStart(ptr);

    printf("\n");



    ptr = FindIndex_Front(pList, 7);

    Add_Node(ptr,3);

    Print_ToEnd(ptr);

    printf("\n");



    return EXIT_SUCCESS;

}
/************************************************************/
【方法三:自己搭建一个内存管理机制进行“动态”分配】
最后一种也是我比较喜欢的一种方法,即,使用内存管理的思想对链表进行插入,删除操作。这样的最大好处就是,所有使用的内存都是程序中自己动手建立的,方便自己估计程序大小.
/*

 ============================================================================

 Name        : Pieta_C_03.c

 Author      : apollius

 Version     :

 Copyright   : Your copyright notice

 Description : Hello World in C, Ansi-style

 ============================================================================

 */



#include <stdio.h>

#include <stdlib.h>

#define  MAX_PARTIONS  100u



typedef struct{

    void * previous;

    void * next;

    int value;

}List_Type;





List_Type        ListPartion[MAX_PARTIONS];

List_Type       *pFreeList;

unsigned int     FreeNum;



void  MemClr(unsigned char * pdest, int size){

    while(size>0){

        *pdest++ = (unsigned char)0;

        size--;

    }

}

List_Type *  ListNode_Malloc(){

    List_Type* ptr;

    if(pFreeList != (List_Type *)0){

        ptr = pFreeList;

        //MemClr((unsigned char*)ptr,sizeof(ptr));   //You Can NOT do clear here, or will lost Free list information

        FreeNum--;

        pFreeList=(List_Type*)pFreeList->next; //To the next node in ListPartion[MAX_PARTIONS]



        ptr->next = (void*)0;

        pFreeList->previous = (void*)0;

    }

    else

        ptr = (List_Type *)0;

    return ptr;

}

void   ListNode_Free(List_Type * node){

    if(node != (List_Type*)0){

        FreeNum++;

        node->next = pFreeList;

        node->previous = (void*)0;



        pFreeList->previous = node;

        pFreeList = (List_Type*)pFreeList->previous;

    }

}

void  ListInit(){

    List_Type *ptr1, *ptr2;

    int i;

    MemClr((unsigned char*)&ListPartion[0], sizeof(ListPartion));

    ptr1 = &ListPartion[0];

    ptr2 = &ListPartion[1];

    for (i=0;i<MAX_PARTIONS-1;i++){

        ptr1->next = ptr2;

        ptr2->previous = ptr1;

        ptr1++;

        ptr2++;

    }



    pFreeList = &ListPartion[0];

    FreeNum = MAX_PARTIONS;

   // pListPar->pList     =  &ListPartion[0];

   // pListPar->pFreeNode =   pListPar->pList;

    printf("ListInit Success!\n");

}





void  Add_Node(List_Type * preNode, int newValue){

    List_Type * newNode  ;

    List_Type * nextNode ;

    if(preNode == (void*)0)

        return ;



    newNode  = ListNode_Malloc();

    nextNode = (List_Type*)preNode ->next;



    MemClr((unsigned char*)newNode, sizeof(List_Type)); //Explicit clear memory

    newNode->value = newValue;



    preNode->next = newNode;

    newNode->previous = preNode;

    newNode->next = nextNode;

    if(nextNode != (void*)0)        //if Not the end of the list

        nextNode->previous = newNode;

}

void Delete_Node(List_Type *pNode){

    List_Type * preNode;

    List_Type * nextNode;

    if(pNode == (List_Type*)0)

        return;



    preNode = (List_Type*)pNode->previous;

    nextNode = (List_Type*)pNode -> next;



    if(preNode != (List_Type*)0){

        preNode->next = nextNode;

    }

    if(nextNode != (List_Type*)0){

        nextNode->previous = preNode;

    }

    ListNode_Free(pNode);

}



List_Type * CreateList_Add(int nodeNum){

    List_Type * entry;

    List_Type * ptr1;



    entry =  ListNode_Malloc();

    ptr1  = entry;

    MemClr((unsigned char*)entry,sizeof(List_Type));



    while(nodeNum>1){

        Add_Node(ptr1, 1);

        if(ptr1 == (List_Type*)0)  //The List Partion is full

        {

            entry = (List_Type*)0;  //Create fail, will return a NULL pointer

            break;

        }

        ptr1 = (List_Type*)ptr1->next;

        nodeNum--;

    }

    return entry;

}

List_Type * FindIndex_Front(List_Type *entry, int index_f){

    List_Type * ptr = entry;

    while(index_f>0){

        ptr = (List_Type* )ptr->next;

        if(ptr == (void*)0)

            return (void*)0;   //index_f overflow

        index_f--;

    }

    return ptr;

}

void Print_ToEnd(List_Type * ptr){

    while(ptr != (void*)0){

        printf("%d, ",ptr->value);

        ptr = (List_Type*)ptr->next;

    }

}

void Print_ToStart(List_Type * ptr){

    while(ptr != (void*)0){

            printf("%d, ", ptr->value);

            ptr = (List_Type*)ptr->previous;

        }

}

int main(void) {

    List_Type *pList;

    List_Type *ptr;



    //initialte List Partion

    ListInit();

    pList = CreateList_Add(10);

    ptr = pList;

    Print_ToEnd(ptr);

    printf("\n");



    ptr = FindIndex_Front(pList, 4);

    Print_ToStart(ptr);

    printf("\n");



    ptr = FindIndex_Front(pList, 7);

    Add_Node(ptr,3);

    Print_ToEnd(pList);

    printf("\n");

    printf("FreeNumber: %d\n",FreeNum);



    ptr = FindIndex_Front(pList, 0);

    pList++;  //If you want delete the first note, you must move the pList to the next one.

    Delete_Node(ptr);

    Print_ToEnd(pList);

    printf("\n");

    printf("FreeNumber: %d\n",FreeNum);



    ptr = FindIndex_Front(pList,7);

    Delete_Node(ptr);

    Print_ToEnd(pList);

    printf("\n");

    printf("FreeNumber: %d\n",FreeNum);



    ptr = FindIndex_Front(pList,8);

    Add_Node(ptr,89);

    Print_ToEnd(pList);

    printf("\n");

    printf("FreeNumber: %d\n",FreeNum);

    return EXIT_SUCCESS;

}
/************************************************************/

最后这种方法虽然很原始,但可以将内存管理部分单独剥离开,可以看做是一个通用的数据结构内存处理机制,特别适合在嵌入式编程中用这种方法编写自己的一个链表、FIFO队列等等。C语言中的指针处理必须得小心翼翼,但是一旦这一关能过,之后就可以将很多上层软件中所运用的编程思想用在C语言中,使自己的程序写得更灵活。

你可能感兴趣的:(内存管理)