使用 realloc 后,数组中的下一个指针丢失
After using realloc the next pointer in array is lost
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) == '[=10=]' || 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
中动态分配的文本中查找单词 (x
) 并将其替换为第二个单词 (y
)。它们以字符串 (sir
) 的形式出现并且是分开的。
move
存储得到的单词之间的差异。 n
表示正文行数
单词 x
不能在另一个单词中,因此需要检查分隔符。
如果满足条件,则根据 move
是正数还是负数重新分配字符串。如果它是正数,则字符串会更长,并且可以为其中的单词 x
的所有幽灵重新分配。 counter
是一个计算字符串中出现次数的函数。
当 move
为负时,必须减少字符串,以便在操作发生后重新分配。
用 memmove
和 memcpy
完成替换。
k
是x
出现后的位置。
在测试期间,需要将 "o"
替换为 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
。
这是参考
Reference
这就是我得到的
Result
替换字符串中间的"o"
时出错,指向下一行的指针丢失,指向上一行的结尾部分。 1 表示
之后的行的计数器值
Does realloc
use memory that was already allocated and by doing so the next pointer is lost?
编辑: 这里是数组的分配:
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] = '[=11=]';
}
free(aux);
就 C 标准而言,realloc 在其成功的所有情况下的行为等同于将内存块复制到某个任意位置,对其调用 free,调用 malloc 来创建一个新块请求的大小,并 returning 指向新块的指针(在 malloc 不成功的情况下,realloc 被定义为 return null 而不干扰原始块)。虽然许多编译器允许将指向旧块的指针与新块进行比较,并且将指向同一对象的两个指针之间的差异视为不可变且永远可观察,即使在相关对象的生命周期之后也是如此,C 标准无法查询特定编译器是否支持此类有用的扩展。
因此,如果希望代码与激进的编译器兼容,就必须避免在将要重新分配的对象中使用任何指针,除非可以保证此类指针永远不会被重新分配在成功重新分配后检查。
您的代码非常混乱,因为副作用太多,对 strlen
...
的冗余调用
主要问题是您没有为字符串分配足够的 space:您忘记了 '[=14=]'
终止符所需的额外字节。
你在解析文件时在主程序中犯了这个错误。
当你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
因为你没有 post 代码,我不能断言它是正确的。
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] == '[=12=]' || 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]);
}
}
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) == '[=10=]' || 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
中动态分配的文本中查找单词 (x
) 并将其替换为第二个单词 (y
)。它们以字符串 (sir
) 的形式出现并且是分开的。
move
存储得到的单词之间的差异。 n
表示正文行数
单词 x
不能在另一个单词中,因此需要检查分隔符。
如果满足条件,则根据 move
是正数还是负数重新分配字符串。如果它是正数,则字符串会更长,并且可以为其中的单词 x
的所有幽灵重新分配。 counter
是一个计算字符串中出现次数的函数。
当 move
为负时,必须减少字符串,以便在操作发生后重新分配。
用 memmove
和 memcpy
完成替换。
k
是x
出现后的位置。
在测试期间,需要将 "o"
替换为 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
。
这是参考 Reference
这就是我得到的 Result
替换字符串中间的"o"
时出错,指向下一行的指针丢失,指向上一行的结尾部分。 1 表示
Does
realloc
use memory that was already allocated and by doing so the next pointer is lost?
编辑: 这里是数组的分配:
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] = '[=11=]';
}
free(aux);
就 C 标准而言,realloc 在其成功的所有情况下的行为等同于将内存块复制到某个任意位置,对其调用 free,调用 malloc 来创建一个新块请求的大小,并 returning 指向新块的指针(在 malloc 不成功的情况下,realloc 被定义为 return null 而不干扰原始块)。虽然许多编译器允许将指向旧块的指针与新块进行比较,并且将指向同一对象的两个指针之间的差异视为不可变且永远可观察,即使在相关对象的生命周期之后也是如此,C 标准无法查询特定编译器是否支持此类有用的扩展。
因此,如果希望代码与激进的编译器兼容,就必须避免在将要重新分配的对象中使用任何指针,除非可以保证此类指针永远不会被重新分配在成功重新分配后检查。
您的代码非常混乱,因为副作用太多,对 strlen
...
主要问题是您没有为字符串分配足够的 space:您忘记了 '[=14=]'
终止符所需的额外字节。
你在解析文件时在主程序中犯了这个错误。
当你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
因为你没有 post 代码,我不能断言它是正确的。
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] == '[=12=]' || 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]);
}
}