使用双指针自定义内存分配

时间:2018-10-05 05:07:23

标签: c dynamic-memory-allocation

这是我的代码。我试图通过在内存块的第一部分中添加一个指向结构体指针的指针,来重构它仅包含空闲块列表。一切似乎都正常,直到我在下一个方法中运行代码,然后指针突然没有指向同一位置。我究竟做错了什么 ?我重构的主要方法是init和bestFit

我想做的就是将指针指向空闲列表,并将其放在内存init中分配的数组的开头,然后使用双指针访问

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* MALLOC implementation
    @zadanie: 1
    @autor: Lukas Anda
*/

#define UINT unsigned int
#define MIN_PAMET sizeof(char) // min pamet ktora sa da alokovat

/*+ Reprezentuje kazdy jeden pametovy blok
    - prazny ci zaplneny
    - velkost bloku
    - odkazi na dalsi a predchadzajuci blok
    - velksot 16 bytov
*/
struct MemBlock { 
    char m_isfree;
    unsigned int m_size;
    //UINT m_id;

    struct MemBlock* m_next;
    struct MemBlock* m_prev;
};

/*+ Hlavna globalna premenna, ktora reprezentuje celu nasu pamet
    - Kebyze mozem dalsiu globalnu do ktorej ulozim gEnd ako koniec pamete 
        hlavicka by zaberala o m_next menej pamete a algoritmus by bol o trochu rychlejsi
        inak sa musi pouzit m_next ako odkaz.
    - Dalsia globlna gFreeList by sa mohla pouzit na udrziavanie zoznamu len volnych blokov atd..
*/
static void* gMemory;

void printHeader(){
    int i =0;
    for(i; i<50;i++){
        printf("%d ", *((char*)gMemory+i));
    }
    putchar('\n');
    putchar('\n');
}
//struct MemBlock* M;
//void *gStart;
//void *gEnd;

/*+ Inicializuj pamet
    - Spravy vsetke potrebne operacie
*/
void memory_init(void *ptr, unsigned int size) {
    struct MemBlock * firstblock;
    int velkost;
    gMemory = ptr;

    memset(gMemory, 0, size);
    printHeader();

    velkost = size - sizeof(struct MemBlock); 
    if(velkost <= 0 || ptr == NULL) {
        printf("Chyba");
    }

    // Pripravy prvy klok pamete
    firstblock = (struct MemBlock*) gMemory +sizeof(struct MemBlock**);
    firstblock->m_isfree = 1;
    firstblock->m_prev = NULL;
    firstblock->m_next = NULL;
    firstblock->m_size = velkost;
    gMemory = &firstblock;

    struct MemBlock** bloock = (struct MemBlock**) gMemory;
    printf("%d\n", (*bloock)->m_size);
    printf("%d\n",firstblock->m_size);

    printHeader();
    //firstblock->m_id = 1;

    //gStart = ptr;
    //gEnd = (char*)gMemory + size;
    //printf("%d <-> %d - %d\n", gStart, gEnd, (char*)gStart - (char*)gEnd);
    //M = gMemory;
}

/*+ ANTI FRAGMENTACIA
    - Dokaze spajat rozne male bloky pamete do vacsich
    - Hlada volne bloky na pravej aj na lavej strane
*/
void memory_antifragmentation(struct MemBlock** cblock) 
{
    struct MemBlock **cblock2;

    // - Skontroluj ci dalsi 
    while((*cblock)->m_next != NULL && (*cblock)->m_next->m_isfree == 1) {
        (*cblock)->m_size += sizeof(struct MemBlock) + (*cblock)->m_next->m_size;
        (*cblock)->m_next->m_prev = (*cblock);
        (*cblock)->m_next = (*cblock)->m_next->m_next;
    }

    // a ten predchadzaujici blok je volny ak ano spoj ich dokopy
    cblock2 = cblock;
    while(*cblock2 != NULL && (*cblock2)->m_prev != NULL && (*cblock2)->m_prev->m_isfree == 1) {
        (*cblock2)->m_prev->m_size += sizeof(struct MemBlock) + (*cblock2)->m_size;
        (*cblock2)->m_prev->m_next = (*cblock2)->m_next;
        if((*cblock2)->m_next != NULL) {
            (*cblock2)->m_next->m_prev = (*cblock2)->m_prev;
        }
        cblock2 = &((*cblock2)->m_prev);
    }
}

