【发布时间】:2016-01-08 08:23:35
【问题描述】:
我有一些代码给你,希望有人能告诉我,我哪里出错了。目前我正在将我的编程难题移植到其他编程语言中,以便动手操作。
C 中的代码抽象(更新):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *dummy = "1234567890";
const char* inlet = "_";
void dosomething(int c, char* s){
printf("%s\n", s);
if (c < 10) {
char *ns = malloc(sizeof(char)*11);
strncpy(ns, s, c-1);
strncat(ns, inlet, 1);
strcat(ns, &s[c]);
dosomething(c+1, ns);
//free(ns);
}
}
void main() {
for(int i = 0; i < 100; i++) {
char *s = malloc(sizeof(char)*11);
strcpy(s, dummy);
dosomething(1, s);
free(s);
}
}
代码运行得很好,直到我取消注释 dosomething() 方法中的 free() 调用。这就是我不明白的地方。在我看来,释放内存绝对没有问题,因为从递归调用返回后不再使用它,但程序输出告诉了一些不同的东西。
没有free的输出符合预期:
...
1_34567890
1_34567890
...
第二个空闲时,只产生一个结果,而不是程序停止:
*** Error in `./a.out': malloc(): memory corruption (fast): 0x000000000164e0d0 ***
Abgebrochen (Speicherabzug geschrieben)
更新: 我根据cmets和answers更改了代码,但问题依然存在。如果对 dosomething() 方法中的 free() 调用进行了注释,则使用 malloc 分配更多内存并不能防止内存错误。递归的第一次迭代正确生成输出,第二次显示不同的结果,第三次也是,然后程序失败(有关新结果,请参阅函数顶部的新 printf:
输出:
1234567890
_234567890
__34567890
___4567890
____567890
_____67890
______7890
_______890
________90
_________0
1234567890
@@J_234567890
@@J_J_234567890
@@J__J_234567890
@@J___J_234567890
@@J___J_234567890
@@J___J_234567890
@@J____J_234567890
@@J____J_234567890
@@J_____0__234567890
1234567890
@@J_234567890
@@J_J_234567890
@@J__J_234567890
@@J___J_234567890
@@J___J_234567890
@@J___J_234567890
@@J____J_234567890
@@J____J_234567890
@@J_____0__234567890__234567890
*** Error in `./a.out': free(): invalid next size (fast): 0x00000000014a4130 ***
Abgebrochen (Speicherabzug geschrieben)
谁能给我解释一下,我在眨眼什么?
更新2: @Michi 和@MichaelWalz 已经解决了这个问题。它是使用 malloc 之间的组合 - 因此在第一次迭代后处理内存中的垃圾(打印内存地址和字符串显示非常整洁),并在其上使用 strcat。
在未初始化的内存上使用 strcat 会将内存中的字符串附加到内存中指针之后找到的下一个“\0”字符。如果内存没有初始化,这可能会远远超出该字符串的范围。
谢谢你们!
工作代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *dummy = "1234567890";
const char* inlet = "_";
void dosomething(int c, char* s){
printf("%p %s\n", s, s);
if (c < 10) {
//char *ns = malloc(sizeof(char)*11);
char *ns = calloc(11, sizeof(char));
strncpy(ns, s, c);
strncat(ns, inlet, 1);
strncat(ns, &s[c+1],10-c);
dosomething(c+1, ns);
free(ns);
}
}
void main() {
for(int i = 0; i < 100; i++) {
//char *s = malloc(sizeof(char)*11);
char *s = calloc(11, sizeof(char));
strcpy(s, dummy);
dosomething(0, s);
free(s);
}
}
【问题讨论】:
-
变量
dummy指向包含11个字符的数组的第一个元素。 -
不要将
malloc和朋友的结果投射到C中! -
为什么您需要在
ns = strcat( ns, &s[2] )中分配?只有strcat就足够了 - 请参阅功能描述。&s[2]也与s + 2相同(我发现它的语法更短)。 -
你忘记在
free里面dosomething;考虑使用valgrind 并使用所有警告和调试信息进行编译 (gcc -Wall -Wextra -g) -
@i486:
&a[i]如果你真的有一个数组会更清楚。相当多的编码标准(例如 MISRA)禁止显式指针算术语法。