首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C: vsprintf覆盖数组

C: vsprintf覆盖数组
EN

Stack Overflow用户
提问于 2012-05-21 18:01:07
回答 2查看 223关注 0票数 0

我在使用vsprintf函数时遇到了一个问题。

我有3个函数可以打开、关闭和写入XML文件。open函数将输入文本的第一个单词存储在数组中,close函数用该单词结束标记。问题是,我存储要使用的关闭标记的数组在每次调用open或write函数时都会被覆盖(即使write函数没有任何对用于存储关闭标记的数组的引用)。

代码语言:javascript
运行
复制
int xml_level = 0;
char *xml_header[64];
FILE *xml_out;

void xmlopen(const char *format, ...){
   char buffer[256];
   va_list arglist;
   va_start(arglist,format);
   vsprintf(buffer,format,arglist);
   va_end(arglist);
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"<%s>\n",buffer);
   xml_header[xml_level] = strtok (buffer, " ");
   xml_level++;
}

void xmlclose(){
   xml_level--;
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"</%s>\n",xml_header[xml_level]);
}

void xmlwrite(const char *format, ...){
   char buffer[256];
   va_list arglist;
   va_start(arglist,format);
   vsprintf(buffer,format,arglist);
   va_end(arglist);
   int i;
   for(i=0; i<xml_level; i++){
      fprintf(xml_out,"\t");  
   }
   fprintf(xml_out,"<%s/>\n",buffer);
}

使用示例:

代码语言:javascript
运行
复制
xmlopen("Hello Word");
xmlopen("Foo Bar");
xmlwrite("Potato");
xmlwrite("Sentence longer than the other ones");
xmlclose();
xmlclose();

输出示例:

代码语言:javascript
运行
复制
<Hello Word>
        <Foo Bar>
                <Potato/>
                <Sentence longer than the other ones/>
        </Sentence longer than the>
</Sentence longer than the>

它应该在哪里:

代码语言:javascript
运行
复制
<Hello Word>
        <Foo Bar>
                <Potato/>
            <Sentence longer than the other ones/>
        </Foo>
</Hello>

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-21 19:04:15

解决方案

更改此行:

代码语言:javascript
运行
复制
xml_header[xml_level] = strtok (buffer, " ");

代码语言:javascript
运行
复制
xml_header[xml_level] = strdup (strtok(buffer, " "));

并且记得在你的程序退出时释放xml_headers。

当然,你还需要检查可能出现的情况,比如strtokstrtok NULL,等等。

说明

strtok不会为返回的令牌分配额外的存储空间。我个人怀疑它会用\0 in place代替分隔符,并且每次都会返回指向下一个令牌开头的指针。

请注意,在您的代码中,在开始时在xmlopenxmlwrite中都分配了256字节的缓冲区,回想一下,这个缓冲区将在堆栈中分配。因此,在您对xmlopenxmlwrite的调用中,buffer实际上将指向相同的地址(您可以打印它的值来验证这个printf("buffer is %p\n", buffer),它在我的机器上是0xbff2481c )。

首先,调用xmlopen("Hello World")xml_header[0]将指向"Hello",这也是buffer的开始。然后调用xmlopen("Foo Bar")xml_header[1]将指向"Foo",它也是buffer的开始。然后调用xmlwrite("Portato")xmlwrite("Sentence longer than the other ones")。注意,在这一点上,xml_header[1]仍然指向buffer的开始,现在是"Sentence longer than the other ones"。因此,当您调用xmlclose()时,它将打印出该语句,而不是您期望的令牌,后者将被稍后的缓冲区覆盖。

有趣的是,如果您在xmlopenxmlwrite中分配不同的缓冲区大小,比如xmlopen为256字节,xmlwrite为128字节,那么您将看到xmlclose将打印出一些不可读的乱码。

您可以通过检查(例如,打印) xml_header[0], xml_header[1]buffer的值来验证所有这些。

票数 1
EN

Stack Overflow用户

发布于 2012-05-21 18:16:10

您的问题是,在xmlopen中只有一个名为buffer的局部变量,并且您(a)存储指向它的指针以供在函数外部使用(未定义的行为)和(b)试图在多个调用中使用它(逻辑错误)。

您需要为strtok返回的字符串分配存储空间,并确保稍后将其处理掉,例如:

代码语言:javascript
运行
复制
xml_header[xml_level] = strtok (buffer, " ");

至:

代码语言:javascript
运行
复制
char * s = strtok(buffer, " ");
if (s != NULL)
{
    xml_header[xml_level] = strdup(s);
}

(以后不再需要这些字符串时,如何处理它们将留给读者作为练习。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10683158

复制
相关文章

相似问题

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