int memory_check(struct MemBlock *b)
{
    // Zaciname od zaciatku pamete
    struct MemBlock** current;
    current = (struct MemBlock**) &gMemory;

    // Prehladavaj
    while(*current != NULL)
    {
        // Dany blok musi byt volny a musi mat dostatok pamete
        if(*current == b) {
            // Wohooo :) naslo sa nieco
            return 1;
        }
        // Prejdi na dalsi block
        current = &(*current)->m_next;
    }
    return 0;
}

/*+ Uvolni pamet
    - Uvolnovanie pamete je extremne rychle, konstatne
    - Antyfragmetacia vsak trva dlhsie ale ta sa nemusi vykonat pri free, moze
    casovo spustat alebo pri nedostatku pamete
*/
void memory_free(void *ptr)
{
    struct MemBlock* cblock;

    // Error ?
    if(ptr == NULL) {
        printf("Invalid pointer!\n");
        exit(1);
    }

    // ptr posun na hlavicku HLAVICKA | DATA - pozor na ((char*)(ptr)) - TYP*(sucet) / ULOZISKOVYTYP
    cblock = (struct MemBlock*) ( (char*) ptr - sizeof(struct MemBlock));

    // Skontroluj ci tento blok je nas - TODO: Hladaj takyto blok v zozname
    if(cblock == NULL || cblock->m_isfree || !memory_check(cblock) ) {
        printf("Invalid pointer!\n");
        exit(1);
    }

    // Status pamete nastav na free
    cblock->m_isfree = 1; // mozno po antyfragmentacii toto nieje potrebne

    // --- ANTI FRAGMENTACIA
    memory_antifragmentation(&cblock);
}

/* Typ vyhladavania volnej pamete
    - Extremne rychly
    - Avsak nemusi byt velmi efektivny z hladiska vyuzivania pamete
*/
struct MemBlock* memory_firstfit(UINT size)
{
    // Zaciname od zaciatku pamete
    struct MemBlock** current;
    current = (struct MemBlock**) &gMemory;

    // Prehladavaj
    while(*current != NULL)
    {
        // Dany blok musi byt volny a musi mat dostatok pamete
        if((*current)->m_isfree && (*current)->m_size >= size) {
            // Wohooo :) naslo sa nieco
            return *current;
        }

        // Prejdi na dalsi block
        current = &(*current)->m_next;
    }

    // Nenaslo nic
    return NULL;
}

/* Typ vyhladavania volnej pamete
    - Extremne efektivnejsi ale pomalsi
*/
struct MemBlock* memory_bestfit(UINT size)
{
    // Zaciname od zaciatku pamete
    struct MemBlock** current;
    struct MemBlock* best;
    UINT bestsize;

    printHeader();

    current = (struct MemBlock**) gMemory;
    printf("%d\n", (*current)->m_size);
    best = gMemory + sizeof(struct MemBlock**);
    printf("%d\n", (best)->m_size);
    struct MemBlock** bloock = (struct MemBlock**) gMemory;
    printf("%d\n", (*bloock)->m_size);
    best = NULL;
    bestsize = 65535;

    // Prehladavaj
    while(*current != NULL)
    {
        // Dany blok musi byt volny a musi mat dostatok pamete
        printf("%d",(*current)->m_size);
        if((*current)->m_isfree && (*current)->m_size >= size) {
            // Je to lepsie ako minuly ?
            if( (*current)->m_size < bestsize) {
                best = (*current);
                bestsize = best->m_size;
            }
        }

        // Prejdi na dalsi block
        current = &(*current)->m_next;
    }
    return best;
}

/* Ktory typ vyhladavania zvolime ?
    - Tieto 2 funkcie sa mozu striedat
    - Napriklad na zaciatku po init je najlepsi First fit
    - Neskor pri nedostatku pamete je lepsi Best fit
*/
struct MemBlock* memory_find(UINT size)
{
    // First fit ?
    //return memory_firstfit(size);

    // Best fit ?
    return memory_bestfit(size);
}

/*+ Rozdel pamet ak je to mozne
    Mame urcity blok pamete napriklad o velkosti 900bytov.
    A potrebujeme naalokovat 80bytov.
    Je hlupost pre blok prirad 900bytov, postaci priradit 80+hlavicku.
    A na zvysku sa vytvori novy blok.
*/
void memory_fragme(struct MemBlock** freeblock, UINT size)
{
    // Zisti kolko pamete sa zvysi
    int zvysok = (*freeblock)->m_size - size;

    // Ked zvysok je vacsi ako hlavicku + MIN_PAMET 
    // teda bolo by mozne vytvorit dalsi blok + nejaku pamet pre najmensi typ
    if(zvysok >= (int) (sizeof(struct MemBlock)+MIN_PAMET)) {

        // Rozdel pamet - Sprav novy blok
        struct MemBlock* newblock;
        newblock = (struct MemBlock *) (  (char*)(*freeblock) + size + sizeof(struct MemBlock)  );
        /*
            int i;    // TYP*(sucet) / ULOZISKOVYTYP
            i = ((char*)newblock - (char*)(*freeblock));
            i = newblock < gEnd && newblock >= gStart;
            printf("%d\n", newblock);
            //newblock->m_id = (*freeblock)->m_id + 1;
        */
        newblock->m_isfree = 1;
        newblock->m_size = zvysok - sizeof(struct MemBlock);
        newblock->m_prev = (*freeblock);
        newblock->m_next = (*freeblock)->m_next;

        (*freeblock)->m_size = size;
        (*freeblock)->m_next = newblock;
        return;
    } 

    // Pamet sa neda rozdelit, ponechaj ju
}

