Ошибка string subscript out of range

Подобные ошибки означают, что во время работы программы была предпринята попытка обращения к памяти, не подготовленной должным образом для этого. Программа с такими ошибками содержит неопределённое поведение. Самыми говорящими из рассмотренных в вопросе ошибок являются те, где сказано «subscript out of range». Дословно это переводится как «Индексация вне диапазона». Понятность их обеспечивается в первую очередь тем, что программа собрана в отладочном (Debug) режиме и соответствующий код индексации operator[] того или иного контейнера (std::array, std::string, std::vector) непосредственно содержит проверку значения индекса, передаваемого в оператор индексации. Например, так выглядит код в msvc 2019 для std::array:

    _NODISCARD _CONSTEXPR17 reference operator[](_In_range_(0, _Size - 1) size_type _Pos) noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
        _STL_VERIFY(_Pos < _Size, "array subscript out of range");
#endif // _CONTAINER_DEBUG_LEVEL > 0

        return _Elems[_Pos];
    }

Другие сообщения не так очевидны, потому что возникают при работе приложений, собранных без отладочной информации и/или оптимизированных так, что подробное отладочное сообщение не содержится/не связано с выполняемый кодом, но причины их возникновения часто те же самые.

Решение проблемы прямо вытекает из текста отладочных сообщений — индекс, по которому идёт обращение к элементу контейнера, должен быть в допустимом диапазоне. Т.е. если контейнер имеет размер N, допустимыми индексами будут являться 0...N-1. Исключением из этого правила является std::string, где допускается так же использовать индекс N, но с оговоркой, что писать туда можно только нулевой символ , и он же вернётся при чтении.

Довольно часто проблема выхода за допустимые границы диапазона случается в циклах, когда условие завершение содержит нестрогое сравнение индекса с размером контейнера: т.е. i <= size вместо i < size. В подобных случаях итерации по элементам, следует по возможности пользоваться диапазонной версией цикла for, которая не допускает выхода за пределы контейнера, если размер контейнера остаётся постоянным в процессе итерирования.

std::vector<int> v = {1, 2, 3};
for(int i = 0; i <= v.size(); ++i) // ошибка. <= вместо <
   v[i] = 42;                      // проблема на последней итерации

for(auto& e : v)                   // диапазонный for 
   e = 42;                         // e всегда принадлежит вектору

Иногда цикл кажется правильным, но вместо v.size() по незнанию указывают v.max_size(), который говорит вообще о потенциально возможном размере контейнера для данной архитектуры, а не о текущем размере. Понятно, что в этом случае можно выйти далеко за пределы разрешённых величин.

При этом даже в циклах, где правильно заданы границы индексов можно использовать не тот элемент, т.к. конкретный индекс вычисляется как функция от индекса из цикла, например:

for(int i = 0; i < v.size(); ++i) {
   v[f(i)] = ...   // f(i) может возвращать другой диапазон
   v[i - 1] = ...  // использование "предыдущего" индекса. Ошибка для i == 0.
}

Другой возможный случай — когда возникает путаница между ассоциативными контейнерами (где operator[] приводит к созданию/добавлению элемента в контейнер, если его ещё не было) и последовательными контейнерами. Например:

std::map<int, int> m;
m[0] = 42; // ok, добавляется элемент с ключом 0 и ему присваивается значение 42

std::vector<int> v;
v[0] = 42; // ошибка, вектор пустой, элемента с индексом 0 не существует

Добавить элемент в вектор можно либо при инициализации std::vector<int> v = {42};, либо позднее, например, через v.push_back(42).

Иногда ошибка может возникать, когда вместо std::vector::resize был вызван std::vector::reserve. Т.е. память выделена и доступ идёт только к элементам внутри выделенной памяти, но логически размер вектора не был изменён (элементы вектора фактически не проинициализированы). При Release сборке в этом случае может вовсе не возникнуть ошибки доступа (access violation), но такая программа не будет считаться валидной.

