Realloc,char **,segfault

时间:2014-04-21 13:55:12

标签: c segmentation-fault realloc

有一个功能。它是add_lexem并在指定数组的末尾添加一个元素(char *)。如果没有剩余内存,它会分配一些额外的内存(100 * sizeof(char *))。该函数会导致段错误,这就是问题所在。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void add_lexem(char **lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
    if (*lexem_n >= *lexemsc) {
        lexems = realloc(lexems, sizeof(char *) * (*lexemsc + 100));
        *lexemsc += 100;
    }

    char *for_adding = malloc(sizeof(char) * strlen(lexem));
    strcpy(for_adding, lexem);
    lexems[*lexem_n] = for_adding;
    (*lexem_n)++;
}

int main(void)
{
    char **D = malloc(sizeof(char *) * 2);
    int lexemsc = 2;
    int lexem_n = 0;

    add_lexem(D, &lexemsc, &lexem_n, "MEOW");
    printf("%s\n", D[0]);

    add_lexem(D, &lexemsc, &lexem_n, "BARK");
    printf("%s\n", D[1]);

    // in this place lexem_n becomes equal lexemsc
    add_lexem(D, &lexemsc, &lexem_n, "KWARK"); 
    printf("%s\n", D[2]);

    return 0;
}

输出必须是

MEOW
BARK
KWARK

但它是

MEOW
BARK
Segmentation fault (core dumped)

4 个答案:

答案 0 :(得分:3)

您的lexeme参数按值传递时,应该按地址传递:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

// removed unused void ccat(char *str, char c)

void add_lexem(char ***lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
    if (*lexem_n >= *lexemsc) {
        *lexems = realloc(*lexems, sizeof(char *) * (*lexemsc + 100));
        *lexemsc += 100;
    }

    char *for_adding = malloc(sizeof(char) * strlen(lexem)+1);
    strcpy(for_adding, lexem);
    (*lexems)[*lexem_n] = for_adding;
    (*lexem_n)++;
}

int main(void)
{
    char **D = malloc(sizeof(char *) * 2);
    int lexemsc = 2;
    int lexem_n = 0;

    add_lexem(&D, &lexemsc, &lexem_n, "MEOW");
    printf("%s\n", D[0]);

    add_lexem(&D, &lexemsc, &lexem_n, "BARK");
    printf("%s\n", D[1]);

    // in this place lexem_n becomes equal lexemsc
    add_lexem(&D, &lexemsc, &lexem_n, "KWARK");
    printf("%s\n", D[2]);

    return 0;
}

<强>输出

MEOW
BARK
KWARK

注意:三重间接(即3开始编程)不是轻易进入的,尽管它实际上符合您在此处尝试做的事情。仔细阅读上面的代码并确保确定,了解它是如何工作的。

编辑:为添加的字符串添加了终结符空间。 (不知道为什么我错过了它,因为这是其他所有人似乎都在第一次审查时所发现的,呃)。

注意:请参阅@wildplasser's answer此问题。老实说,这是最好的方法,因为它收紧了字符串指针数组和所述相同大小之间的关系。如果可以重新调整代码以使用该模型,那么您应该这样做,并且在这样做时选择该答案作为&#34;正确的&#34;溶液

答案 1 :(得分:2)

主要问题是您通过值将D传递给函数:赋值

lexems = realloc(...);

D没有影响。在realloc执行重新分配的情况下,D成为悬空指针,因此取消引用它将成为未定义的行为。

您需要通过指针传递D的方式与传递lexemsc&lexem_n的方式相同,以便realloc的效果在main内可见{1}}功能也是如此。

此外,您的add_lexem没有为要复制的字符串分配足够的内存:strlen不计算空终止符,因此这两行

char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);

在分配的空间之后写一个字节'\0'

答案 2 :(得分:2)

避免三星级编程的替代方案:在结构中放置所需的一切:

struct wordbag {
        size_t size;
        size_t used;
        char **bag;
        };

void add_lexem(struct wordbag *wb, const char *lexem)
{
    if (wb->used >= wb->size) {
        wb->bag = realloc(wb->bag, (wb->size+100) * sizeof *wb->bag );
        wb->size += 100;
    }

    wb->bag[wb->used++] = strdup(lexem);
}

答案 3 :(得分:0)

问题可能来自:

 char *for_adding = malloc(sizeof(char) * strlen(lexem));
  strcpy(for_adding, lexem);

尝试char *for_adding = malloc(sizeof(char) * (strlen(lexem)+1));为&#39; \0字符留出一些空间。

编辑:和@WhozCraig似乎是对的!

再见,