Visual Studio 中的字符串下标超出范围

String subscript out of range in Visual Studio

我一直在学习 Codecademy 的 C++ 课程,我已经学完了,但我对最后一个任务感到困惑。

我们必须创建一个程序,将所选单词过滤为 'swear words' 并用所选字符替换它们。

我把代码写在了Visual Studio里面可以看到下面 main.cpp

#include <iostream>
#include <string>

#include "functions.h"


int main()
{
    std::string word = "broccoli";
    std::string sentence = "I sometimes eat broccoli.";
    bleep(word, sentence);

    for (int i = 0; i < sentence.size(); i++) {
        std::cout << sentence[i];
    }

    std::cout << "\n";
}

functions.cpp

#include <iostream>
#include <string>
#include "functions.h"

void asterisk(std::string word, std::string &text, int i) {
    for (int k = 0; k < word.size(); k++) {
        text[i + k] = '*';
    }

}

void bleep(std::string word, std::string &text) {
    for (int i = 0; i < text.size(); i++) {
        int match = 0;
        for (int j = 0; j < word.size(); j++) {
            if (text[i + j] == word[j]) {
                match++;
            }       
            
        }
        if (match == word.size()) {
            asterisk(word, text, i);
        }
    }
}


functions.h

#pragma once

void bleep(std::string word, std::string &text);
void asterisk(std::string word, std::string &text, int i);

现在,当我 运行 Visual Studio 中的这段代码时,我得到一个与字符串下标超出范围有关的断言。但是使用相同的代码,它可以在浏览器代码编辑器中的 Codecademys 中运行。 我一辈子都弄不明白为什么它不会 运行 在 VS 中。

如果您 运行 您的程序处于调试模式(通过按 F5),调试器将在问题所在的位置停止您的程序。然后您可以检查变量的值,例如 ij.

当你在做文本[i + j]时,当i已经接近句子的结尾时(比如在西兰花后面的.上),[i+j]会超出句子的结尾句子.
当你在 vs 中处于调试模式时,它会检查下标的范围。也许代码学院没有。
您应该添加一个检查以确保 i 还没有超过单词不能放入剩余 space 的点。您可以在此时结束外循环。

这是内循环

    for (int j = 0; j < word.size(); j++) {
        if (text[i + j] == word[j]) {
            match++;
        }       
        
    }

没有考虑到字符串尾部 text 可以比 word.size() 的值小很多。所以这个 for 循环会在字符串文本之外引发访问内存。

为避免这种情况,至少按以下方式重写外循环

if ( not ( text.size() < word.size() ) )
{
    for ( size_t i = 0, n = text.size() - word.size() + 1; i < n; i++) {
        //...
}

更有效和更安全的方法是使用 class std::string 的方法 find 而不是循环。

这是一个演示程序。

#include <iostream>
#include <string>

std::string & bleep( std::string &text, const std::string &word, char c )
{
    if ( auto n = word.size() )
    {
        for ( std::string::size_type pos = 0; 
              ( pos = text.find( word, pos ) ) != std::string::npos; 
              pos += n )
        {
            text.replace( pos, n, n, c );
        }
    }
    
    return text;
}

int main() 
{
    std::string word = "broccoli";
    std::string sentence = "I sometimes eat broccoli.";
    
    std::cout << sentence << '\n';
    std::cout << bleep( sentence, word, '*' ) << '\n';
    
    return 0;
}

程序输出为

I sometimes eat broccoli.
I sometimes eat ********.