我有一个通用堆栈的以下实现,即堆栈可以存储用户指定的数据。
@SafeVarargs
public static <E> Iterable<E> concat(final Iterable<? extends E>... iterables) {
return concat(Arrays.asList(iterables));
}
public static <E> Iterable<E> concat(final Iterable<Iterable<? extends E>> iterables) {
return new Iterable<E>() {
final Iterator<Iterable<? extends E>> iterablesIterator = iterables.iterator();
@Override
public Iterator<E> iterator() {
return !iterablesIterator.hasNext() ? Collections.emptyIterator()
: new Iterator<E>() {
Iterator<? extends E> iterableIterator = nextIterator();
@Override
public boolean hasNext() {
return iterableIterator.hasNext();
}
@Override
public E next() {
final E next = iterableIterator.next();
findNext();
return next;
}
Iterator<? extends E> nextIterator() {
return iterablesIterator.next().iterator();
}
Iterator<E> findNext() {
while (!iterableIterator.hasNext()) {
if (!iterablesIterator.hasNext()) {
break;
}
iterableIterator = nextIterator();
}
return this;
}
}.findNext();
}
};
}
但是,我在运行代码时得到了以下输出。
#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 );
}
代码中的“freefnc”似乎有些不对,但我不确定。任何人都可以解释代码中的错误以及如何修复它吗?
P.S。该代码来自另一个SO帖子Generic Stacks in C。我试图了解代码的工作原理。如果有人能够通过测试用例提供代码的工作版本,我们将非常感激。
提前多多感谢!
答案 0 :(得分:3)
让我们清楚你的堆栈如何存储在内存中:你有一个Stack
对象(其内存实际上不是由stack
函数管理,而是由“拥有”堆栈的任何东西管理,和一个包含所有元素的大内存块(以及一些空白区域)。
以ASCII艺术形式:
+-----------------------+
| elems | ............. | <- Stack object
+---|-------------------+
|
V
+---------------------------------+
| elem1 | elem2 | unused | unused | <- Data array
+---------------------------------+
elems
对象中的 Stack
包含指向数据数组开头的指针。
要销毁此堆栈,您需要做的就是销毁数据数组(使用malloc-ed,因此使用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
存储在堆栈中。