Чтобы обеспечить дополнительную проверку диапазона используемых индексов как в отладочном, так и в релизном режимах сборки вместо operator[] можно воспользоваться функцией at(), которая выбросит исключение std::out_of_range при использовании индекса вне разрешённого диапазона. В некоторых случаях сложного вычисления индекса это может быть оправдано, но внесёт дополнительный оверхед.

Маринчик

0 / 0 / 3

Регистрация: 12.10.2012

Сообщений: 150

1

02.03.2017, 22:24. Показов 3121. Ответов 9

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Разбираю пример, который дала препод в примерах к лекциям..Пример по коду Виженера.. Пару раз запустился-результат выводился.Исправила только алфавит на кириллицу,и поставила на некоторые строки коменты.Теперь консолька запускается, начальный этап проходит, но потом результат не выводится, и консолька просто виснет..и выбивает это сообщение про «Debug assertion failed : string subscript out of range»

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 11.cpp: определяет точку входа для консольного приложения.
//
#include "stdafx.h"
#include <string>
#include <iostream>
#include <conio.h>
 
using namespace std;
 
int main()
{
    string TEXT, KEY, D = "";
    string A = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ-_,."; //наш алфавит
    setlocale(LC_ALL, "Rus");
    cout << "Введите предложение: ";
    cin >> TEXT;
    KEY =  "МАРИНА";
    int *F = new int[TEXT.size()];
    int *G = new int[TEXT.size()];
    int key = KEY.size(); //делаем замену переменных для удобства
    int text = TEXT.size();
    
    if (text >= key)//Первое условие. Если длина вводимого слова больше, либо равна длине ключа
    {
        for (int i = 0; i < (text / key); i++)
        {
            D = D + KEY; //Записываем целое количество ключа. Растягивая ключ по длине слова.
        }
        for (int j = 0; j < (text%key); j++)
        {
            D = D + KEY[j];
        }
    }
    else  //Иначе если ключ длиннее слова, укорачиваем ключ до длины слова.
    {
        for (int s = 0; s < text; s++)
        {
            D = D + TEXT[s];
        }
    }
 
//cout<<"Распишем ключ под текст: ";
//cout << D << endl;
 
    for (int k = 0; k < text; k++)//Здесь мы уже начинаем шифровать.
    {
        for (int n = 0; n < 36; n++)
        {
            if (TEXT[k] == A[n])// Смысл заключается втом, что мы ищем номер буквы во вводимом ключе и номере, 
            {
                F[k] = n;
            }
 
            if (D[k] == A[n])
            {
                G[k] = n;
            } ///И после чего записываем их в массив
 
        }
    }
 
    int e = 0; //Для суммы номеров символов. Чтобы при достижении 36 буквы или символа, программа шла по кругу, начиная с первого номера
bool shifr;
cout<<"для шифрования введите 1, для расшифровки нажмите 0: ";
cin>>shifr;
if (shifr==1){
    for (int u = 0; u < text; u++)
    {
        e = ((F[u] + G[u]) % 36);
        TEXT[u] = A[e];
    }
 }
else
    for (int u = 0; u < text; u++)
    {
        e = ((F[u] - G[u]));
        if (e<0)
            e+=36;
        TEXT[u] = A[e];
    }
    cout << "Зашифрованное слово: " << TEXT << endl;
 
    
    _getch();
    return 0;
 
}

По пошаговой отладке понимаю что проблема вроде как с загрузкой символов на 81 строчке.. А как сделать чтоб работало нормально-правильно?



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

02.03.2017, 22:24

9

284 / 232 / 114

Регистрация: 07.09.2016

Сообщений: 584

02.03.2017, 22:34

2

в вашей 81 строке ничего такого, что может родить ассерт не происходит.
поведение вашей программы зависит от того, что вы там вводите. я вбил что-то от балды и ассертов не было.
в таких случаях вводные данные надо писать тут, а еще лушче тупо хардкодить, вместо того, чтобы запрашивать
у пользователя их ввод. сильно экономит время всем. после отладки хардкод можно убирать.
ну и до кучи почитайте третий пост из темы:
Как пользоваться отладчиком (в Visual Studio)



0



Lambont

93 / 91 / 62

Регистрация: 23.11.2013

Сообщений: 242

02.03.2017, 22:48

3

