Передача NULL для параметра массива в C / C

#c #c #arrays #null

#c #c #массивы #null

Вопрос:

 void DoSomeThing(CHAR parm[])
{

}

int main()
{
    DoSomeThing(NULL);
}
  

Разрешена ли передача NULL для параметра массива в C / C ?

Комментарии:

1. @VladLazarenko: Я думаю, вы пропустили различие между «возможным» и «разрешенным»

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

3. @reader: Нет, именно поэтому у нас есть спецификации . То, что он компилируется, не означает, что это разрешено.

4. @JohnDibling — И только потому, что это разрешено, не означает, что оно компилируется.

5. @JohnDibling Я думаю, что компиляторы разрешают или отклоняют вещи, спецификации говорят, как все должно быть. Вы не можете скомпилировать программу со спецификацией. Если бы вопрос был в том, является ли допустимым использование, мы бы обязательно посмотрели на спецификацию. Посмотрите на этот пост: списки. whatwg.org/pipermail/whatwg-whatwg.org/2009-June/… Разработчик спецификации обновил спецификацию, потому что, хотя все должно быть в соответствии со спецификациями, но в реальном мире это не так.

Ответ №1:

Чего вы не можете сделать, так это передать массив по значению. Сигнатура функции

 void f( char array[] );
  

преобразуется в:

 void f( char *array );
  

и вы всегда можете передать NULL в качестве аргумента функции, принимающей указатель.

Однако вы можете передать массив по ссылке в C , и в этом случае вы не сможете передать нулевой указатель (или любой другой указатель):

 void g( char (amp;array)[ 10 ] );
  

Обратите внимание, что размер массива является частью типа и, следовательно, частью подписи, что означает, что g будут приниматься только выражения типа lvalue типа array из 10 символов

Ответ №2:

Короткий ответ: да, вы можете передать NULL в этом экземпляре (по крайней мере, для C, и я думаю, что то же самое верно и для C ).

Для этого есть две причины. Во-первых, в контексте объявления параметра функции объявления T a[] и T a[N] являются синонимами T *a ; IOW , несмотря на обозначение массива, a объявляется как указатель на T , а не как массив T . Из стандарта языка Си:

6.7.5.3 Деклараторы функций (включая прототипы)

7 Объявление параметра как ‘массива типа’ должно быть скорректировано на ‘квалифицированный указатель на тип’, где квалификаторы типа (если таковые имеются) являются теми, которые указаны в [ и ] производной типа массива. Если ключевое static слово также появляется в [ и ] производной типа массива, то для каждого вызова функции значение соответствующего фактического аргумента должно предоставлять доступ к первому элементу массива, содержащего по меньшей мере столько элементов, сколько указано в выражении size .

Вторая причина заключается в том, что когда выражение типа array появляется в большинстве контекстов (например, при вызове функции), тип этого выражения неявно преобразуется («распадается») в тип указателя, поэтому фактически функции передается значение указателя, а не массив:

6.3.2.1 Значения Lvalues, массивы и обозначения функций

3 За исключением случаев, когда это операнд sizeof оператора или унарного amp; оператора или строковый литерал, используемый для инициализации массива, выражение, имеющее тип ‘массив типа’, преобразуется в выражение с типом ‘указатель на тип’, который указывает на начальный элемент объекта массива ине является значением lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

Ответ №3:

Во-первых, то, что вы передаете функции, является указателем, а не массивом. Обозначение массива, используемое для parm параметра, является просто синтаксическим сахаром для CHAR *parm .

Так что да, вы можете передать NULL указатель.

Ответ №4:

Единственной проблемой было бы, если бы doSomething был перегружен, и в этом случае компилятор мог бы не различить, какую функцию вызывать. Но приведение к соответствующему типу теоретически исправило бы это.