【问题标题】:String made from the first char of another string - why is it also printing the full original string?由另一个字符串的第一个字符组成的字符串 - 为什么它还打印完整的原始字符串?
【发布时间】:2013-04-10 18:23:56
【问题描述】:

学习 C++。我只想抓取一个字符串中的第一个字符,然后根据这个字符创建一个新的字符串,然后打印出来:

#include <iostream>
using namespace std;

int main(int argc, const char * argv[]) {
    string name = "Jerry";
    char firstCharacter = name.at(0);
    string stringOfFirstCharacter = string(&firstCharacter);
    cout << stringOfFirstCharacter;
    return 0;
}

输出是:

J
Jerry

我真的不知道为什么它还打印Jerry。这是为什么呢?

【问题讨论】:

  • 完全不相关,只是寻找信息,不作为判断:你是在代码中输入using namespace std;,还是被工具插入?
  • @PeteBecker:不久前我在一些示例代码中看到了它,从那以后我开始自己做。我曾经把它放在每个街区内,但这种方式对我来说似乎更方便。没有工具可以做到。为什么,这是一种奇怪的做法?
  • 这不是特别好(std::string 通常更好),但是我看到很多代码示例在 #includes 之后直接使用声明,我怀疑有些工具正在做它。感谢您提供信息。
  • @PeteBecker 这在初学者 C++ 书籍中很常见,但通常不足以解释他们这样做是为了简化代码示例,而不是因为这是一种好的做法。
  • @JBentley - 太糟糕了。但我对在#includes 之后立即看到它的一致性感到震惊:没有空行,好像它只是自动成为#include 指令的一部分。

标签: c++ string char iostream


【解决方案1】:

您的代码具有未定义的行为。采用指向 char 的指针的构造函数的签名要求它是指向 null 终止 字符串的指针,在您的情况下它不是,因为它是单个字符。

我的猜测是您的实现使用了小对象优化,并且“Jerry”足够小,可以存储在 std::string 对象中,而不是动态分配。堆栈中两个对象的布局恰好是先firstCharacter,然后是name。当您调用std::string(&amp;firstCharacter) 时,它会一直读取到第一个空字符(在std::string 缓冲区内)并停在那里。

【讨论】:

  • 不错的答案,+1 用于弄清楚为什么它会给出该输出。
【解决方案2】:

您正在从char* 构造一个std::string 对象(因为您正在获取firstCharacter 的地址)。 std::string 的构造函数不会将指向字符的指针解释为字符本身,而是将其解释为以 null 结尾的字符串。

在这种情况下,您的程序有未定义行为,因为firstCharacter 的地址不是以空字符结尾的字符串的第一个字符的地址。

你应该做的是:

string stringOfFirstCharacter(1, firstCharacter);
cout << stringOfFirstCharacter;

如果你真的想创建一个单字符的字符串。但是,请注意,为了将字符打印到标准输出,您可以简单地编写:

cout << firstCharacter;

甚至:

cout << name.at(0);

【讨论】:

  • +1。不过,我更喜欢“空终止”(小写)或“\0-终止”。 NULL 让我想到了空指针常量。
【解决方案3】:

使用string(&amp;firstCharacter),您正在使用表单的std::string constructor

std::string( const char* s, const Allocator& alloc = Allocator() );

该表单需要一个指向以空字符结尾的字符数组的指针。将指针传递给非空终止字符是不正确的。

如果您打算使用 1 char 初始化字符串,您应该使用以下形式:

string( 1, firstCharacter )

【讨论】:

    【解决方案4】:

    您正在使用的string 构造函数(接受char * 参数的构造函数)旨在将C 风格的字符串转换为C++ 字符串对象——而不是单个字符。通过将单个字符传递给它,您会导致未定义的行为。

    在您的具体情况下,firstCharacter 之后的内存中似乎没有零字节,因此构造函数会运行并包含所有 name

    【讨论】:

      猜你喜欢
      • 2017-03-31
      • 2021-10-04
      • 2012-03-13
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      相关资源
      最近更新 更多