[英]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)
+------------+
在這種情況下,您需要設置freefnc
來free
字符串本身(但仍然不是實際的堆棧元素)。 當然,您目前沒有這種情況,因為您只是將int
存儲在堆棧中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.