/*+ Funkcia naalokuje novu pamet 
    - Vracia NULL pri neuspechu
*/
void *memory_alloc(unsigned int size) 
{
    // Skus najst nejaky volny block...
    struct MemBlock* freeblock;
    if(size == 0) return NULL;
    printf("inside alloc\n");
    printHeader();
    freeblock = memory_find(size);

    // Nenasli sme zial ziadnu volnu pamet
    if(!freeblock) return NULL;

    // Pamet uz nieje volna
    freeblock->m_isfree = 0;

    // Rozdel pamet ak je to potrebne a mozne
    memory_fragme(&freeblock, size);

    // Presun pointer z hlavicky na DATA
    //return (char*)freeblock + sizeof(struct MemBlock);
    // TYP*(sucet) / ULOZISKOVYTYP
    //return ((int)freeblock + sizeof(struct MemBlock)); 
    return (freeblock+1); // to iste
}

/*
void memory_dump()
{
    // Zaciname od zaciatku pamete
    struct MemBlock** current;
    current = (struct MemBlock**) &gMemory;
    // Prehladavaj
    while(*current != NULL && (*current)->m_next != NULL) {
        printf("- %d", (*current)->m_next - (*current) );
        printf("- %d", ((*current) + (*current)->m_size) - (*current) );
        current = &(*current)->m_next;
    }
    printf("\n");
}
*/

int main()
{    
    char region[500];
    char* pointers;
    memory_init(region, 500);
    printf("inside main\n");
    printHeader();
    pointers = (char*) memory_alloc(10);
    if (pointers) {
        memset(pointers, 0, 10);
    };
    /*pointers[1] = (char*) memory_alloc(3);
    if (pointers[1]) {
        memset(pointers[1], 0, 3);
    };
    pointers[2] = (char*) memory_alloc(6);
    if (pointers[2]) {
        memset(pointers[2], 0, 6);
    };
    if (pointers[0]) {
        memory_free(pointers[0]);
    };
    pointers[3] = (char*) memory_alloc(10);
    if (pointers[3]) {
        memset(pointers[3], 0, 10);
    };
    if (pointers[2]) {
        memory_free(pointers[2]);
    };
    pointers[4] = (char*) memory_alloc(5);
    if (pointers[4]) {
        memset(pointers[4], 0, 5);
    };
    if (pointers[1]) {
        memory_free(pointers[1]);
    };
    if (pointers[3]) {
        memory_free(pointers[3]);
    };*/

    return 0;
}

/*
#define H_ISALLOC(a)    (*a & 1) // 0x01
#define H_GETSIZE(a)    (*a & ~0x1)
#define H_SETSIZE(a,b)    *a = b | 0x1;
#define H_DEALLOC(a)    *a = *a & ~0x1;
char memory[1000];
char* data[30];
char *p;
UINT i;
//    TYP*(sucet) / ULOZISKOVYTYP
    struct MemBlock *a = 0;
    struct MemBlock *b = 0;

    printf("%d\n", sizeof(char));
    printf("%d\n", sizeof(int));
    printf("%d\n", sizeof(unsigned int));
    printf("%d\n", sizeof(long));
    printf("%d\n", sizeof(void*));
    printf("%d\n", sizeof(struct MemBlock));
    printf("%d\n", sizeof(struct MemBlock*));
    printf("---\n");
    b = a + sizeof(char)*100; printf("%d\n", b - a);
    b = a + 100; printf("%d\n", b - a); // 100
    b = (char*) a + 100; printf("%d\n", b - a); // 25
    b = ( long *) a + 100; printf("%d\n", b - a);
    b = ( float *) a + 100; printf("%d\n", b - a);
    b = (UINT*) ( (struct MemBlock*) a + 100 ); printf("%d\n", b - a); // 16*100 / 4
*/

0 个答案:

没有答案