C中这种通用堆栈实现的“自由”功能有什么错误?

时间:2015-12-07 03:51:35

标签: c stack free

我有一个通用堆栈的以下实现,即堆栈可以存储用户指定的数据。

@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。我试图了解代码的工作原理。如果有人能够通过测试用例提供代码的工作版本,我们将非常感激。

提前多多感谢!

1 个答案:

答案 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存储在堆栈中。