Особо не вникал в код, но, пройдя отладчиком, у вас после 69 строки

C++
1
        e = ((F[u] + G[u]) % 36);

переменная e в любом случае будет содержать очень большое число, которое потом используется как индекс символа в строке, а размер строки явно меньше чем это число, вот и ошибка выхода за границы string.



0



nd2

3434 / 2813 / 1249

Регистрация: 29.01.2016

Сообщений: 9,426

02.03.2017, 22:54

4

Цитата
Сообщение от Маринчик
Посмотреть сообщение

По пошаговой отладке понимаю

Найди точное место в коде, где ошибка вылетает. Судя по ошибке, где-то выходишь за границу string, значит внимание к местам, где к string A по индексу обращаешься. Например:

C++
1
2
3
4
        e = ((F[u] - G[u]));
        if (e<0)
            e+=36;
        TEXT[u] = A[e];



0



1272 / 1029 / 470

Регистрация: 25.12.2016

Сообщений: 3,333

02.03.2017, 22:55

5

Цитата
Сообщение от Lambont
Посмотреть сообщение

переменная e в любом случае будет содержать очень большое число

От нуля до 35 — вроде не очень большое. А в массиве А как раз 36 элементов.
Точнее, 37 элементов, так что делить по модулю нужно на 37, если я правильно понял алгоритм.



0



3434 / 2813 / 1249

Регистрация: 29.01.2016

Сообщений: 9,426

02.03.2017, 22:57

6

Цитата
Сообщение от Lambont
Посмотреть сообщение

еременная e в любом случае будет содержать очень большое число

Тут, как раз, не будет. Здесь от 0 до 35.

Добавлено через 55 секунд

Цитата
Сообщение от likehood
Посмотреть сообщение

А в массиве А как раз 36 элементов.

37.



0



93 / 91 / 62

Регистрация: 23.11.2013

Сообщений: 242

02.03.2017, 23:05

7

Цитата
Сообщение от likehood
Посмотреть сообщение

От нуля до 35 — вроде не очень большое. А в массиве А как раз 36 элементов.

Цитата
Сообщение от nd2
Посмотреть сообщение

Тут, как раз, не будет. Здесь от 0 до 35.

Странно, у меня явно переменная е после 69 строки всегда отрицательное значение имеет, чтобы я не вводил, и именно здесь мне бросает исключение выхода за границы



0



3434 / 2813 / 1249

Регистрация: 29.01.2016

Сообщений: 9,426

02.03.2017, 23:13

8

Цитата
Сообщение от Lambont
Посмотреть сообщение

е после 69 строки всегда отрицательное значение имеет,

Отрицательный индекс — это тоже выход за границу.



0



likehood

1272 / 1029 / 470

Регистрация: 25.12.2016

Сообщений: 3,333

02.03.2017, 23:17

9

Кажется понял в чём дело. Если строка содержит только символы алфавита, то программа не вылетает. Но если есть хотя бы один пробел или например цифра, то 51 строка не будет выполнена и этот элемент массива не будет инициализирован. Отсюда и все глюки.

Кроме того, для корректного ввода русских букв нужно в начале программы добавить строки

C++
1
2
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

Ну и естественно, шифруемый текст должен содержать только большие буквы.


Я бы вообще сначала отладил программу для английского алфавита, а потом при желании добавил поддержку русского.



1



Lambont

93 / 91 / 62

Регистрация: 23.11.2013

Сообщений: 242

02.03.2017, 23:18

10

Цитата
Сообщение от nd2
Посмотреть сообщение

Отрицательный индекс — это тоже выход за границу.

Вот вот, я и о том же. Я даже больше скажу, у меня и после 76 строки

C++
1
        e = ((F[u] - G[u]));

в е космические числа, видимо в массивах F и/или G что-то не-то происходит… дойду до дома — подробнее посмотрю тогда



0



КОД:

#include <iostream>
#include <string>

using namespace std;

