Malloc,strlen,strcat

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

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进程影响其他地方完全不相关的数组?

然而strcat执行没有问题。

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

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

正确的方法是分配内存

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

由于sizeof "-results.pdb"为13,因此它处理终止NUL的“+1”。

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

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

那里! 没有strlen,没有strcat,没有sizeof,没有malloc。 只是一个一体化的电话做正确的事 TM

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

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

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

所以不可预测的意思是“一切都可能发生”,你的情况就是一种事物

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

这就是为什么使用strncat总是更好,所以你可以指定缓冲区大小,甚至可以使用asprintf进行字符串连接,它会根据需要为你分配尽可能多的内存。

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

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

然后你将有一个指向新的malloc ed字符串的指针,在你的newstr ,不要忘记在之后释放它。

你可以对malloc更加慷慨

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

这将避免strcat的dest size问题,它会覆盖内存的任意部分,导致以后出现问题……正如其他答案所提到的,’未定义的行为’……

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

将其添加到头文件中

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

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

 _CrtSetDbgFlag _CrtSetBreakAlloc 

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

GCC内存泄漏检测相当于Microsoft crtdbg.h?