簡體   English   中英

用C語言實現這種通用堆棧的“免費”功能有什么問題?

[英]What Is Wrong in the “free” Function for this Generic Stack Implementation in C?

我具有以下通用堆棧的實現,即該堆棧可以存儲用戶指定的數據。

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

typedef struct{
    void *elems;
    int elemSize;
    int allocLength;
    int logLength;
    void (*freefnc) ( void* );
} Stack;

void stackNew( Stack* s, int elemSize, void (*freefnc) (void*) ){
    s->allocLength = 4;
    s->logLength = 0;
    s->elemSize = elemSize;
    s->elems = malloc( s->allocLength * elemSize );
    s->freefnc = freefnc;
}

void stackDispose( Stack* s ){
    if( s->freefnc ){
        int i;
        for( i = 0; i < s->logLength; i++ ){
            s->freefnc( ( char* ) s->elems + i * s->elemSize   );
        }
    }
    free( s->elems );
}

void stackGrow( Stack* s){
    s->allocLength *= 2;
    s->elems = realloc( s->elems, s->allocLength * s->elemSize );
    assert( s->elems != NULL );
}

void stackPush( Stack* s, void* elemAddr ){
    if( s->allocLength == s->logLength ){
        stackGrow( s );
    }
    void *target = (char*) s->elems + s->logLength * s->elemSize;
    memcpy( target, elemAddr, s->elemSize );
    s->logLength++;
}

void* stackPop( Stack* s ){
    void* source = (char*) s->elems + ( s->logLength - 1 ) * s->elemSize;
    void* elemAddr = malloc( s->elemSize );
    assert( elemAddr != NULL );
    memcpy( elemAddr, source, s->elemSize );
    s->logLength--;
    return elemAddr;
}

void freeInt( void* p ){
    char* q = p;
    free( q );
}

void stackPrint( Stack* s ){
    printf( "elemSize: %d\n", s->elemSize );
    printf( "allocLength: %d\n", s->allocLength );
    printf( "logLength: %d\n", s->logLength );

    int i;
    for( i=0; i < s->logLength; i++ ){
        printf("%d\n", *( (char*) s->elems + i * s->elemSize ) );
    }
}

int main(){
    Stack st;
    stackNew( &st, 4, &freeInt );
    int elem = 5;
    int elem2 = 9;
    stackPush( &st, &elem );
    stackPush( &st, &elem2);
    stackPrint( &st );
    stackDispose( &st );
}

但是,在運行代碼時,我得到以下輸出。

elemSize: 4
allocLength: 4
logLength: 2
5
9
*** Error in `./a.out': free(): invalid pointer: 0x00000000014b9014 ***
Aborted

在代碼中的“ freefnc”中似乎有問題,但是我不確定。 誰能解釋代碼中的錯誤以及如何解決?

PS該代碼從C中的另一個SO 泛型堆棧采用 我試圖了解代碼是如何工作的。 如果有人可以給出帶有測試用例的代碼的工作版本,將不勝感激。

在此先多謝!

讓我們明確一下堆棧是如何存儲在內存中的:您有一個Stack對象(其內存實際上不是由stack函數管理,而是由“擁有”堆棧的任何對象管理),以及一個包含所有元素的大內存塊(以及一些空白空間)。

以ASCII藝術形式:

+-----------------------+
| elems | ............. |    <- Stack object
+---|-------------------+
    |
    V
    +---------------------------------+
    | elem1 | elem2 | unused | unused |    <- Data array
    +---------------------------------+

Stack對象中的elems包含一個指向數據數組開頭的指針。

要銷毀此堆棧,您所需要做的就是銷毀數據數組(已進行malloc分配,因此請使用free )和Stack對象(這是局部變量,因此在包含它的函數返回時銷毀)。

無需釋放所有單個元素。 它們將作為數據數組的一部分被銷毀。 free調用各個元素是錯誤的 ; 如果嘗試free第一個元素,最終將釋放整個數組,如果嘗試free其他元素,則最終導致未定義的行為。


您可能想知道為什么freefnc有用。 如果堆棧元素本身是指針(或包含指針的結構),則freefnc很有用。 說,如果您要存儲使用malloc分配的字符串:

+-----------------------+
| elems | ............. |    <- Stack object
+---|-------------------+
    |
    V
    +---------------------------------+
    | elem1 | elem2 | unused | unused |    <- Data array
    +---|-------|---------------------+
        |       |
        |       V
        |       +------------+
        |       |w|o|r|l|d|\0|    <- second string
        |       +------------+       (allocated with malloc)
        V
        +------------+
        |H|e|l|l|o|\0|    <- first string (allocated with malloc)
        +------------+

在這種情況下,您需要設置freefncfree字符串本身(但仍然不是實際的堆棧元素)。 當然,您目前沒有這種情況,因為您只是將int存儲在堆棧中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM