【问题标题】:empty string plus an int?空字符串加一个int?
【发布时间】:2016-01-09 05:19:01
【问题描述】:

这是我的部分代码:

//num is an int
string s = "" + num;

当我在 Macbook 上的 Xcode 中运行它时,s 将被分配给一个奇怪的字符串。 谁能给我解释一下? 我真的很困惑。 谢谢。

【问题讨论】:

  • XCode 默认使用 Clang AFAIK。 警告:向字符串添加 'int' 不会追加到字符串 [-Wstring-plus-int]
  • "" 是一个字符串文字,它衰减成一个指针,所以你实际上在这里做指针运算产生UB

标签: c++ string int


【解决方案1】:

我假设string 指的是std::string 类型,在标准头文件<string> 中声明。您没有将其作为上下文给出 - 从技术上讲,从您给出的信息来看,它可能是一些前面的 typedef 或宏。

解释原因

string s = "" + num;

给出一个“奇怪的字符串”是""在内存中表示为一个const数组,其中一个char的值为零。在表达式"" + num 中,"" 被转换为一个指针(等于该char 的地址,值为0),+ num 然后给出内存中某个位置的地址,num 后面的字符.

如果num 不为零,则该内存地址可能不存在,或者(如果存在)可能包含任意数据。

无论如何,该指针都会传递给std::string 的构造函数(以便构造s)。该构造函数从给定的地址开始,并不断将数据复制到std::string,直到它碰巧找到值为零的字符。中间的字符可以是任何东西——它们是那个内存位置发生的任何东西。

正式地,C++ 标准将所有这些(通过错误指针访问数据)描述为未定义的行为。这意味着 C++ 标准没有说明允许什么结果,因此允许任何结果。它可能会导致字符串中出现奇怪的数据。操作系统可能会检测到您的程序访问它不应该访问的内存,并强制终止您的程序。它可以重新格式化您的硬盘驱动器并重新安装您的操作系统。

假设您只想将 num 写入字符串(例如,num 的值 42 会生成类似 "42" 的字符串),那么通常的技术是将 num 转换为 std::string .例如;

 std::string s = to_string(num);   // C++11 or later

 #include <sstream>            //  pre_C++11 (albeit valid in C++11)
 std::ostringstream ostr;
 ostr << num;
 std::string s(ostr.str());

【讨论】:

  • 你忘了说恶魔可能会从他/她的鼻子里飞出来。 ;)
  • 这依赖于特定的硬件、固件和湿件支持。 :-)
  • 即时重新安装操作系统也是如此。 ;)
  • 谢谢。您的精彩解释解决了我所有的困惑。@Peter
  • @Xing:您解除了对多个无效指针的引用,并从它们的内存位置读取 - 这有资格进入未定义的行为领域。
【解决方案2】:
string s = std::to_string(num);

试试这个。

【讨论】:

    【解决方案3】:

    std::to_string() 的想法很好,但不幸的是它只适用于 C++11,而且我看到编译器虽然支持 C++11,但并不完全支持该方面。能用就用吧。

    如果它不起作用,试试这个:

    #include <sstream>
    
    ...
    
    int num = 5;
    float rNum = 63.2;
    std::stringstream ss;
    ss << num;
    ss << rNum;
    
    std::string s;
    ss >> s;
    
    cout << s << endl;
    

    您将获得格式化为一个字符串的 float 和 int 值。实际上,如果您有多个变量被格式化,我认为您最好使用字符串流。用ss &gt;&gt; s 将它们作为字符串拉出来,你就完成了!

    【讨论】:

    • 我建议使用auto s(ss.str());(如果可能)或std::string s(ss.str());,而不是使用operator&gt;&gt;
    • 有什么区别?它在技术上是相同的,是指优雅还是为什么std::string s(ss.str()); 更好?
    • 1.如果ss 包含空格see example,它在语义上是不同的。 2. 它可能更有效,因为std::basic_istreamstd::basic_string 中的operator&gt;&gt; 执行多次检查以避免读取越界/越过EOF 等。如果stringstreams 没有特殊过载,则检查将被执行。但是,basic_stringbuf 类通常包含一个 basic_string,它可以(全部或部分 - 如果过度分配)由 str() 返回。
    【解决方案4】:

    你得到不想要的答案的原因是 num 到空字符串 s 的算术加法,这基本上就像 C 语言中的指针加法。

    查看示例以获得更好的解释:

    例如。 1:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int num = 0;
    
        string s = "1234567890" + num;
        cout << s << endl;
    
        return 0;
    }
    

    输出: 1234567890

    例如。 2:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int num = 1;
    
        string s = "1234567890" + num;
        cout << s << endl;
    
        return 0;
    }
    

    输出: 234567890

    例如。 3:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int num = 4;
    
        string s = "1234567890" + num;
        cout << s << endl;
    
        return 0;
    }
    

    输出: 567890

    例如。 4:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int num = 8;
    
        string s = "1234567890" + num;
        cout << s << endl;
    
        return 0;
    }
    

    输出: 90

    等等……


    因为,这里的字符串s 是空的,而num 有垃圾值,这会导致未定义的结果。

    在将num 附加到空字符串s 之前,最好使用to_string()

    例子:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int num = 1000;
    
        string s = "" + to_string(num);
        cout << s << endl;
    
        return 0;
    }
    

    【讨论】:

    • "你得到不受欢迎的答案的原因是 intstring 的不必要转换。" 不。你的解决方案很好,但你的理由是错误的。
    • @ildjarn 你能告诉我我必须在我的答案中做出哪些改变吗?
    • 好的,它在运行一些测试用例后得到了它。再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 2020-04-30
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多