C ++字符串copy()最后给了我额外的字符,为什么呢?

时间:2019-05-04 00:24:44

标签: c++

我正在学习c ++,在博客中,他们介绍了复制功能的概念。当我在系统中尝试相同的结果时,结果与我期望的结果不匹配。请在下面的代码中告诉我我做错了什么。

#include <iostream>

main(){

std::string statement = "I like to work in Google";
char compName[6];
statement.copy(compName, 6, 18);

std::cout<<compName;
}

我期望Google,但实际输出是Googlex

我正在使用Windows-(MinGW.org GCC-6.3.0-1)

2 个答案:

答案 0 :(得分:2)

您正在混淆字符序列,C样式字符串和std::string。让我们分解一下:

  1. 一个字符序列就是这样,在一个容器中(在您的情况下为C样式数组)一个接一个的字符。对于一个人来说,几个字符可能看起来像一个字符串,但是您的代码中没有让它如此的东西。
  2. C样式字符串是由符号\0结尾的字符数组。它是C的遗留物,因为这样的编译器会假设,即使您没有告诉它,否则字符数组也可能是这样的字符串。
  3. C ++字符串(std::string)是存储字符串的模板类。无需担心它在内部如何进行。尽管前两种功能具有互操作性,但这是完全不同的。

现在,让我们弄清楚编译器如何看待您的代码:

char compName[6];

这将创建一个具有足够空间的字符数组,以存储6个符号。您可以在其中编写C样式字符串,只要它们不超过5个符号即可,因为您还需要在末尾写入'\0'。由于在C ++中,C样式数组是不安全的,因此它们将允许您向其中写入更多字符,但是您无法预先预测将这些多余的字符写入内存的位置(即使您的程序将继续执行)。您还可以潜在地从数组中读取更多的字符...但是,您甚至不能问这个数据的来源,除非您只是在玩弄编译器。永远不要在您的代码中这样做。

statement.copy(compName, 6, 18);

此行写6个字符。它不会使它成为C样式的字符串,它只是一个数组中的6个字符。

std::cout<<compName;

您正试图将未提供给编译器的C样式字符串输出到控制台。因此,一个operator<<会收到一个char [],它假定您知道自己在做什么,并且就像给它C字符串一样工作。它显示一个接一个的字符,直到到达'\0'。什么时候会出现这样的角色?我不知道,因为您从未给过它。但是由于C样式数组不安全,因此尝试读取数组末尾的字符,读取一些内存块并认为它们是您不存在的C样式字符串的延续是没有问题的。

在这里,您很幸运,并且只有一个字节显示为'x',然后又写入了一个字节,其中写入了0,并且输出停止了。如果您在不同的时间,使用不同的编译器或以不同的优化方式运行程序,则可能会显示完全不同的数据。

那你应该怎么做?

您可以尝试以下方法:

#include <iostream>
#include <string>

int main()
{

  std::string statement = "I like to work in Google";
  char compName[7]{};
  statement.copy(compName, 6, 18);

  std::cout<<compName;

  return 0;
}

我改变了什么?我使一个数组能够容纳7个字符(为6个字符的C样式字符串留有足够的空间),并且提供了一个空的初始化列表{},它将用\0个字符填充该数组。这意味着当您用数据替换前六个字符时,最后将有一个终止字符。

另一种方法是:

#include <iostream>
#include <string>

int main()
{

  std::string statement = "I like to work in Google";
  char compName[7];
  auto length = statement.copy(compName, 6, 18);
  compName[length] = '\0';

  std::cout<<compName;

  return 0;
}

这里,我没有初始化数组,但是我使用.copy方法获得了写入其中的数据的长度,然后在正确的位置添加了所需的终止符。

哪种方法最好取决于您的特定应用。

答案 1 :(得分:1)

将指向字符的指针插入流插入运算符时,要求该指针指向以空终止的字符串。

@override Widget build(BuildContext context) { return _SomeInherited( data: this, child: MaterialApp( navigatorKey: navigatorKey, title: 'Some Title', theme: someTheme, home: FrontPage(), ), ); } 不包含空终止符。因此,将其插入(指向元素的指针)插入字符流违反了上述要求。

  

请让我知道我在这里做错了

您违反了上述要求。因此,您的程序的行为是不确定的。

  

我希望有Google,但实际输出是Googlex

这是因为程序的行为是不确定的。

  

如何终止它?

首先,请确保数组中有空终止符:

navigatorKey.currentState.pushXXX

然后,分配空终止符:

compName