Ответ C наиболее близок к правильности. Линия
free( *ppInt2 );
определенно неверно. Ошибка не может быть обнаружена компилятором. Но это вполне может вызвать ошибку во время выполнения. (Но это не гарантированно приведет к ошибке во время выполнения. Подробнее об этом ниже.)
Правило для malloc
и free
довольно простое: каждый указатель, который вы вручаете free
, должен быть точно таким, как вы получили от предыдущего вызова malloc
(или calloc
, или realloc
). В коде malloc
и free
требует pInt
и ppInt1
правильно следовать этому правилу. Но для ppInt2
указатель, возвращаемый malloc
, присваивается ppInt2
, а указатель, передаваемый free
, равен *ppInt2
, значение, на которое указывает ppInt2
. Но так как *ppInt2
- то есть значение, на которое указывает ppInt2
, - никоим образом не инициализировано, это мусорное значение, при котором free
может привести к сбою. Конечный результат более или менее точно такой, как если бы вы сказали
int main()
{
int *p;
free(p); /* WRONG */
}
Но, опять же, сбой не гарантирован. Поэтому более правильный ответ будет сформулирован как
C '- free(*ppInt2)
неверно. Вероятно, это даст ошибку во время выполнения.
Боюсь, что тот, кто говорит, что ответ D верен, может не знать, о чем он говорит. Я бы предложил не продолжать эту викторину - кто знает, сколько других неверных или вводящих в заблуждение ответов она содержит?
Всегда трудно понять неопределенное поведение, потому что неопределенное поведение означает, что может произойти все, что угодно , включая ничего. Когда кто-то говорит: «Я слышал, что выполнение X было неопределенным, но я попробовал это, и оно работало нормально», это все равно, что сказать: «Я слышал, что бегать по оживленной улице опасно, но я пытался, и все работало нормально. "
Еще одна вещь, связанная с неопределенным поведением, заключается в том, что Вы должны тщательно обдумать это и понять это . По определению, ни один инструмент языкового перевода - ни компилятор C, ни другой инструмент - гарантированно не предупредит вас об этом. Вы должны знать, что не определено и что следует избегать. Вы не можете сказать: «Ну, моя программа компилируется без ошибок и предупреждений, и, похоже, она работает, поэтому она должна быть правильной». Другими словами, вы не можете пытаться навязать «правильное или неправильное» определение на машине - вы должны владеть этим различием.
Но, возможно, вы знали все это. Возможно, реальный вопрос заключается в следующем: «Если ответ C верен, как программа , а не может завершиться с ошибкой во время выполнения, на самом деле, как она может многократно не работать?» На этот вопрос есть два ответа:
Как уже упоминалось, неопределенное поведение означает все, что может произойти, в том числе ничего (т.е. без ошибок), в том числе ничего при нескольких последовательных запусках.
Во многих системах первый раз malloc
дает вам указатель на какую-то совершенно новую память, это всегда все биты-0 (то есть, более или менее, как если бы вы вызывали calloc
). Это абсолютно
не гарантировано стандартами C - вы должны никогда не зависеть от него - но в этих системах вполне вероятно, что это может быть гарантировано. Кроме того, практически во всех системах значение указателя all-bits-0 является нулевым указателем. Итак, и снова только в этих конкретных системах, и снова только в первый раз malloc
дает вам указатель на совершенно новую память, код ppInt2 = malloc(10 * sizeof(int*))
даст вам 10 нулевых указателей. А поскольку free
определяется как ничего не делать, если вы передаете ему нулевой указатель, в этом конкретном случае free(*ppInt2)
никогда не завершится ошибкой, даже во время выполнения. (Возможно, это именно то, что имел в виду человек, проводящий тест, потому что , если вы делаете эти дополнительные предположения, ответ C, как написано, в основном неверен, а ответ D в основном - я не хочу признавать это - - более или менее точно.)
Возвращаясь к более ранней аналогии, если кто-то делает эти дополнительные предположения и замечает, что код никогда не завершается с ошибкой, и пытается утверждать, что ответ D является правильным, то это все равно что сказать: «Я слышал, что бегать по улице было опасно, но я попробовал это посреди ночи, и это работало нормально. Я даже бегал туда-сюда десять раз. Я никогда не попадал под машину, даже ни разу ». И, к сожалению, есть программисты, которые следуют схожей логике и пишут программы, которые делают программирование на С эквивалентным работе через дорогу в любое время. И эти программисты потом жалуются, как будто это не их вина, когда неизбежно заканчивается их удача и происходит ужасный фатальный сбой.