0

在这个最小的例子中,字符串流的输入和以前使用的 cout 的内容之间有一个奇怪的混乱:

在线gdb: https ://onlinegdb.com/itO69QGAE

代码:

#include <string>
#include <iostream>
#include <sstream>

using namespace std;

const char sepa[] = {':', ' '};
const char crlf[] = {'\r', '\n'};


int main()
{
    cout<<"Hello World"  << endl;

    stringstream s;
    
    string test1 = "test_01";
    string test2 = "test_02";


    s << test1;
    cout << s.str() << endl;
    // works as expected
    // excpecting: "test_01"
    // output: "test_01"
    
    s << sepa;
    cout << s.str() << endl;
    // messing up with previous cout output
    // expecting: "test_01: "
    // output: "test_01: \nHello World"
    
    s << test2;
    cout << s.str() << endl;
    // s seems to be polluted
    // expecting: "test_01: test_02"
    // output:  "test_01: \nHello Worldtest_02"
    
    s << crlf;
    cout << s.str() << endl;
    // once again messing up with the cout content
    // expecting: "test_01: test_02\r\n"
    // output: "test_01: Hello Worldtest_02\r\nHello World"

    return 0;
}

所以我想知道为什么会这样?

因为它仅在将 char 数组推入 stringstream 时才会发生,这很可能是这样的......但根据参考,stringstream 的“<<”-operator 可以/应该处理 char*(这个数组的名称实际上代表什么) .

除此之外,stringstream 和 cout 之间似乎存在(?隐藏的,或者至少不明显的?)关系。那么为什么内容会污染到字符串流中呢?

在这个例子中是否有任何错误/愚蠢的用法或者狗被埋在哪里(-> 德语成语 :P )?

最好的问候和感谢达米安

PS我的问题不是关于“解决”这个问题,比如使用字符串而不是char数组(这会起作用)......这是关于理解内部机制以及为什么这实际上会发生,因为对我来说这只是一个意想不到的行为.

4

2 回答 2

0

std::stringstream::str()函数返回一个字符串,其中包含先前在所有先前调用(或其他输出函数)中写入流中的所有字符。但是,您似乎希望只返回最后一个输出操作 - 事实并非如此。operator<<

这类似于 egstd::cout的工作方式:每次调用都std::cout <<将字符串附加到标准输出;它不会清除控制台的屏幕。

为了实现你想要的,你要么std::stringstream每次都需要使用一个单独的实例:

std::stringstream s1;
s1 << test1;
std::cout << s1.str() << std::endl;

std::stringstream s2;
s2 << sepa;
std::cout << s2.str() << std::endl;

或者更好的是,清除函数的std::stringstreamusing 单参数重载的内容str()

std::stringstream s;

s << test1;
std::cout << s.str() << std::endl;

// reset the contents of s to an empty string
s.str(""); 
s << sepa;
std::cout << s.str() << std::endl;

s.str("")调用有效地丢弃了之前写入流中的所有字符。请注意,即使std::stringstream包含一个clear()看起来更好的函数,它也不类似于 eg std::string::clear()orstd::vector::clear()并且不会产生您的情况所需的效果。

于 2021-07-27T10:25:11.627 回答
-1

我又来了

感谢“一些程序员老兄”的评论,我想我明白了:

由于没有与两个 char 数组相关的 (null-)termination-symbol ,似乎 stringstream- 运算<<符会插入,直到它偶然发现 null-terminator '\0'

\0使用- 符号(例如)扩展两个数组const char sepa[] = {':', ' ', '\0'}或使用 eg 终止长度s << string(sepa,2)将执行预期的输出。

在上述特定情况下,数据似乎在内存中对齐,因此将在cout << "Hello World"-statement 中找到下一个空终止符。由于无法保证这种对齐方式,因此当缺少终止时,这实际上会导致未定义的行为。

因此,还有两个额外的“终止”数组,例如const char sepa[] = {':', ' '}; char[] end_of_sepa = {'\0'};在提到的数组之后立即声明的例如,将导致预期的输出,即使其余部分保持不变......但这可能无法保证,并且取决于内存中的内部表示。

PS 如前所述,这个问题不是关于修复而是理解。因此,请随时确认或更正我的假设。

编辑:更正了粗体代码部分。

于 2021-07-27T11:58:12.450 回答