【问题标题】:After using realloc the next pointer in array is lost使用 realloc 后,数组中的下一个指针丢失
【发布时间】:2016-03-12 17:30:36
【问题描述】:
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]);
    }
}

代码旨在在**p 中动态分配的文本中查找并用第二个单词 (y) 替换单词 (x)。它们以字符串 (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);

【问题讨论】:

  • 呃.. 我会使用逐字符状态机而不是那些讨厌的库调用。这样就可以在没有噩梦的情况下对其进行调试。
  • 在分配和复制中似乎没有考虑空字符。
  • 我的意思是,'if((strchr(separatori,*(q - 1)) || q == p[i]) && (*(q + strlen(x)) == ' \0' || strchr(separatori, *(q + strlen(x)))))' 需要花费太多精力来解开和验证:(
  • 有很多 strlen(x) 调用:(
  • @MartinJames 但是qpx 是不言自明的!它可能会在不到一个小时内被破译。

标签: c string realloc


【解决方案1】:

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

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

你在解析文件时在主程序中犯了这个错误。

当你reallocate 时,你又成功了。

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

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

编辑:您已将代码固定到位,这可能会使该问题的其他读者感到困惑,但您在第二次调用 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 的更简单版本,修复了 cmets 中的大多数备注。我没有使用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]);
    }
}

【讨论】:

  • 我删除了 x 和 y 的 strlen 调用。还在 malloc 和 realloc 中为 '\0' 分配了额外的字节。效果依旧。如果替换发生在行首,则不会发生此错误。如图所示
  • @BarbuTudor:count 函数中可能存在错误。我发布了一个更简单的operation2() 版本。检查这是否能解决问题。
  • 看来这解决了问题。难道是我没有将{ } 用于if 分支的事实吗?或者您认为是什么导致了错误?
  • @BarbuTudor:正如我在回答中所写,我怀疑count 函数中存在错误。大括号在这里似乎没有错。
【解决方案2】:

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

因此,如果希望代码与激进的编译器兼容,则必须避免将任何指针指向将要重新分配的对象,除非可以保证这样的指针甚至永远不会被 在成功重新分配后进行检查

【讨论】:

  • 你写的一切都是真的,但在这里不相关:OP 不会在重新分配的块中保留指针。他为每次迭代从p[i] 重新计算q
  • @chqrlie:我明白了我的困惑;我认为后来使用了一些指向 p[i] 字符串的指针; q 不是,但我不太清楚 x 和 y 发生了什么。
  • xy 是要搜索的单词和要替换的单词。它们是由strtok 修改的sir 参数的片段。这很麻烦,就像这个函数的其余部分一样。
猜你喜欢
  • 2021-12-07
  • 1970-01-01
  • 2012-08-20
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
  • 2019-04-04
相关资源
最近更新 更多