Завершить вызов после создания экземпляра 'std::out_of_range' What(): Basic_string::erase: __pos (18446744073709551615)

#include <bits/stdc++.h>
using namespace std;

int main() {
    string a,b; cin >> a;
    b = "WUB";
    int n;
    while(a.find(b)==0){
        a.erase(0,3);
    }
    while(a.find(b)>0){
        n=a.find(b);
        a.replace(n,3," ");
    }
    n=a.size();

    while(a[--n]==' '){
        a.erase(n,1);
    }
    cout<<a;
    return 0;
}

По сути, мне нужно удалить WUB из входной строки, а если он стоит между словами, то заменить его пробелом, но я получаю ошибку, упомянутую в заголовке. Комментируя поочередно разные блоки, я обнаружил, что ошибка во 2-м цикле while.

образец ввода:

WUBWUBABCWUB WUBWEWUBAREWUBWUBTHEWUBCHAMPIONSWUBMYWUBFRIENDWUB

Можете ли вы сказать, в чем проблема и как ее решить?

Это мой первый запрос в StackOverflow, поэтому извините, если я не предоставил важную информацию, которую мне следовало иметь.

Отсюда: while(a.find(b)>0) знаете ли вы, какое значение возвращается, если подстрока не найдена?

sweenish 10.07.2024 18:48

Поиск std::string::npos

Pepijn Kramer 10.07.2024 18:49

Незначительный момент (очень незначительный): формально вывод в поток должен заканчиваться символом новой строки. Итак std::cout << a << '\n';. В реальном мире это не имеет значения; ваша программа будет работать нормально (за исключением того, что некоторые люди удивляются, увидев командную строку в конце строки вывода). Это требование является пережитком времен ориентированного на записи ввода-вывода на древних мэйнфреймах, когда требовалась серьезная гимнастика для упаковки строк текста в серию записей фиксированного размера.

Pete Becker 10.07.2024 20:01

Добро пожаловать в StackOverflow. Если ответ решает вашу проблему, вы можете нажать «✔», чтобы отметить его как принятый ответ. Вы также можете проголосовать за любой полезный ответ (голосование и принятие выполняются отдельно). Смотрите здесь: Что мне делать, если кто-то отвечает на мой вопрос?.

wohlstad 15.07.2024 06:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
95
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

std::string::find возвращает не int, а std::string::size_type, который является беззнаковым типом (для него обычно используется size_t, но это не гарантировано).

Более того, если ему не удается найти подстроку, он возвращает специальное значение npos. Поскольку оно беззнаковое, это значение не может быть ниже 0.

По ссылке на документацию выше:

Возвращаемое значение

Позиция первого символа найденной подстроки или npos, если нет такая подстрока найдена.

Поэтому:

  1. Вам нужно изменить n, чтобы стать std::string::size_type:
    std::string::size_type n;
    
  2. Вам необходимо изменить:
    while (a.find(b) > 0) {  // BTW: didn't you mean `>=` here ?
    
    К:
    while (a.find(b) != std::string::npos) {
    

Тогда вывод для упомянутого вами ввода будет:

ABC   WE ARE  THE CHAMPIONS MY FRIEND

Live demo

Побочные примечания:
(1) Почему мне не следует #include <bits/stdc++.h>?
(2) В чем проблема с «использованием пространства имен std;»?

Технически, string::find() возвращает string::size_type, который обычно, но не гарантированно, будет size_t. Это может быть любой беззнаковый тип, который требуется реализации.

Remy Lebeau 10.07.2024 20:18

@RemyLebeau спасибо, исправлено. Также +1 за ваш ответ, поскольку он дополняет мой.

wohlstad 10.07.2024 20:30
Ответ принят как подходящий

std::string::find() возвращает целочисленный тип без знака. Если запрошенная подстрока не найдена, возвращается std::string::npos:

static const size_type npos = -1;

Это специальное значение, равное максимальному значению, представленному типом size_type. Точное значение зависит от контекста, но обычно оно используется либо как индикатор конца строки функциями, которые ожидают строковый индекс, либо как индикатор ошибки функциями, которые возвращают строковый индекс.

Примечание

Хотя в определении используется -1, size_type — это целочисленный тип без знака, а значение npos — это наибольшее положительное значение, которое оно может содержать, благодаря неявному преобразованию знака в беззнак. Это переносимый способ указать наибольшее значение любого беззнакового типа.

Ваш первый цикл while обрабатывает npos правильно, но только потому, что значение npos не равно 0.

  • Примечание: вам не нужно искать string целиком, чтобы увидеть, начинается ли оно с подстроки. Вместо этого вы можете использовать std::string::compare() (или std::string::starts_with() в C++20 и более поздних версиях).

Ваш второй цикл while вообще не может обработать npos, так как значение npos больше 0, поэтому вы в конечном итоге передаете npos в std::string::replace(), когда больше WUB не найдено, что затем не удается, за исключением std::out_of_range.

  • Кстати, вызов a.find() дважды за итерацию цикла является излишним. Кроме того, find() позволяет указать индекс, с которого начать поиск. Поскольку вы уже знаете индекс, в котором вы заменяете символы, вы можете начать следующий вызов find() с этой позиции вместо того, чтобы каждый раз возвращаться к началу строки.

У вас также есть еще один потенциальный доступ за пределы зоны — в третьем while цикле. Если n равно 0, потому что a пусто перед циклом или становится пустым во время цикла, то вы уменьшите n ниже 0, что приведет к очень большому положительному значению при передаче в std::string::operator[] , вызывая неопределенное поведение (поскольку operator[] не выполняет никакой проверки границ. Вместо этого вы можете использовать std::string::at(), если хотите).

С учетом сказанного, попробуйте вместо этого следующее:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string a, b;
    cin >> a;
    b = "WUB";

    while (a.compare(0, b.size(), b) == 0) {
        a.erase(0, b.size());
    }

    string::size_type n = 0;
    while ((n = a.find(b, n)) != string::npos) {
        a.replace(n, b.size(), " ");
        ++n;
    }

    while ((!a.empty()) && (a.back() == ' ')) {
        a.erase(a.size()-1, 1);
    }

    cout << a;
    return 0;
}

предыдущий ответ развеял мои сомнения, но спасибо за совет по оптимизации, потому что даже после исправления я получаю WA в тесте 4, по какой-то причине я не могу понять, внедрит ли это сразу. спасибо и хорошего дня. Редактирование: около третьего цикла while... тем не менее, он будет работать, потому что там есть хотя бы одно слово, не относящееся к WUB.

Aditya Raj 11.07.2024 10:36

Другие вопросы по теме