首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C:动态字符数组崩溃堆

C:动态字符数组崩溃堆
EN

Stack Overflow用户
提问于 2013-04-03 11:27:06
回答 3查看 558关注 0票数 1

我再次提出了一个关于C. (由VS2012编译的ANSI)的工作原理的问题。

我正在将一个独立的程序(.exe)重构为一个.dll。到目前为止,这还不错,但是当涉及到伐木时,我遇到了一些问题。让我解释一下:

最初的程序--在运行时--编写了一个日志文件并将信息打印到屏幕上。因为我的dll将运行在一个dll服务器上,许多人同时访问它,所以

  • 没有真正的机会正确地处理日志文件(并在它们之后清理)
  • 没有任何人会看到的控制台窗口

因此,我的目标是将日志文件或屏幕上的所有内容写入类似字符串的变量(我知道C中没有字符串),然后我可以将请求传递给调用者(也是一个dll,但用C#编写)。

因为在C语言中,这样的事情是不可能的:

代码语言:javascript
复制
char z88rlog;
z88rlog="First log-entry\n";
z88rlog+="Second log-entry\n";

我有两种可能性:

  1. char z88rlog[REALLY_HUGE];
  2. 动态分配内存

在我看来,第一种方法是被忽视,因为:

  • 潜在的内存浪费是相当巨大的。
  • 我可能仍然需要比REALLY_HUGE更多的内存,从而造成缓冲区溢出。

剩下第二条路了。我在这方面做了一些工作,并提出了两种解决方案,任何一种都不能正常工作。

代码语言:javascript
复制
/* 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将两个“字符串”连接起来。使用断点--直接窗口--我获得了以下输出:

代码语言:javascript
复制
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:

代码语言:javascript
复制
/* 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)种方法,我想实现这种“字符串增长”,但没有工作。给出大小的错误会让我得出数组变得太大的结论吗?我希望我能很好地解释我想做的事情,有人可以帮我:-谢谢!

对梅比的讽刺,我应该去买些新的电脑堆。它适合内存插槽吗?有人能重塑一个好品牌吗?反讽

EN

回答 3

Stack Overflow用户

发布于 2013-04-03 11:30:40

这是解决方案1的一个错误。

代码语言:javascript
复制
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));

因为没有为终止空字符分配空格。请注意,您必须将realloc()的结果存储到一个临时变量中,以避免发生故障时的内存泄漏。纠正:

代码语言:javascript
复制
char* tmp = realloc(z88rlog, strlen(z88rlog) + strlen(tmpstr) + 1);
if (tmp)
{
    z88rlog = tmp;
    /* ... */
}

解决方案2中的错误

代码语言:javascript
复制
z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
                                      /*^^^^^^^^^*/

它计算的长度小于tmpstr的长度。纠正:

代码语言:javascript
复制
z88rlogtmp=malloc(strlen(z88rlog) + strlen(tmpstr) + 1);

指针重新分配导致未定义的行为:

代码语言:javascript
复制
    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中执行,那么它几乎肯定是在多线程环境中运行的。由于您有一个全局变量,它将需要同步访问。

票数 2
EN

Stack Overflow用户

发布于 2013-04-03 11:30:13

你好像有很多问题。首先,在您的realloc调用中,您不为终止'\0'字符分配空间。在第二个解决方案中,您有strlen(tmpstr+1),这是不正确的。在您的第二个解决方案中,您还可以使用strcat来附加到现有的缓冲区z88rlog,如果它不够大,就会覆盖未分配的内存,或者覆盖为其他东西分配的数据。strcat的第一个参数是目标,这也是函数返回的内容,因此您也释放了新分配的内存。

第一个解决方案,使用realloc,应该工作良好,如果您只是记得分配额外的字符。

票数 1
EN

Stack Overflow用户

发布于 2013-04-03 11:42:43

在解决方案1中,您需要为终止NULL字符分配空间。因此,realloc应该包括多一个空间,即

代码语言:javascript
复制
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr) + 1);

在第二个解决方案中,我不确定这个z88rlogtmp=strcat(z88rlog,tmpstr);,因为z88rlog是目标字符串。如果您希望只执行malloc,那么

代码语言:javascript
复制
 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 string
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15786076

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档