Я написал следующую программу для поиска определенной строки в заданном массиве строк. Я допустил ошибку в функции поиска и написал i-- вместо i ++.
#include <iostream>
#include <string>
using namespace std;
int search(string S[], int pos, string s)
{
for(int i=0; i<pos; i--) {
cout << i << " : " << S[i] << "\n";
if (S[i] == s) {
cout << "Inside Return ->\n";
cout << i << " / " << S[i] << " / " << s << "\n";
return i;
}
}
return -1;
}
int main()
{
string S[] = {"abc", "def", "pqr", "xyz"};
string s = "def";
cout << search(S,2,s) << "\n";
return 0;
}
Логически цикл представляет собой бесконечный цикл и не должен останавливаться, но я заметил, что условие if было истинным для каждого поиска, и функция возвращала -1.
Я распечатал значения и заметил, что значение S [-1] всегда совпадает с третьим аргументом, переданным функции (строка для поиска), из-за чего цикл каждый раз возвращал -1.
Это то, что делает g ++, или это связано со способом выделения памяти для формальных аргументов функции?
Вывод приведенного выше кода -
0 : abc
-1 : def
Inside Return ->
-1 / def / def
PS - я использую g ++ (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0
Изменить. Я понимаю, что g ++ не проверяет границы, но меня заинтриговал тот факт, что значения S [-1] всегда были такими же, как s. Мне было интересно, есть ли какие-нибудь возможные теории для этого
Ага, это дубликат. Но также очень интересно, поскольку вы, вероятно, получаете доступ к стеку вызовов функций ... Пожалуйста, прочтите ответ на связанный вопрос @ AlgirdasPreidžius для объяснения неопределенного поведения :)
Обычный вопрос: а как твои показания нет фигня? В конце концов, это не значения из массива ...
@Quentin Мусор для одного человека - сокровище для другого!
"Я понимаю, что g ++ не проверяет границы" Это не просто g ++. По стандарту C++ ни один компилятор не обязан проверять границы. "но меня заинтриговал тот факт, что значения S [-1] всегда были такими же, как s." Неопределенное поведение не определено. Это может быть так и в этой конкретной версии компилятора, которую вы используете, но она также может форматировать ваш жесткий диск, когда вы обновляете компилятор.
Я понял, спасибо за объяснение
Попробуйте распечатать адрес каждой строки в дополнение к ее значению. Я подозреваю, что s
находится «слева» от S[0]
в памяти.
Это фактически объясняет проблему, адреса S [0] и s - 0x7ffdf6346350 0x7ffdf6346330 соответственно.
Подробнее: en.cppreference.com/w/cpp/language/ub
Индексирование массивов вне пределов - UB! UB может меняться от компилятора к операционной системе, к оборудованию и т. д.
Доступ вне пределов - неопределенное поведение.
Неопределенное поведение чтения - это не «мусор» или «segfault», это буквально что угодно. Чтение может перемещаться во времени и заставлять код в более ранней части программы вести себя иначе. Поведение программы от начала до конца полностью не определено стандартом C++, когда любое неопределенное поведение где-либо происходит.
В этом случае наивная сборка и ABI сообщают вам, что аргументы в «стеке» во время выполнения расположены рядом с такими вещами, как аргументы функции.
Таким образом, наивное переписывание вашего кода в сборку приводит к считыванию отрицательных индексов из аргументов функции.
Но существует множество совершенно безобидных, распространенных и безопасных альтернативных интерпретаций вашей программы как машинного кода, начиная со встроенного кода и заканчивая удалением оттуда, чтобы этого не произошло.
При компиляции без LTO или с превышением границ динамической библиотеки вы можете иметь некоторую небольшую уверенность в том, что опубликованный компилятором ABI будет использован для выполнения вызова; любое предположение в другом месте опасно плохо. И если вы компилируете без LTO и полагаетесь на него, это означает, что вам придется проверять каждую сборку вашего кода с этого момента до вечности, иначе вы рискуете обнаружить ошибку без видимой причины в течение длительного времени.
Возможный дубликат Доступ к массиву за пределами границ не дает ошибок, почему?