从第一性原理反转字符串 - 有什么问题?

Reversing a string from first principles - what's wrong?

提问人:Alex 提问时间:3/20/2019 最后编辑:Cody Gray - on strikeAlex 更新时间:3/21/2019 访问量:97

问:

我正在学习如何从 C++ 中的第一性原理反转字符串(即向后写)。我设计了以下代码,旨在从用户那里获取字符串,将其反转并打印出来。但是,它无法编译 - Visual Studio 给了我一个错误“字符串子集超出范围”。怎么了?

using namespace std;

int main()
{
    string example;

    getline(cin, example);

    int i = 0;

    while (example[i] != '\0') 
    {
        i++;
    }

    int n=0;
    string reverse;

    while (n < i)
    {
        reverse[n] = example[i - n - 1];
        n++;
    }

    cout << reverse << endl;

    return 0;
}

我的目标是 C++17。

C++ 字符串 反转

评论

2赞 NathanOliver 3/20/2019
听起来您可能需要学习如何使用调试器来单步执行代码。使用一个好的调试器,您可以逐行执行程序,并查看它与预期偏离的地方。如果您要进行任何编程,这是必不可少的工具。延伸阅读:小程序调试方法调试指南
1赞 Slava 3/20/2019
我几乎不怀疑 VS 会在编译时验证字符串索引,请准确区分 - 您是否收到编译或运行时错误?
0赞 Alex 3/20/2019
我认为这不适用于我的情况,因为我的两个字符串的名称不同。您可能正在考虑将反转的字符串与原始字符串同名的实例,对吗?@Bathsheba
0赞 Alex 3/20/2019
我收到运行时错误@Slava
1赞 t.niese 3/20/2019
您不会调整到示例的大小,因此任何大小都会超出范围。你为什么不使用?reversenpush_back

答:

2赞 Aykhan Hagverdili 3/20/2019 #1

reverse[n]导致字符串超出索引问题。您刚刚创建了字符串,其大小为零。以下是修复方法:

#include <string>
#include <iostream>

using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::getline;

int main()
{
    string example;
    getline(cin, example);
    int i = 0;
    while (example[i] != '\0') 
    {
        i++;
    }

    int n=0;
    string reverse(example.size(), 0);

    while (n < i)
    {
        reverse[n] = example[i - n - 1];
        n++;
    }

    cout << reverse << endl;

    return 0;
}

但是,此代码仍然存在很多错误。例如,存储字符串的大小是一个坏主意。请改用。并且已经给了你尺寸,无需数。另外,请考虑在此处使用 for 循环:intstd::string::size_typestd::string::size

#include <string>
#include <iostream>

using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::getline;

int main()
{
    string example;
    getline(cin, example);
    string reverse(example.size(), 0);
    for (string::size_type n = 0; n != example.size(); ++n)
    {
        reverse[n] = example[example.size() - n - 1];
    }

    cout << reverse << endl;

    return 0;
}

话虽如此,以下是我的实现方式:

#include <string>
#include <iostream>

using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::getline;

int main()
{
  auto example = string();
  getline(cin, example);
  auto reverse = string(example.crbegin(), example.crend());

  cout << reverse << endl;

  return 0;
}

如果您尚未熟悉反向迭代器,请确保熟悉它们。

评论

0赞 Alex 3/20/2019
谢谢。为什么将字符串的长度存储为整数是个坏主意?@Ayxan
1赞 t.niese 3/20/2019
size_t还具有最大值限制。重要的部分是 的最大值 could 不同于 (理论上 can 的最大值也大于 的 ),并且是无符号的并且是有符号的。您应该使用代替 .虽然这是确实大多数实现之一,但它是 - afaik - 不能保证是 .所以合适的类型是严格来说。intsize_tintsize_tsize_tintnumeric_limitsINT_MAXstd::string::size_typesize_tsize_tnstd::string::size_type
1赞 Aykhan Hagverdili 3/20/2019
size_t确实有一个最大值,但保证它足够大以表示字符串的大小。而且由于 A 的大小不能用 std::size_t 表示的类型格式不正确,因此使用代替或任何其他类型总是可以的,不是吗?std::size_tstd::string::size_typesize_type
1赞 t.niese 3/21/2019
因此,对于大多数 std 容器,您可以假设它在常规 32/64 位系统上使用是有效的。您应该始终记住,这不一定是真的。std::size_t
1赞 Aykhan Hagverdili 3/21/2019
std::vector<bool>是一个特例,你在这方面是对的。谢谢你的指出。我将编辑答案并切换,以获得最大的通用性和可移植性。size_tsize_type
0赞 Yash Mishra 3/20/2019 #2

您的问题:reverse[n] = example[i - n - 1];

由于您使用字符串作为数据类型,但使用的是字符数组语法;

将其更改为:

`reverse += example[i - n - 1];

完整的参考代码:'

#include <iostream>

using namespace std;

int main()
{

    string example;

    getline(cin, example);

    int i = 0;

    while (example[i] != '\0') 
    {
        i++;
    }

    int n=0;
    string reverse;

    //cout << i << endl;

    while (n < i)
    {
        reverse += example[i - n - 1];
        n++;
    }

    cout << reverse << endl;

    return 0;
}