使用realloc后,数组中的下一个指针将丢失

时间:2015-12-07 23:02:24

标签: c string realloc

void operation2(char **p, int n, char *sir) {
    int i, move, k, xlen, ylen;
    char *x, *y, *q, separatori[] = " \'\",!?";
    x = strtok(sir, " ");
    y = strtok(NULL, " ");
    xlen = strlen(x);
    ylen = strlen(y);
    move = ylen - xlen;
    for (i = 0; i < n; i++) {
        k = 0;
        while (strstr(p[i] + k, x)) {
            q = strstr(p[i] + k, x);
            if ((strchr(separatori, *(q - 1)) || q == p[i]) &&
                (*(q + xlen) == '\0' || strchr(separatori, *(q + xlen)))) {
                if (move > 0 && k == 0)
                    p[i] = realloc(p[i], (strlen(p[i]) + move * counter(p[i], x) + 1) * sizeof(char));
                q = strstr(p[i] + k, x);
                memmove(q + xlen + move, q + xlen, strlen(q + xlen) + 1);
                memcpy(q, y, ylen);
                k = strlen(p[i]) - strlen(q) + ylen;
                if (move < 0)
                    p[i] = realloc(p[i], (strlen(p[i]) + move + 1) * sizeof(char));
            } else
                k = k + xlen;
        }
        puts(p[i]);
    }
}

该代码旨在使用x中动态分配的文本中的第二个(y)查找并替换单词(**p)。它们以字符串形式(sir)分开。 move存储获得的单词之间的差异。 n表示文本中的行数。

单词x不能在另一个单词中,因此需要检查分隔符。

如果符合条件,则根据move是正还是负,重新分配字符串。如果它是正数,则字符串将更长,并且可以为其中的单词x的所有显示重新分配。 counter是一个计算字符串中的外观的函数。 当move为负数时,必须减少字符串,以便在操作发生后重新分配。

替换是使用memmovememcpy完成的。

kx

的幻影之后的位置

在测试期间,需要将"o"替换为"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

这是参考 Reference

这就是我得到的 Result

当替换字符串中间的"o"时,会发生错误,指向下一行的指针将丢失,指向上一行的结尾部分。 1表示后面一行的计数器值

  

realloc是否使用已经分配的内存,这样下一个指针就会丢失?

编辑:以下是数组的分配:

int n, i;
scanf("%d", &n);
char **p, *aux;
p = malloc(n * sizeof(char *));
aux = malloc(12000 * sizeof(char));
getchar();
for (i = 0; i < n; i++) {
    fgets(aux, 12000, stdin);
    p[i] = malloc((strlen(aux) + 1) * sizeof(char));
    strcpy(p[i], aux);
    p[i][strlen(p[i]) - 1] = '\0';
}
free(aux);

2 个答案:

答案 0 :(得分:2)

您的代码非常混乱,因为副作用太多,对strlen的多余调用...

主要问题是你没有为字符串分配足够的空间:你忘记了'\0'终结符所需的额外字节。

解析文件时,您在主例程中犯了这个错误。

当你realloc吃完这条线时,你会再次拍摄。

当你memmove行内容时,你也忘记包含空字节。

首先解决这些问题。可能还有其他的,但您需要简化代码才能看到它们。阅读所有评论,有很多提示。

编辑:您修改了代码,这可能会使其他读者对此问题感到困惑,但您在第二次调用realloc时仍然出错:

p[i] = realloc(p[i], (strlen(p[i]) + move + 1) * sizeof(char));

不正确,因为您已经缩短了行,因此strlen(p[i])是新的长度。只需写下:

p[i] = realloc(p[i], strlen(p[i]) + 1);

编辑:以下是operation2的更简单版本,修复了评论中的大多数评论。我没有使用count,因为你没有发布代码,我不能断言这是正确的。

void operation2(char **p, int n, char *sir) {
    int i, move, k, xlen, ylen;
    static const char separatori[] = " \'\",!?";
    char *x, *y, *q;

    x = strtok(sir, " ");
    y = strtok(NULL, " ");
    xlen = strlen(x);
    ylen = strlen(y);
    move = ylen - xlen;
    for (i = 0; i < n; i++) {
        k = 0;
        while ((q = strstr(p[i] + k, x)) != NULL) {
            k = q - p[i];
            if ((q == p[i] || strchr(separatori, q[-1])) &&
                (q[xlen] == '\0' || strchr(separatori, q[xlen]))) {
                if (move > 0) {
                    p[i] = realloc(p[i], strlen(p[i]) + move + 1);
                    q = p[i] + k;
                }
                memmove(q + ylen, q + xlen, strlen(q + xlen) + 1);
                memcpy(q, y, ylen);
                k += ylen;
                if (move < 0) {
                    p[i] = realloc(p[i], strlen(p[i]) + 1);
                }
            } else {
                k += xlen;
            }
        }
        puts(p[i]);
    }
}

答案 1 :(得分:0)

就C标准而言,realloc在其成功的所有情况下的行为等同于将内存块复制到某个任意位置,在其上调用free,调用malloc以创建所请求大小的新块并返回指向新块的指针(在malloc不成功的情况下,realloc被定义为返回null而不会干扰原始块)。虽然许多编译器有用地允许将旧块的指针与新块进行比较,并且将指向同一对象的两个指针之间的差异视为永久不可变和可观察的,即使在所讨论的对象的生命周期之后,C标准也是如此。没有提供查询特定编译器是否支持这种有用扩展的方法。

因此,如果一个人希望代码与积极的编译器兼容,那么必须避免在一个将要重新分配的对象中指向任何指针,除非可以保证这样的指针永远不会是成功重新分配后,检查