C++中字符串串联后崩溃

Crash after string concatenation in C++

本文关键字:崩溃 字符串 C++      更新时间:2023-10-16

我有一个从串行端口读取数据的程序。对于每一行,我都试图将当前时间与数据行连接起来。出于某种原因,它在第二次打印时崩溃(看起来像在括号的末尾?)。奇怪的是,如果我评论打印结果,它仍然会崩溃

char * cdata;
{
    if( BINARY_ASCII == 1 ) //right now this is just set to 0, please ignore
    {
        cdata = convertBSTRToByteArray(data , numChars);
    }
    else
    {
        cdata = convertBSTRToString(data);
        //prints the original output
        cout << "before timestamp concat is: " << cdata << "n";
        //this is supposed to concatenate each output line with the associated time
        std::stringstream ss;
        ss << currentDateTime() << "," << cdata;
        std::string s = ss.str();
        std::strcpy(cdata,s.c_str());
        cout << "after timestamp concat is: " << cdata << "n"; //around here it crashes
}
cout << "after the thing" << "n"; //does not even get here     

我原以为char*数据会是个问题,但我试着像一样初始化它

char *cdata = 0;

char *cdata = new char [100];

没有变化。。。

这让我觉得我在串联中做错了什么?

我认为在这里强调数组和指针之间的区别很重要。

char * cdata;

这将创建一个名为cdata的指针。它是未初始化的,所以它包含一些无用的内存地址。指针只是一个内存地址,这意味着它占用32(或64)位,仅此而已

char *cdata = 0;

这将创建一个名为cdata的指针,并将其初始化为全零,这意味着它指向内存中的第0个位置。这通常用于指示您不应该跟随此指针。

char *cdata = new char [100];

这会创建一个包含100个字符的块(数组),但不会为该数组命名。然后,它创建一个名为cdata的指针,并将其设置为未命名的100字节块的内存地址。即:

cdata [ 0x3Ad783B2 ] --------
                              
                               
                               |
                               V
                             [ unnamed 100-byte block ]

我强调这一区别的原因是下一行将其全部抹杀:

cdata = convertBSTRToString(data);

该行将cdata设置为指向convertBSTRToString返回的任何内存地址。这一行之前cdata的值是多少并不重要——未初始化,为null,指向未命名的内存块——现在它指向由convertBSTRToString创建的内存块。

滥用更多ASCII艺术:

cdata [ 0x64ADB7C8 ] --------
                              
                               
                               |
                               V
                             [ unknown size, created by convertBSTRToString ]
                             // hey, look over here!  it still exists,
                             // but we just don't point to it anymore.
                             [ unnamed 100-byte block ]

既然已经涵盖了这一点,这就是为什么它很重要。此行:

std::strcpy(cdata,s.c_str());

strcpy将获取第二个参数所指向的数据,并逐字节将其复制到第一个参数所指的位置。它不关注缓冲区大小。这真是一本愚蠢的书。没有任何安全——这取决于你自己。

无论如何,我不确定您想用这一行完成什么,因为s保存了您想要连接的完整字符串数据:

cout << "after timestamp concat is: " << s << "n";

convertBSTRToString可能会分配一个新的缓冲区,该缓冲区的大小刚好可以容纳您传入的BSTR。这意味着您无法扩展其大小。

在您的代码中,您试图将currentDateTime()的结果添加到该缓冲区中(除了现有内容之外)。数据不合适。于是,坏事就发生了。

您需要首先分配一个足够大的缓冲区,以包含convertBSTRToString和currentDateTime,然后strcpy convertBSTRToString,然后strcat currentDateTime。strcpy不会追加,strcat会追加。