2013-03-31 74 views
-4

使用的sprintf输出的额外字符串,如“%×......”的sprintf输出的额外字符串

int main() 
{ 
    char *word_tmp = new char[0]; 
    char *word_all = new char[0]; 

    for(int i=0;i<5;i++) 
    { 
     sprintf(word_tmp, "\nNumber:%d, Good Good!", i); 
     sprintf(word_all, "%s%s", word_all, word_tmp); 
    } 

    std::cout<<word_all; 
} 

该项目工程的权利,但输出字符串我没有输出。

回答

3

你的阵列具有零长度,所以在没有足够大的缓冲区word_tmp举行第一次调用sprintf(),这会导致缓冲区溢出的结果。因此,在这种情况下,您首次致电sprintf()的行为未定义。

除此之外,if copying takes place between objects that overlap as a result of a call to sprintf() or snprintf(), the results are undefined

最后,你的函数正在泄漏内存,因为你没有为new[]分配的数组调用delete[]

您应该使用std::ostringstream做你正试图在一个类型安全的方式达到什么样的(学分James Kanze为察觉的问题与我以前试图产生一个最小的修复你的程序):

#include <iostream> 
#include <sstream> 

int main() 
{ 
    std::ostringstream ss; 
    for (int i = 0; i < 5; i++) 
    { 
     ss << "Number: " << i << ", Good Good!" << std::endl; 
    } 

    std::cout << ss.str(); 
} 

这是一个live example

+0

很可能他不想要这样的事情。例如,幻数256是什么意思?例如,该程序仍然充满未定义的行为:违反'sprintf'参数上的'restrict'。 (更不用说所有违反良好编码习惯的情况:例如,使用'memset',例如,简单的初始化就可以实现;使用'sprintf';使用'char []'时'std :: string'会更合适,等等等等) –

+0

@JamesKanze:是的,我同意。我只是不想完全改变OP的程序,因为这不会回答他的问题(“什么导致了我的程序的怪异行为?”)。所以我基本上试图“说出他的语言”来找到一个共同点,可能我没有正确地做到这一点。当然我同意使用'std :: string'更好,但是这会使得不可能使用'sprintf'。很好,我可以显示'std :: stringstream'等,但OP可能需要先到达那里。 –

0

我真的很惊讶这段代码不会崩溃......您的sprintf目标字符串没有足够的空间放置数据。同时,我刚才输入的人sprintf和阅读:

C99 and POSIX.1-2001 specify that the results are undefined if a call to sprintf(), 
snprintf(), vsprintf(), or vsnprintf() would cause copying to take place between objects 
that overlap (e.g., if the target string array and one of the 
supplied input arguments refer to the same buffer). 

所以你的第二个sprintf的是C99不确定的。

另外这真的很奇怪,你使用C++ new运算符并使用sprintf来附加字符串并将数字插入到字符串中,在C++中,你有std :: string和stings流以安全的方式执行此操作。

我认为你需要阅读一些书籍,并了解c和C++中发生了什么。

+0

未定义的行为不能保证崩溃。 IIRC,'new [0]'需要返回一个非空指针,并被有效地实现,就好像它是'new [1]'一样。无疑,他正在破坏自由空间领域,如果他要做一个“删除”(或者如果他试图分配更多的内存),程序可能会崩溃。最后,关于违反“限制”的问题:这可能就是为什么他的输出不符合他的预期。 –

+0

@JamesKanze我从未说过未定义的行为等于崩溃。我刚才提到我很惊讶,程序没有崩溃。两个错误的内存写入已完成,预计将以null结尾的字符串和重叠的null(?)终止的字符串副本完成(有些功能可以根据自己的需要获取该内存块)。我敢肯定,这是完全可能的,一些空终止符可以填充一些数据和足够的非空垃圾之后。 (在这里,我甚至不希望第一次写入时即时发生段错误)。 – JustAnotherCurious

0

首先,你永远不想使用sprintf。几乎不可能的 正确使用。在这种情况下,您将它的值输出到 不存在的内存,因此您有未定义的行为。 (到底有多少内存,你认为new char[0]是要 分配?在第二sprintf,你也从 内存不存在—更多不确定的行为输入,以及 您输出,并从输入。相同的内存(假设 ,有任何内存),这也是不确定的行为

忘掉sprintf和数组新:

std::string results; 
for (int i = 0; i != 5; ++ i) { 
    std::ostringstream s; 
    s << "Number: " << i << " Good Good!\n"; 
    results += s.str(); 
} 
std::cout << results; 

(我认为这是你想要做什么。)

最后一点:虽然它几乎从不是一个真正的问题,但标准确实要求输出到文本流的最后一个字符(如std::cout)为'\n'