反转输入,输出字符串意外为空

kp'*_*kp' 4 c++ string

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1;
  cin>>s1;

  int n=s1.size();
  string s2;
  for(int a=0;a<n;a++)
  {
    s2[a]=s1[n-1-a];        
  }
  cout<<s2;
}
Run Code Online (Sandbox Code Playgroud)

但是我没有得到任何输出,但我可以打印反转字符串的元素.任何人都可以帮忙.

BoB*_*ish 6

string s2; // no size allocated
for(int a=0;a<n;a++)
{
    s2[a]=s1[n-1-a]; // write to somewhere in s2 that doesn't exist yet
Run Code Online (Sandbox Code Playgroud)

您正在写入s2您从未创建过的元素.这是未定义的行为,任何事情都可能发生,包括看似正常工作.在这种情况下,您可能会覆盖内存中的一些随机位置.它可能会崩溃,或者内存可能确实存在,但不会立即破坏任何其他内容.你甚至可以在以后阅读它,但它似乎只能通过纯粹的意外工作.

您可以通过始终使用s2.at(a)访问数据来捕获此问题,因为它将为您进行范围检查.([]不进行范围检查).当然,这是一个成本,有时人们会在他们确定索引不能超出范围的情况下跳过它.这是有争议的.在这种情况下,即使你可能确定你的数学是正确的,它仍然可以帮助捕获这个bug.


您需要预先创建该空间,即创建一个充满正确数量的虚拟值的字符串,或者根据需要为每个元素创建空间push_back.我可能会选择第一个选项:

string s2(s1.size(), '\0'); // fill with the right number of NULs
for(int a=0;a<n;a++)
{
    s2.at(a)=s1.at(n-1-a); // overwrite the NULs
Run Code Online (Sandbox Code Playgroud)

例如,您可能希望选择一个未出现在测试数据中的可打印虚拟字符'#',因为如果您无法正确覆盖某些元素,则在打印出来时它会变得非常明显.例如,如果你试图反转,"abc"但是当你打印出来时,你"cb#"会明白你有一些一个一个错误.


第二个选项有点贵,因为它可能需要在字符串增长时进行多次分配和复制,但是它的外观如下:

string s2; // no space allocated yet
for(int a=0;a<n;a++)
{
    s2.push_back(s1.at(n-1-a)); // create space on demand
Run Code Online (Sandbox Code Playgroud)

我假设你这样做是为了学习练习,但我建议你不要写自己的reverse,因为语言是在库中提供的.

  • 是的,这是未定义的行为.按照标准,它可以做任何事情,包括获得看似正确的输出或使整个系统崩溃.如果你使用`at()`方法,你会得到一个例外. (2认同)