我再次提出了一个关于C. (由VS2012编译的ANSI)的工作原理的问题。
我正在将一个独立的程序(.exe)重构为一个.dll。到目前为止,这还不错,但是当涉及到伐木时,我遇到了一些问题。让我解释一下:
最初的程序--在运行时--编写了一个日志文件并将信息打印到屏幕上。因为我的dll将运行在一个dll服务器上,许多人同时访问它,所以
因此,我的目标是将日志文件或屏幕上的所有内容写入类似字符串的变量(我知道C中没有字符串),然后我可以将请求传递给调用者(也是一个dll,但用C#编写)。
因为在C语言中,这样的事情是不可能的:
char z88rlog;
z88rlog="First log-entry\n";
z88rlog+="Second log-entry\n";我有两种可能性:
char z88rlog[REALLY_HUGE];在我看来,第一种方法是被忽视,因为:
REALLY_HUGE更多的内存,从而造成缓冲区溢出。剩下第二条路了。我在这方面做了一些工作,并提出了两种解决方案,任何一种都不能正常工作。
/* Solution 1 */
void logpr(char* tmpstr)
{
extern char *z88rlog;
if (z88rlog==NULL)
{
z88rlog=malloc(strlen(tmpstr)+1);
strcpy(z88rlog,tmpstr);
}
else
{
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));
z88rlog=strcat(z88rlog,tmpstr);
}
}在解决方案1(等于解决方案2)中,我通过char tmpstr[255];传递我的新日志条目。我的“日志文件”z88rlog是全局声明的,所以我需要extern来访问它。然后,我检查是否为z88rlog分配了内存。如果没有,则分配日志条目的大小(\0为+1),并将tmpstr的内容复制到z88rlog中。如果是的话,我为z88rlog重新分配内存,其大小为+ tmpstr (+1)的长度。然后使用strcat将两个“字符串”连接起来。使用断点--直接窗口--我获得了以下输出:
z88rlog
0x00000000 <Schlechtes Ptr>
z88rlog
0x0059ef80 "start Z88R version 14OS"
z88rlog
0x0059ef80 "start Z88R version 14OS
opening file Z88.DYNÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þîþîþîþ"它显示了logpr的三个连续调用(strcpy/strcat之前的断点)。最终无法区分的胡言乱语是内存分配的结果。之后,VS给出了一条错误消息,说明是什么原因导致调试器在realloc.c中设置了断点。因为这显然不起作用,我炮制了我的绝妙解决方案2:
/* Solution 2 */
void logpr(char* tmpstr)
{
extern char *z88rlog;
char *z88rlogtmp;
if (z88rlog==NULL)
{
z88rlog=malloc(strlen(tmpstr)+1);
strcpy(z88rlog,tmpstr);
}
else
{
z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
z88rlogtmp=strcat(z88rlog,tmpstr);
free(z88rlog);
z88rlog=malloc(strlen(z88rlogtmp)+1);
memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
free(z88rlogtmp);
}
}这里我的目标是创建我的日志文件的副本,释放原件的内存,在新的大小中为原始内存创建新的内存,并将内容复制回来。不要忘记释放临时副本,因为它是通过malloc分配的。当它到达free时,它立即崩溃,再次告诉我堆可能被破坏。
因此,让我们暂时免费发表评论。这确实更好--这让我松了一口气--但是在构建日志字符串时,并不是所有的z88rlogtmp字符都会被复制。但一切还是正常的。直到突然间,我再次被告知堆可能被破坏,调试器在_heap_alloc (size_t size) in malloc.c size的末尾放置一个断点--根据调试器--值为1041。
因此,我有2(或3)种方法,我想实现这种“字符串增长”,但没有工作。给出大小的错误会让我得出数组变得太大的结论吗?我希望我能很好地解释我想做的事情,有人可以帮我:-谢谢!
对梅比的讽刺,我应该去买些新的电脑堆。它适合内存插槽吗?有人能重塑一个好品牌吗?反讽
发布于 2013-04-03 11:30:40
这是解决方案1的一个错误。
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));因为没有为终止空字符分配空格。请注意,您必须将realloc()的结果存储到一个临时变量中,以避免发生故障时的内存泄漏。纠正:
char* tmp = realloc(z88rlog, strlen(z88rlog) + strlen(tmpstr) + 1);
if (tmp)
{
z88rlog = tmp;
/* ... */
}解决方案2中的错误
z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
/*^^^^^^^^^*/它计算的长度小于tmpstr的长度。纠正:
z88rlogtmp=malloc(strlen(z88rlog) + strlen(tmpstr) + 1);指针重新分配导致未定义的行为:
z88rlogtmp=strcat(z88rlog,tmpstr);
/* Now, 'z88rlogtmp' and 'z88rlog' point to the same memory. */
free(z88rlog);
/* 'z88rlogtmp' now points to deallocated memory. */
z88rlog=malloc(strlen(z88rlogtmp)+1);
/* This call ^^^^^^^^^^^^^^^^^^ is undefined behaviour,
and from this point on anything can happen. */
memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
free(z88rlogtmp);此外,如果代码在Web中执行,那么它几乎肯定是在多线程环境中运行的。由于您有一个全局变量,它将需要同步访问。
发布于 2013-04-03 11:30:13
你好像有很多问题。首先,在您的realloc调用中,您不为终止'\0'字符分配空间。在第二个解决方案中,您有strlen(tmpstr+1),这是不正确的。在您的第二个解决方案中,您还可以使用strcat来附加到现有的缓冲区z88rlog,如果它不够大,就会覆盖未分配的内存,或者覆盖为其他东西分配的数据。strcat的第一个参数是目标,这也是函数返回的内容,因此您也释放了新分配的内存。
第一个解决方案,使用realloc,应该工作良好,如果您只是记得分配额外的字符。
发布于 2013-04-03 11:42:43
在解决方案1中,您需要为终止NULL字符分配空间。因此,realloc应该包括多一个空间,即
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr) + 1);在第二个解决方案中,我不确定这个z88rlogtmp=strcat(z88rlog,tmpstr);,因为z88rlog是目标字符串。如果您希望只执行malloc,那么
z88rlogtmp=malloc(strlen(z88rlog)+1 // Allocate a temporary string
strcpy(z88rlogtmp,z88rlog); // Make a copy
free(z88rlog); // Free current string
z88rlog=malloc(strlen(z88rlogtmp)+ strlen(tmpstr) + 1)); //Re-allocate memory
strcpy(z88rlog, z88rlogtmp); // Copy first string
strcat(z88rlog, tmpStr); // Concatenate the next string
free(z88rlogtmp); // Free the Temporary stringhttps://stackoverflow.com/questions/15786076
复制相似问题