【问题标题】:A generic function to copy char* in C在 C 中复制 char* 的通用函数
【发布时间】: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;
}

freeFunctioncopyFunction 的定义如下:

typedef void (*freeFunction)(void *);
typedef void (*copyFunction)(void **, void *);

对于原始类型(intdouble,...)我不需要特定的复制功能,但我需要 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() 复制节点的信息内容时使用它(对于原始类型copyFnNULL)。

问题出在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-&gt;info 复制到element(当我使用push() 时它会复制)并且它不会释放p=info

我不知道为什么。对不起,很长的帖子。任何帮助表示赞赏。

编辑: 我把main函数里的dchar 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
  • &amp;element 是局部变量地址。
  • 不相关,但size_t是无符号的,所以不能是velInfo &lt;= 0
  • 您没有发布足够的代码来回答您的问题。 push 特别重要。请发布 MCVE。不清楚为什么你会在 pop 函数中使用 copyfunc 而不是只返回弹出的项目(它不需要复制,因为它不再在堆栈中)

标签: c generics stack void-pointers


【解决方案1】:

弹出代码应该是:

char *d;

while (pop(&s, &d))
{
    printf("d = %s ", d);
    free(d);
}

pop 函数将弹出的值写入参数指向的内存。因此,您必须提供一个指向您写入弹出值的区域的指针。传递 d 不好,传递指向 1 字节 char 数组的指针也不好。

注意:这可能不是一个完整的答案。我认为您的 pop 函数也是错误的,但您没有发布足够的代码。

【讨论】:

    猜你喜欢
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 2013-05-14
    • 1970-01-01
    • 2010-10-08
    相关资源
    最近更新 更多