Malloc,strlen,strcat

时间:2016-01-06 11:29:32

标签: c arrays memory-management

以下是我正在编写的程序开头的一段代码(包含错误)。

    char *name;
    char *name2;

    if (argn != 2) {
        printf("You have to enter the name of the input file");
        return 1;
    }

    name = malloc(strlen(arg[1]) + 1);      
    name2 = malloc(strlen(arg[1]) + 1);

    strcpy(name, arg[1]); 
    strcpy(name2, arg[1]);

    strcat(name2, "-results.pdb");  

此处出现错误strcat,确实name2没有足够的大小来执行上述操作。然而strcat执行没有问题。 但是后来在程序的一个完全不相关的部分中,在strcat之后初始化的另一个数组的操作给出了错误。 它是一个整数数组,我为其分配值,并在分配所有值之前给出错误。我假设因为上面的操作在name2中没有足够的内存,所以“某种程度上”会影响下一个初始化的数组。我想了解:

1-这里可能发生什么,以至于无法写入name2的额外信息会影响稍后声明的其他数组?

2-我可能无法在更复杂的程序中轻易地回溯此问题,因为错误发生在其他地方而不是strcat中。如何防止像memory problematic进程这样的偷偷摸摸的错误影响其他地方完全不相关的数组呢?

3 个答案:

答案 0 :(得分:10)

  

然而strcat执行没有问题。

不,它没有。它返回,但它已经种下了定时炸弹。正如你稍后观察的那样。

未定义的行为会发生什么。你已写入内存,你不能写。无论存储什么,现在都有垃圾,任何代码都希望找到有意义的价值,现在行为不端。 特别是如果malloc内部数据被破坏,则在尝试重新分配或释放内存时,观察会随机崩溃。

正确的方法是使用

分配内存
name2 = malloc(strlen(arg[1]) + sizeof "-results.pdb");

这会照顾" + 1"对于终止NUL,因为sizeof "-results.pdb"是13。

更容易使用asprintf(不是ISO C,但可以在任何现代Unix上使用),它根据需要分配内存:

asprintf(&name2, "%s-results.psb", arg[1]);

有!没有strlen,没有strcat,没有sizeof,没有malloc。只是一个一对一调用 Right Thing TM

答案 1 :(得分:5)

就像strcat的手册对你说的那样:

char *strcat(char *dest, const char *src);

  

strcat()函数将src字符串追加到dest字符串,   覆盖dest末尾的终止空字节('\ 0'),和   然后          添加一个终止空字节。字符串可能不重叠,dest字符串必须有足够的空间用于结果。 如果是的话   不大          足够的,程序行为是不可预测的; 缓冲区溢出是攻击安全程序的最佳途径。

所以不可预测意味着“一切都可能发生”,你的情况是一种一切

你应该知道,一切都是真实的一切,所以程序可能会在strcat调用时崩溃,甚至可能按预期工作(这次),可能会在其他地方崩溃,因为它已经过了一些内存所占用的内存例如,malloc内部,现在它不知道要释放什么。这实际上取决于您的系统以及内存是char *dest的位置,每次运行程序时这可能会有所不同。

这就是使用strncat总是更好的原因,因此您可以指定缓冲区大小,甚至可以使用asprintf进行字符串连接,它会为您分配尽可能多的内存,因为它需要

对于你的例子,你会写这样的东西:

char *newstr = NULL;
asprintf(&newstr, "%s%s", name2,"-results.pdb");

然后你会在malloc中找到指向新newstr ed字符串的指针,不要忘记在之后将其释放。

答案 2 :(得分:-4)

你可以对你的malloc更加慷慨

transitionTo

这可以避免name2 = malloc(strlen(arg[1])+100); 的目标大小问题,这会覆盖内存的任意部分,导致以后出现问题......正如其他答案所提及的那样,未定义的行为' ..

如果您可以使用Microsoft C ++编译器,那么内存泄漏检测器将有助于: https://msdn.microsoft.com/en-us/library/e5ewb1h3%28v=vs.90%29.aspx

将此添加到您的标题文件

strcat

然后在main中的代码中使用这些函数,然后再使用其他函数:

#ifdef _Windows
#include "stdlib.h"
#include "crtdbg.h"
#endif

应该有很多好的资源,使用起来比看起来更简单。有关更多变化,请参阅此链接:

GCC memory leak detection equivalent to Microsoft crtdbg.h?