C++检查和修改字符串/字符串下标超出范围

Posted

技术标签:

【中文标题】C++检查和修改字符串/字符串下标超出范围【英文标题】:C++ Check and modify strings / String subscript out of range 【发布时间】:2017-02-24 13:50:33 【问题描述】:

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

#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] 相同。 【参考方案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")

    //...

【讨论】:

以上是关于C++检查和修改字符串/字符串下标超出范围的主要内容,如果未能解决你的问题,请参考以下文章

问题:“字符串下标超出范围”C++

c++ 断言字符串迭代器偏移超出范围

c++和opencv中的向量下标超出范围错误

我收到“字符串下标超出范围错误”。我不知道为啥

搜索字符串时向量下标超出范围

从字符数组更改为字符串时出现“字符串下标超出范围”错误?