2017-01-12 3 views
3

Это была викторина (не градуированная) на Курсере. Вопрос в том, что, возможно, оценивает следующий код? Правильные ответы были 127 и 0 (другие параметры были сбой, -1, 128. Почему следующий код может оцениваться до 0? Я понимаю, почему он будет оценивать до 127. Это так же просто, как байт символов неинициализирован, и поэтому случайным? Можно ли также возможно оценить на любой # между 0 и 127?C длина указателя поворота

int foo(void) { 

    char bar[128]; 

    char *baz = &bar[0]; 

    baz[127] = 0; 

    return strlen(baz); 

} 
+3

** нет ** из ваших возможных возможных ответов - это corect. – tofro

+0

какой курс на coursera? – alinsoar

+0

Безопасность программного обеспечения. Это «квалификационная викторина», которая предназначена для оценки того, можете ли вы завершить курс. –

ответ

5

Ранее этот ответ имел неправильную информацию, этот случай не вызывает undefined behavior.


Отредактированный ответ:

TL; DR Мы не можем иметь окончательный ответ, код содержит индетерминисти- поведение.

Чтобы уточнить, char bar[128]; - это автоматическая локальная переменная и, если она не инициализирована явно, будет содержать неопределенные значения.

Цитирование C11, глава §6.7.9

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

В вашем коде вы присвоили значение только для одного элемента массива в индексе 127. Остальные элементы все еще имеют неопределенное значение.

Попытка передать этот массив (указатель на первый элемент массива, в основном) в strlen(), не вызывает чтение этих значений (в поисках нуль-терминатором) и из-за неопределенных значений, там нет убедитесь, что он найдет нуль-терминатор в любом , в частности.

  • Это может очень хорошо найти нулевой терминатор (значение ASCII 0) в первом же элементе и возвращает 0.
  • Он также не может найти нулевой терминатор (значение ASCII 0) в любом другом массиве элементов до последнего и возврата 127.
  • Он может найти нулевой ограничитель в любом месте массива и вернуть его.

Итак, нет определенного ответа на этот вопрос.


Примечание:(сделать для моего неправильного понимания, чтобы предотвратить читатель от попадания в ту же самую ловушку дальнейшего)

Здесь, чтение неинициализированных значений (т.е. , неопределенные значения) не вызывает неопределенного поведения, как можно подумать.

Один лайнер: адрес берется для объекта.

Подробную информацию по этой теме см. here.

+4

Массив символов будет содержать неопределенные значения между -128 и 127. Чтение их не является UB. Возвращаемое значение будет неопределенным между 0 и 127, так как оно вернет позицию первого встреченного \ 0. Поскольку база [127] = 0, нет UB. – neuro

+0

@neuro (_or upvoters to above comment_) как это так? Я смотрю Приложение J.2 _ «Значение объекта с автоматической продолжительностью хранения используется, когда оно равно неопределенным». Что я упустил? –

+0

Адрес массива полностью определен. поэтому baz отлично справляется, поэтому дать ему strlen не UB. Содержимое бара в неопределенном виде, но это что-то еще ... – neuro

5

поведение кода является неопределенными. Я имею в виду, что ответ может быть что угодно, от 0 до 127 включительно.

strlen будет читать неинициализированную память до, но не включая bar[127], которая будет действуют как условие завершения.

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

(Было бы совершенно иначе, если бы bar имел статическую продолжительность хранения, тогда ответ всегда был бы нулевым).


Большая часть комментарии ниже реагируют на неправильной формулировке этого ответа, что говорилось, что поведение не определено.

+4

Я не уверен, что это не определено. Доступ за пределы буфера невозможен. Он просто считывает неопределенные значения. – StoryTeller

+0

См. Http://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior-in-c – Bathsheba

+0

И принятый ответ дает очень хорошие моменты. Ни один из них не применяется здесь. Насколько мне известно, 'char' не имеет значений ловушек, и буфер не будет храниться в регистре. – StoryTeller

1

Есть две вещи, которые могли бы сделать этот код UB, как указано here. Это переменная с автоматической продолжительностью хранения, которая имеет свой адрес, поэтому первый случай определенно не применяется.

Переменная не позволила провести представление ловушки или, как в определении ловушки представлений C11 6.2.6.1/5 курсив:

Некоторые представления объектов не должны представлять значение объекта тип. Если хранимое значение объекта имеет такое представление и считывается выражением lvalue, которое не имеет типа символа , поведение не определено. Если такое представление получает побочный эффект, который изменяет все или часть объекта посредством выражения именующего , который не имеет типа символов, тем поведения является undefined.50) Таким представлением называется ловушкой представление.

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

+0

Upvoted. Я только что отменил ваш первый комментарий в исправлении моего ответа ;-) – Bathsheba

+1

@ Bathsheba Ну, правда об этом нужно найти довольно глубоко в болоте на языке-адвокате. И C++ отличается. – Lundin

Смежные вопросы