2016-02-27 74 views
-3

我正在寫小內存分配系統。有:C內存池存儲

typedef struct _POOL 
{ 
    int size;  /*size of memory pool*/ 
    void* memory; /*pointer to pool location in memory*/ 
} Pool; 

Pool* allocatePool(int n) { 
    Pool *myPool = malloc(sizeof(Pool) + n); 

    if (myPool){ 
     myPool->size = n; 
     myPool->memory = myPool+1; 
    } 

    return myPool; 
} 

我想寫的功能,將存儲任意對象的大小n位置偏移池內。

void store(Pool* pool, int offset, int size, void *object) { 
    char *ptrHelper;     
    ptrHelper = &(pool->memory);  /*copy pool memory address*/ 
    ptrHelper += offset;    /*increment to match offset*/ 
    memcpy(ptrHelper, &object, size); /*copy object in to the pool*/ 
} 

問題:

ptrHelper = &(pool->內存)是有越來越池內存地址的另一種正確的方式?

如果我想存儲大於void *對象大小的值(我的情況是4字節),該怎麼辦?

如何在不改變函數參數結構的情況下正確處理字符串? 謝謝。

+0

爲什麼'&(pool-> memory)'而不是'pool-> memory'?看起來'pool-> memory'已經是一個指向池的指針了。爲什麼採取它的地址?如果'offset'是0,你不會覆蓋'pool-> memory'嗎? –

+0

池 - >內存是我的池的基地址。增加它的地址更改我的池的地址並將偏移量設置爲0對我的目標地址沒有任何影響。我可能錯了。這些是我第一步到C :)。 – Arth

+0

這是第二次轉貼!只是供參考:我標記它爲mod注意。堆棧溢出不是教程網站。如果你缺乏基礎知識,請閱讀一本C書,並從一些容易開始的練習開始。 – Olaf

回答

1

我不知道這是最好的答案,但是這可能幫助...:

  1. 您的結構浪費存儲空間 - 你不需要指針,爲您的內存塊只是在結構的末尾繼續。要輕鬆訪問內存塊,您可以使用flexible (un-specified) length array at the end of your structure, known as a FAM

  2. 我不認爲你需要使用標籤和typedef別名命名結構 - t的多餘。無論如何,你不會使用結構的標籤名,所以不要使用它。

  3. 您的store函數濫用指針。例如:object已經是一個指針了,直接使用它(不要拿指針的地址)。 ptrHelper也是如此 - 它已經是一個指針了。

    採用指針的地址(使用&運營商)將堆棧的存儲器地址(變量的在函數的位置)返回指針的位置,不是數據的位置

  4. 正如Olef指出的那樣 - 混合了有符號值和無符號值,這很危險。我已將size類型更改爲size_t,這是您從size_of得到的結果,也是malloc預期的結果。

    如果對你來說太大了,你可以使用unsigned int或unsigned short,具體取決於你將用作上限......但是,這會使錯誤處理更難以管理。

下面是相同的結構具有無符號size財產,並使用FAM(柔性陣列構件):

typedef struct 
{ 
    size_t size;  /*size of memory pool*/ 
    char memory[]; /* the actual memory buffer, available as a byte array */ 
} Pool; 

// sizeof(Pool) == sizeof(size_t) // the char[] array isn't part of the size. 

這種輕微的變化也使得分配更容易:

Pool* allocatePool(size_t n) { 
    Pool *myPool = malloc(sizeof(Pool) + n); 

    if (myPool){ 
     myPool->size = n; 
    } 

    return myPool; 
} 

有得想一想 - 這種結構和分配功能要求你的對象的用戶使用特殊的語義來訪問內存。

在另一方面,返回pool->memory陣列,而不是pool對象將讓你的用戶是不可知的,你可以實現一個malloc替代適合徑直往前

當你得到一個指針回來,你只需要計算偏移量即可找到對象在內存中的原始位置。

看看Redis使用的驚人的SDS String Library - 他們有很棒的想法。

可以使用實現類似的東西:

#define _get_pool_addr(p) ((p) - sizeof(Pool)) 

void* allocatePool(size_t n) { 
    Pool *myPool = malloc(sizeof(Pool) + n); 

    if (myPool){ 
     myPool->size = n; 
    } 

    return myPool->memory; 
} 

void freePool(void * pooled_memory) { 
    Pool *myPool = _get_pool_addr(pooled_memory); 
    // do what you want. If you're freeing the memory: 
    free(myPool); 
} 

使用這些變化,你store功能是非常簡單的:

void store(void * mymem, int offset, int size, void *object) { 
    memcpy(mymem + offset, object, size); /*copy object in to the pool*/ 
} 

此,我想,效果會更好,然後用store功能看起來像這樣(你的版本,只是固定的):

void store(Pool* pool, int offset, int size, void *object) { 
    char *ptrHelper;     
    ptrHelper = pool->memory;  /*copy pool memory address*/ 
    ptrHelper += offset;    /*increment to match offset*/ 
    memcpy(ptrHelper, object, size); /*copy object in to the pool*/ 
} 

祝你好運!

+0

很費力,但還是有些瑕疵。對於初學者來說:混合有符號和無符號整數應該小心處理。 'sizeof'運算符產生一個'size_t',它不應該與'int'混合。一般說明:做OP的工作是一個壞主意。最好提供一些提示並解釋她的問題,以便他可以自己編寫代碼。否則,他不會真正學習。 – Olaf

+0

「使用未命名結構」 - 沒有「未命名結構」。 – Olaf

+0

@Olaf - 謝謝。我只是在修復與問題相關的部分(而不是'int' v。s'size_t'),所以謝謝你的收穫。至於OP的工作......我認爲他/她已經完成了大部分工作,只是在指針使用方面存在問題(和我忽略的類型不匹配)......但下次我會記住它。 – Myst

0

ptrHelper = &(pool->memory)不給出池內存地址。 用途:ptrHelper = pool->memory