string codeNormalization(string code) {
	string result;
	for (int i = 0; i < code.size(); i++) {
		if (code[i] == 'n') {
			result += "\n";
		}
		else if (code[i] == '"') {
			result += ''';
		}
		else if (code[i] == 't') {
			result += "\t";
		}
		else {
			result += code[i];
		}
	}
	return result = R"("exec(''')" + result + "''')" + R"(")";
}

string myOBF(string codeLine) {
	string result;
	for (int i = 0; i < codeLine.capacity(); i++) {
		int _ord = (int)codeLine[i];
		if (codeLine[i] == codeLine[-1]) {
			result += "chr(" + to_string(_ord) + "))";
		}else if (codeLine[i] == codeLine[0]){
			result += "exec(chr(" + to_string(_ord) + ")+";
		}else {
			result += "chr(" + to_string(_ord) + ")+";
		}
	}
	return result;
}

int main() {
	string code = "print('txt')";
	cout <<myOBF(codeNormalization(code)) << endl;
	system("pause");
}

Ошибка появляется в MessageBox после появления консоли.
Сама ошибка:
string subscript out of range
При дебаге кидает в xstring
Ошибка появилась сразу после написания функции myOBF. <ОШИБКА ГДЕ ТО В НЕЙ>
Ошибка пропадает если из цикла for убрать все if и else if :(

Hello, I am working on a project and I have run into a slight error. I am setting up an array to spit out the ICAO words for a given string. (Ex. Input = «GO» — Output = «Golf Oscar») It compiles cleanly the first time, but after I get the output, I get the error «String Subscript Out of Range». What does this mean and how can I fix it? Thank you very much. I couldn’t find any information online that I could understand, frankly, so I hope you guys can help me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string>
using namespace std;


int main()
{               
	string stringin;
	int index = 0;
	string ICAO[26] = { "Alpha" , "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", 
						"Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", 
						"Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform"
						"Victor", "Whiskey", "X-ray", "Yankee", "Zulu" } ;

	do
	{		
	cout << "Please enter string or press 9 to exit:   " << endl;			
	cout << endl;
	cin >> stringin;
	cout << endl;
	cout << "The phonetic version is:   " << endl;
	cout << endl;
	
	for (int i=0; stringin.size(); i++)	
	{
		string stringout;
		char letter;
		letter = toupper(stringin[i]);
		stringout = ICAO[letter-'A'];
		cout << stringout << " ";

	}

	cin.get();
	cin.get();

	} while (stringin != "9");

	return 0;
}

Compiling does not mean your code is right! :laugh:
Think of the development process as writing an email: compiling successfully means that you wrote the email in the right language — English, rather than German for example — not that the email contained the message you wanted to send.

So now you enter the second stage of development (in reality it’s the fourth or fifth, but you’ll come to the earlier stages later): Testing and Debugging.

Start by looking at what it does do, and how that differs from what you wanted. This is important, because it give you information as to why it’s doing it. For example, if a program is intended to let the user enter a number and it doubles it and prints the answer, then if the input / output was like this:

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16

Then it’s fairly obvious that the problem is with the bit which doubles it — it’s not adding itself to itself, or multiplying it by 2, it’s multiplying it by itself and returning the square of the input.
So with that, you can look at the code and it’s obvious that it’s somewhere here:

int Double(int value)
   {
   return value * value;
   }

Once you have an idea what might be going wrong, start using the debugger to find out why. Put a breakpoint on the first line of the method, and run your app. When it reaches the breakpoint, the debugger will stop, and hand control over to you. You can now run your code line-by-line (called «single stepping») and look at (or even change) variable contents as necessary (heck, you can even change the code and try again if you need to).
Think about what each line in the code should do before you execute it, and compare that to what it actually did when you use the «Step over» button to execute each line in turn. Did it do what you expect? If so, move on to the next line.
If not, why not? How does it differ?
Hopefully, that should help you locate which part of that code has a problem, and what the problem is.
This is a skill, and it’s one which is well worth developing as it helps you in the real world as well as in development. And like all skills, it only improves by use!

Понравилась статья? Поделить с друзьями:
  • Ошибка string index out of range python
  • Ошибка string expected esdlreader cpp 287 в тылу врага
  • Ошибка string does not name a type
  • Ошибка string cannot be converted to string
  • Ошибка street legal racing redline