【问题标题】:C++ Check and modify strings / String subscript out of rangeC++检查和修改字符串/字符串下标超出范围
【发布时间】:2025-12-01 01:30:01
【问题描述】:

我正在尝试制作一个以特定方式修改单词的程序: 它应该首先检查单词的结尾,然后继续修改它们。我不会详细解释它,因为它在英语中没有多大意义。 我写了以下内容:

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
    cout << "Por favor, introduzca los gentilicios separados por la tecla enter, para finalizar, escriba OK" << '\n';
    string name[10];
    string place[10];
    for (int i(0); (i < 10); i++)
    {
        getline(cin, name[i]);
        if (name[i] == "OK")   //Error here
            break;      
    }

    for (int i(0); (i < 10); i++)
    {
        place[i] = name[i];
        if (name[i][name[i].length() - 1] == 'c')
            {
                if (name[i][name[i].length()] == 'a' || (name[i][name[i].length()] == 'o') || (name[i][name[i].length()] == 'u'))
                    place[i][place[i].length() - 1] = 'q';
                    place[i][place[i].length()] = 'u';
                    place[i] = place[i] + "istan";

        }
        else if (name[i][name[i].length()] == 'a' || name[i][name[i].length()] == 'e' || name[i][name[i].length()] == 'i' || name[i][name[i].length()] == 'o' || name[i][name[i].length()] == 'u')
        {
            place[i][place[i].length()] = 'i';
            place[i] = place[i] + "stan";
        }

        if (name[i][name[i].length()] == 's')
            place[i] = place[i] + "tan";
        else {
            place[i] = place[i] + "istan";
        }

        place[i][0] = toupper(place[i][0]);



    }

    for (int i(0); (i < 10); i++)
    {
        cout << place[i] << '\n';
    }

    return 0;
}

现在我收到错误 "String subscript out of range" 。我想知道错误到底在哪里。我知道当我在第 18 行写“OK”时它会提示。

【问题讨论】:

  • 这段代码有很多风格问题,可能是也可能不是问题的一部分。使用 C 数组(以及相关的 sizeof 滥用)、“裸”指针和指针算术而不是其中的 [] 访问。此外,错误消息中的行号或整个错误消息(而不是转述的)会有所帮助。
  • *(p+ (name[i].length()-2))p[name[i].length()-2] 相同,与name[i + name[i].length() - 2] 相同。

标签: c++ arrays string pointers char


【解决方案1】:

条件i &lt;= sizeof(name)sizeof(name)bytes 为单位返回数组的大小,不是其中元素的数量。即使返回元素个数,&lt;= 也是错误的,会导致越界访问(应该是&lt;)。

要遍历数组中的所有元素,可以使用基于范围的 for 循环:

for(auto& n : name)
{
    getline(cin, n);
    if (n == "OK")
        break;      
}

或者用 C 风格的 for 循环以正确的方式来做:

for (int i(0); i < sizeof(name)/sizeof(name[0]; i++)
{
    …
}

【讨论】:

    【解决方案2】:

    这里:

      for (int i(0); (i <= sizeof(name)); i++)
    

    sizeof(name) 是以字节为单位的数组大小,因为它是一个 std::string 数组,实际上是没有意义的。如果你想迭代超过 10 个项目,只需这么说(还要注意小于或等于这里也是错误的):

      for (int i = 0; i < 10; i++)
    

    这里:

       getline(cin, name[i]);
    

    每当您执行输入时,您必须检查输入函数的返回值并处理任何错误:

       if( ! getline(cin, name[i]) ) {
           // handle error somehow
       }
    

    这里:

      string * p;
    

    你确实想要处理指向字符串的指针。如果要访问字符串的内容,可以在字符串上使用 operator[] 或其他字符串成员函数。

    【讨论】:

      【解决方案3】:

      std::strings 不像 cstrings。您可以使用std::string* 获取其中的一部分。当你这样做时

      *(p+ (name[i].length()-2))
      

      您实际上是说将存储在p 中的地址提前name[i].length()-2 数量并访问该字符串。如果您越过 name 数组的末尾,那么这是未定义的行为。如果不是,您仍然有一个std::string,它无法与char 进行比较。如果你想检查字符串是否以"ca" 结尾,那么你可以使用

      if (name[i].substr(name[i].size() - 2) == "ca")
      

      【讨论】:

        【解决方案4】:

        你的最后一个循环正在做一些非常时髦的事情。没必要走那么远。你可以这样做:

        if (name[i][name[i].length - 2] == 'c')
        

        将倒数第二个字符与 c 进行比较。还有一个非常相似的测试,将最后一个与 a 进行比较。


        为了澄清为什么你做的不对,你首先得到p 作为指向当前元素的字符串的指针。然后你做一些指针算术p + (name[i].length - 2),它仍然会产生一个指向字符串的指针。最后,您取消引用它,从而产生一个字符串。这是你无法与 char 相比的。此外,指针指向内存中的某个任意地址,因此取消引用会产生一个字符串,其中包含 very bad 数据。很随意,有人可能会说。如果你试图使用它,你会破坏你的程序

        您似乎在使用该字符串,就像使用类似 C 的字符串 char* 一样。尽管它们代表相同的概念,但两者并不相同。 C++ 字符串通常有一个 size 字段,里面有一个 char* 指针,还有一堆其他的逻辑来使它使用 char-m。

        【讨论】:

        • 感谢您的解释!
        【解决方案5】:

        因为您没有与字符串中的特定字符进行比较,您正在与字符串进行比较

        考虑以下代码:

        *(p + (name[i].length() - 2))
        

        这将评估为一个字符串,因为您正在使用 p (一个字符串*)并将一个字符连接到它。这意味着它仍然是一个字符串(即使它是一个单字符的字符串),因此等式的另一边无法与之相比

        你需要的是这个:

        if (name[i][name[i].length() - 2] == 'c')
        

        由于 name[i] 已经是一个字符串,我们可以使用上面的代码从中获取 char。这确实返回字符,所以它是可比较的。这也允许您摆脱不需要的整个 string* 位。

        【讨论】:

        • 非常感谢!我确实想过这个。但我认为访问数组内部的数组不会像 name[x][y] 这么简单
        【解决方案6】:

        首先(i &lt;= sizeof(name))是错误的,应该是i &lt; sizeof(name) / sizeof(*name)sizeof(array) 返回array 的大小(以字节为单位),您需要除以array 的元素大小才能实际获得数组的最大元素数。如果您觉得这很复杂,请使用std::vector

        vector<string> name(10);  //a vector of size 10
        
        for (size_t i = 0; i < name.size(); i++)  //name.size(), simple
        

        其次,您需要跟踪name 数组中有多少个字符串。或者您需要检查name[i] == "OK" 是否然后中断第二个循环(类似于第一个循环)。 name[i] 后面的"OK" 无效。

        第三,不要使用*(p+ (name[i].length()-2))。如果要name[i]的倒数第二个字符,可以写成name[i][name[i].size()-2]name[i].end()[-2]end(name[i])[-2]

        如果要检查单词是否以“ca”结尾,则可以使用substr

        if (name[i].substr(name[i].size() - 2) == "ca")
        {
            //...
        }
        

        【讨论】: