проверка на nullptr 100% защищает от ошибки в сегменте памяти? - PullRequest
3 голосов
/ 07 января 2020

Допустим, я перебираю массив, но go за пределами этого массива, потому что мой l oop глуп.
Если объект в памяти находится сразу после этого массива того же типа, что и этот массив, Может ли
проверка array[invalid_index] == nullptr
защитить меня?

Как правильно проверить, является ли индекс (размер неизвестен) действительным для массива C?

Ответы [ 4 ]

9 голосов
/ 07 января 2020

Невозможно определить размер массива по указателю на его первый элемент. Вы должны сообщить размер как-то.

Распространенными стратегиями являются сохранение массива в виде массива и передача размера через систему типов, предоставление размера в качестве отдельного значения или использование значения часового типа (например, нулевого символа в строке c). В c ++ рекомендуется использовать std::vector или std::array, которые всегда знают свой собственный размер.

Попытка разыменования элемента массива за пределами этого массива является неопределенным поведением. Как только вы попытаетесь прочитать array[invalid_index], у вас будет неопределенное поведение. Поэтому невозможно использовать array[invalid_index] для каких-либо полезных целей, включая проверку границ. nullptr здесь никак не влияет.

7 голосов
/ 07 января 2020

Нет, проверка на nullptr не защищает вас. Совсем. 0%.

Это вы создали этот массив. Правильный способ проверить, является ли индекс действительным, состоит в том, чтобы узнать, какой размер массива вы создали (что вы делаете; помните: это был вы , который создал массив), а затем проверьте, находится ли индекс в пределах диапазона , Более того, напишите код так, чтобы индексы не выходили за пределы диапазона go во-первых, и, следовательно, проверка не требуется, чтобы начинаться с…

, за исключением гипотетического элемента после последнего элемента массив, одна попытка даже просто вычислить (даже не получить доступ, просто вычислить) адрес элемента, который не является частью массива, немедленно вызывает неопределенное поведение [expr.add] / 4 . И, без исключения, попытка получить доступ к элементу, который на самом деле не является элементом массива, всегда вызывает неопределенное поведение, несмотря ни на что. 100%. Встроенный оператор индекса - это просто сокращение для вычисления адреса данного элемента и доступа к объекту по этому адресу [expr.sub] / 1 . Таким образом, вы даже не дойдете до точки, в которой вы сможете сравнить прочитанное вами значение с nullptr до того, как вы введете землю с неопределенным поведением ...

2 голосов
/ 07 января 2020

Такая проверка не защитит вас.

Многие C API имеют своего рода контракт с программистами, использующими его, что они будут подчиняться соглашениям, указанным API, без какого-либо строгого механическое обеспечение выполнения этого контракта. Например, строковые API на основе C в основном утверждают, что строки всегда заканчиваются нулем, и что правильное использование любого строкового API на основе C предполагает и зависит от строки, заканчивающейся нулем.

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

char string[13] = "Hello World!"; //string[12] contains the value 0

/*...*/
char const* str = string;

do {
    char curr = *str++;
    if(curr == 0) 
        break;
    /*...*/
} while(true);

В большинстве строковых API на основе C этот код считается "безопасным" в контексте указанного c этого контракт гарантирован.

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

char string[12] = "Hello World"; 
string[11] = '!';

немедленно сломает строку l oop, которую я только что показал. Вот почему программисты на C ++ считают (справедливо, на мой взгляд), что такого рода проверки небезопасны: они просто не могут быть гарантированно правильными, если вы не доверяете своим пользователям (программистам) соблюдать ваши правила.

Вот почему мы предпочитаю API, которые не могут неожиданно сломаться, как это.

std::string string = "Hello World!";
for(char curr : string) { //for-each loop, intrinsically safe unless the iterators are improperly implemented
    /*Do whatever with curr*/
}

Итак, вернемся к исходному вопросу: безопасный способ решить эту проблему - использовать объекты, специально предназначенные для нашей безопасности. Используйте std::array<T, N> вместо T arr[N], что позволит использовать циклы for-each. Если вам нужно использовать итерации на основе индекса, предпочтите at(index) вместо [index] в любой ситуации, когда производительность не на высоте. Это методы, которые сделают ваш код безопасным, вместо того, чтобы просто полагать, что ваши данные правильно настроены.

0 голосов
/ 07 января 2020

выполняет проверку на nullptr 100% защиты от segfault

Нет. Есть много способов получить доступ к недопустимой памяти, и нулевой указатель - это только один из них.

Что вы должны сделать, это избежать всего неопределенного поведения.

Как правильно проверить допустим ли индекс (размер неизвестен) для массива C?

Чтобы проверить это, нужно сравнить его с размером массива:

if (index < size)
    // valid

Если вы не знаете размер массива, вы не можете проверить его на достоверность. Другими типичными источниками ошибок являются ошибочно принятый размер или время жизни массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...