除了 malloc 问题(已参见 cmets),您还有一个基本问题:您分配了一个新结构,然后将其替换为从递归调用返回的结构。所以你丢失了之前创建的那个(实际上是内存泄漏!)。
现在最简单的变体是将您的符号转换为链表节点;那么你可以这样做:
Symbol* lastLeafFound; // probaly a function parameter!
if(!(root->left || root->right))
{
// leaf found:
Symbol* a = (Symbol*)malloc(sizeof(Symbol));
a->chr = root->chr;
a->counter = /* ... */;
a->next = NULL;
lastLeafFound->next = a;
// you might return a now as last leaf found, using it in the next recursive call
}
当然,上面的代码是不完整的,但应该给你的想法......
如果你不能修改你的结构,那么你需要创建一个数组并将它传递给每个新的递归调用(最好不要使用全局变量):
void doGetSL
(
HNode* root,
Symbol** symbols, // your array to be used
unsigned int* count, // number of symbols contained so far
unsigned int* capacity // maximum possible symbols
)
将所有数据作为指针传递允许函数根据需要修改它们,并且它们仍然可以从外部获得......
Symbol* getSL(HNode* root)
{
if(!root)
return NULL;
unsigned int count = 0;
unsigned int capacity = 128;
// allocate a whole array:
Symbol* array = malloc(capacity*sizeof(Symbol));
if(array) // malloc could fail...
{
doGetSL(root, &array, &count, &capacity);
// as you cannot return the number of leaves together with
// the array itself, you will need a sentinel:
array[count].chr = 0;
// obvious enough, I'd say, alternatively you could
// set counter to 0 or -1 (or set both chr and counter)
}
return array;
}
doGetSL 现在将使用上面设置的“基础设施”:
{
if(!(root->left || root->right))
{
if(*count == *capacity)
{
// no memory left -> we need a larger array!
// store in separate variables:
unsigned int c = *capacity * 2;
Symbol* s = realloc(symbols, c * sizeof(Symbol));
// now we can check, if reallocation was successful
// (on failure, s will be NULL!!!):
if(s)
{
// OK, we can use them...
*symbols = s; // <- need a pointer for (pointer to pointer)!
*capacity = c;
}
else
{
// re-allocation failed!
// -> need appropriate error handling!
}
}
(*symbols)[count].chr = root->chr;
(*symbols)[count].counter = /*...*/;
++*count;
}
else
{
if(root->left)
{
doGetSL(root->left, symbols, count, capacity);
}
if(root->right)
{
doGetSL(root->right, symbols, count, capacity);
}
}
}
还有一件事被忽略了:设置计数器。这很简单:在doGetSL 中添加另一个参数来指示当前深度,您可以在输入 doGetSL 时立即增加该参数,然后您可以在需要时分配此值。
如果你引入一个新的结构,你可以进一步改进上述变体(尤其是可读性):
struct SLData
{
Symbol* symbols, // your array to be used
unsigned int count, // number of symbols contained so far
unsigned int capacity // maximum possible symbols
};
并传递这个而不是三个指针:
doGetSL(HNode*, struct SLData*, unsigned int depth);
struct SLData data =
{
.count = 0;
.capacity = 128;
.array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
doGetSL(root, &data, 0); // again passed as pointer!