• 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语言中,使自己的程序写得更灵活。

  • 相关阅读:
    20200721训练记录
    20200717训练记录
    打家劫舍III(力扣第337题)
    HBase API的删除数据操作的分析
    相交链表(第160题)
    删除排序链表中的重复元素(第83题)
    合并两个有序链表(力扣第21题)
    删除链表的倒数第N个节点(第19题)
    HBase的架构原理
    回文链表、链表求和(234、445)
  • 原文地址:https://www.cnblogs.com/apollius/p/3074045.html
Copyright © 2020-2023  润新知