以下是我正在编写的程序开头的一段代码(包含错误).
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");
这样可以处理终止NUL的"+1",因为它sizeof "-results.pdb"
是13.
更容易使用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
,不要忘记在之后释放它.