Подобные ошибки означают, что во время работы программы была предпринята попытка обращения к памяти, не подготовленной должным образом для этого. Программа с такими ошибками содержит неопределённое поведение. Самыми говорящими из рассмотренных в вопросе ошибок являются те, где сказано «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
, но с оговоркой, что писать туда можно только нулевой символ \0
, и он же вернётся при чтении.
Довольно часто проблема выхода за допустимые границы диапазона случается в циклах, когда условие завершение содержит нестрогое сравнение индекса с размером контейнера: т.е. 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. Показов 3414. Ответов 9 Метки нет (Все метки)
Разбираю пример, который дала препод в примерах к лекциям..Пример по коду Виженера.. Пару раз запустился-результат выводился.Исправила только алфавит на кириллицу,и поставила на некоторые строки коменты.Теперь консолька запускается, начальный этап проходит, но потом результат не выводится, и консолька просто виснет..и выбивает это сообщение про «Debug assertion failed : string subscript out of range»
По пошаговой отладке понимаю что проблема вроде как с загрузкой символов на 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 строке ничего такого, что может родить ассерт не происходит.
0 |
Lambont 93 / 91 / 62 Регистрация: 23.11.2013 Сообщений: 242 |
||||
02.03.2017, 22:48 |
3 |
|||
Особо не вникал в код, но, пройдя отладчиком, у вас после 69 строки
переменная e в любом случае будет содержать очень большое число, которое потом используется как индекс символа в строке, а размер строки явно меньше чем это число, вот и ошибка выхода за границы string.
0 |
nd2 3434 / 2813 / 1249 Регистрация: 29.01.2016 Сообщений: 9,426 |
||||
02.03.2017, 22:54 |
4 |
|||
По пошаговой отладке понимаю Найди точное место в коде, где ошибка вылетает. Судя по ошибке, где-то выходишь за границу string, значит внимание к местам, где к
0 |
1272 / 1029 / 470 Регистрация: 25.12.2016 Сообщений: 3,333 |
|
02.03.2017, 22:55 |
5 |
переменная e в любом случае будет содержать очень большое число От нуля до 35 — вроде не очень большое. А в массиве
0 |
3434 / 2813 / 1249 Регистрация: 29.01.2016 Сообщений: 9,426 |
|
02.03.2017, 22:57 |
6 |
еременная e в любом случае будет содержать очень большое число Тут, как раз, не будет. Здесь от 0 до 35. Добавлено через 55 секунд
А в массиве А как раз 36 элементов. 37.
0 |
93 / 91 / 62 Регистрация: 23.11.2013 Сообщений: 242 |
|
02.03.2017, 23:05 |
7 |
От нуля до 35 — вроде не очень большое. А в массиве А как раз 36 элементов.
Тут, как раз, не будет. Здесь от 0 до 35. Странно, у меня явно переменная е после 69 строки всегда отрицательное значение имеет, чтобы я не вводил, и именно здесь мне бросает исключение выхода за границы
0 |
3434 / 2813 / 1249 Регистрация: 29.01.2016 Сообщений: 9,426 |
|
02.03.2017, 23:13 |
8 |
е после 69 строки всегда отрицательное значение имеет, Отрицательный индекс — это тоже выход за границу.
0 |
likehood 1272 / 1029 / 470 Регистрация: 25.12.2016 Сообщений: 3,333 |
||||
02.03.2017, 23:17 |
9 |
|||
Кажется понял в чём дело. Если строка содержит только символы алфавита, то программа не вылетает. Но если есть хотя бы один пробел или например цифра, то 51 строка не будет выполнена и этот элемент массива не будет инициализирован. Отсюда и все глюки. Кроме того, для корректного ввода русских букв нужно в начале программы добавить строки
Ну и естественно, шифруемый текст должен содержать только большие буквы. —
1 |
Lambont 93 / 91 / 62 Регистрация: 23.11.2013 Сообщений: 242 |
||||
02.03.2017, 23:18 |
10 |
|||
Отрицательный индекс — это тоже выход за границу. Вот вот, я и о том же. Я даже больше скажу, у меня и после 76 строки
в е космические числа, видимо в массивах F и/или G что-то не-то происходит… дойду до дома — подробнее посмотрю тогда
0 |
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.
|
|
КОД:
#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
I’m starting to use strings in place of character arrays and am encountering an error when I change one of my character arrays defined with a size of 5 to a string. The error I get is «Expression: string subscript out of range» upon trying to run the program.
«newWord» was originally a character array, but upon changing it to a string I’m getting this error. I don’t understand what could be causing this, when using the character array the program performs fine.
int main() {
fstream inputFile;
fstream outputFile;
string newWord;
int i, k;
string word;
inputFile.open( "H:\\word.txt" );
outputFile.open( "H:\\newword.txt" );
if( inputFile )
{
while( getline( inputFile, word ) )
{
for( i = 0; i < (word.length()- 3); ++i )
{
for( k = 0; k < 4; ++k )
newWord[k] = word[i+k];
cout << newWord << endl;
outputFile << newWord << endl;
}
}
}
return 0;
}
asked Feb 27, 2013 at 1:47
user1560249user1560249
3432 gold badges5 silver badges14 bronze badges
12
newWord[k]
The size of the newWord
string is zero. The behavior of indexing beyond the end of a std::string
is not defined.
You may need to resize the string, thus:
newWord.resize(5);
answered Feb 27, 2013 at 1:50
RobᵩRobᵩ
164k20 gold badges241 silver badges310 bronze badges
The error is because newWord[k] = word[i+k];
does not allocate a space for the string in newWord. The string length is 0, and it is undefined behaviour to do this. Use .append instead.
From cplusplus.com:
If pos is not greater than the string length, the function never
throws exceptions (no-throw guarantee).Otherwise, it causes undefined
behavior.
In the case of newWord[k], pos is k.
This is easy to avoid by using the append function in the string lib.
From cplusplus.com, again:
string& append (const string& str); //Appends a copy of str.
answered Feb 27, 2013 at 1:51
David DDavid D
1,57111 silver badges12 bronze badges