当前位置:  开发笔记 > 编程语言 > 正文

malloc和递归函数中的自由

如何解决《malloc和递归函数中的自由》经验,为你挑选了1个好方法。

我有一些代码给你,希望有人能告诉我,我错了.目前我正在将我的编程难题移植到其他编程语言中,以便获得一些动手.

C中的代码抽象(更新):

#include 
#include 
#include 
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()调用.这就是我不理解的.正如我所看到的,释放内存绝对没有问题,因为在从递归调用返回后不再使用它,但是programm输出告诉了不同的东西.

没有免费的输出符合预期:

...
1_34567890
1_34567890
...

使用第二个空闲时,只有一个结果,而程序停止时:

*** Error in `./a.out': malloc(): memory corruption (fast): 0x000000000164e0d0 ***
Abgebrochen (Speicherabzug geschrieben)

更新:我根据评论和答案更改了代码,但问题仍然存在.如果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)

任何人都可以向我解释一下,我在眨眼间的是什么?

Update2:@Michi和@MichaelWalz已经解决了这个问题.它是使用malloc之间的组合 - 因此在第一次迭代后处理内存中的垃圾(打印内存地址以及字符串显示非常整洁),并使用strcat.

在未初始化的内存上使用strcat会将内存中的字符串追加到内存中指针后面的下一个"\ 0"字符.如果内存未初始化,则可能远远超出该字符串的范围.

感谢你们!

工作代码:

#include 
#include 
#include 
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);
  }
}

Ring Ø.. 9

原因是因为malloc函数分配10个字符而需要11个字符(结束\0).

虽然这是依赖于实现的,但是高效的malloc函数可能使用分配区域内外的一些字节来设置一些内部信息.在此内部区域被更改(一个char太多)之后,free可以使用这些字节,最终结果是未定义的行为.

无论如何,更改甚至读取数组越界 UB.

更好用

char *s = malloc(strlen(dummy) + 1);

并且不要强制生成malloc的结果指针.



1> Ring Ø..:

原因是因为malloc函数分配10个字符而需要11个字符(结束\0).

虽然这是依赖于实现的,但是高效的malloc函数可能使用分配区域内外的一些字节来设置一些内部信息.在此内部区域被更改(一个char太多)之后,free可以使用这些字节,最终结果是未定义的行为.

无论如何,更改甚至读取数组越界 UB.

更好用

char *s = malloc(strlen(dummy) + 1);

并且不要强制生成malloc的结果指针.


这里至少还有一个问题:在第一次迭代时,`c`包含1.因此`strncpy(ns,s,c-1)`复制0字节并保持`ns`缓冲区不变.因此`ns`缓冲区包含垃圾.然后`strncat(ns,inlet,1);`产生未定义的bahaviour,因为`ns`指向未初始化的内存.如果要复制的长度小于源字符串的长度,您还可以认为`strncpy`可以保留目标字符串而不终止为零.
推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有