【发布时间】:2016-09-07 12:41:54
【问题描述】:
我正在尝试实现一个通用堆栈(单链表),我已经解决了所有问题,除非我必须处理字符数组。
节点:
typedef struct cvor {
void *info;
struct cvor *next;
} Cvor;
堆栈类型定义:
typedef struct {
Cvor *tos;
size_t velicinaInfo; //
freeFunction freeFn;
copyFunction copyFn;
} Stek;
初始化新堆栈的函数:
void noviStek(Stek *stek, size_t velInfo, freeFunction freeFn, copyFunction copyFn)
{
if (velInfo <= 0)
{
// element size can't be <=0
printf("Velicina elementa ne moze biti 0.\n");
return;
}
stek->tos = NULL;
stek->velicinaInfo = velInfo;
stek->freeFn = freeFn;
stek->copyFn = copyFn;
}
freeFunction 和 copyFunction 的定义如下:
typedef void (*freeFunction)(void *);
typedef void (*copyFunction)(void **, void *);
对于原始类型(int,double,...)我不需要特定的复制功能,但我需要 char*。这是我目前所拥有的:
void copyString(void **dest, void *src)
{
char *psrc = (char*) src;
size_t size = strlen(psrc) + 1;
*dest = calloc(size, 1);
memcpy(*dest, src, size);
}
主要看起来像这样:
char a[] = "helloooooooooo";
char b[] = "helloworld";
char c[] = "stringst";
Stek s;
noviStek(&s, sizeof(char*), NULL, copyString);
push(&s, a);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
push(&s, b);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
push(&s, c);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
//char d[100] = "";
char d[]="";
while (pop(&s, d))
{
printf("d = %s ", d);
}
isprazniStek(&s);
stekTop() 打印堆栈顶部,isprazniStek() 释放堆栈。
输出是:
tops: helloooooooooo
tops: helloworld
tops: stringstring
d =
d =
d =
因此,如果定义了copyFn,则在调用push() 和pop() 复制节点的信息内容时使用它(对于原始类型copyFn 是NULL)。
问题出在pop 函数上,函数如下:
int pop(Stek *stek, void *element)
{
if (isEmptyStek(stek))
return 0;
Cvor *p = stek->tos;
if (stek->copyFn)
{
stek->copyFn(&element, p->info);
}
else
{
memcpy(element, p->info, stek->velicinaInfo); // element = p->info;
}
stek->tos = p->next;
if (stek->freeFn)
{
stek->freeFn(p->info);
}
free(p->info);
free(p);
return 1;
}
它不会将p->info 复制到element(当我使用push() 时它会复制)并且它不会释放p=info。
我不知道为什么。对不起,很长的帖子。任何帮助表示赞赏。
编辑:
我把main函数里的d从char d[]=""改成了char *d,现在输出是:
tops: helloooooooooo
tops: helloworld
tops: stringstring
d = (null)
d = (null)
d = (null)
EDIT2:
因为我需要更改d 我需要发送它的地址,这里是正确的代码:
char d[]="";
while (pop(&s, &d))
{
printf("d = %s ", d);
}
以及pop()中的相应修复:
int pop(Stek *stek, void *element)
{
if (isEmptyStek(stek))
return 0;
Cvor *p = stek->tos;
if (stek->copyFn)
{
stek->copyFn(element, p->info); // <= !
}
...
EDIT3:
变量d 必须单独释放以避免韭菜(感谢Valgrind):
char d[]="";
while (pop(&s, &d))
{
printf("d = %s ", d);
// do something else with it
// ...
free(d);
}
【问题讨论】:
-
您的
pop循环代码产生了正确的输出。为什么你说pop不起作用?另外,char d[]="";不应该是char* d;吗?您不能移动或调整数组大小! -
应该改变变量
d的值。即弹出栈顶到d。 -
&element是局部变量地址。 -
不相关,但
size_t是无符号的,所以不能是velInfo <= 0。 -
您没有发布足够的代码来回答您的问题。
push特别重要。请发布 MCVE。不清楚为什么你会在 pop 函数中使用 copyfunc 而不是只返回弹出的项目(它不需要复制,因为它不再在堆栈中)
标签: c generics stack void-pointers