Почему argv [argc] указатель на NULL?

В стандарте C ISO / IEC 9899: 2018 (C18), §5.1.2.2.1 - «Запуск программы», написано:

2 - Если они объявлены, параметры основной функции должны подчиняться следующим ограничениям:

- argv [argc] должен быть нулевым указателем.


Мой вопрос:

  • Почему _1 _ / _ 2_ должен быть / является указателем на NULL?

Это то, что для меня не имеет смысла. argv[] - это массив указателей, указывающих на char. argv - указатель на массив указателей, указывающий на char. Даже если при вызове не заданы флаги, указатель не должен превращаться в указатель на NULL.

Разве char* argv[] массив указателей на char и char **argv не является вложенным указателем на char указатели? Как может вложенный указатель на char (char**) быть указателем на NULL?


Я прочитал ответы на argv [argc] ==?, где в качестве ответов цитируется вышеупомянутая фраза из стандарта. а также спросил @ pmg´s answer, который дал мне ответ:

Независимо от используемых имен, согласно спецификации c char * argv [argc] объявляет массив с именем argv, способный содержать указатели argc на char. При передаче функции массив преобразуется в указатель на ее 1-й элемент (так что указатель на указатель на char [вот почему обычно можно увидеть main (int argc, char ** argv)]), теряющую информацию о размере (char * a [10] имеет 10 элементов; char ** a - указатель --- если указатель указывает на массив, невозможно узнать, сколько элементов имеет базовый массив).

но, к сожалению, несмотря на скромные усилия, я все еще не могу понять, почему указатель на указатель (вложенный указатель) на char (char**) превращается в указатель на NULL.

Ответы на Является ли argv [argc] равным указателю NULL, также не отвечают почему это должен быть указатель на NULL, только это является указателем на NULL при цитировании приведенного выше утверждения стандарта.


Заранее спасибо.


person RobertS supports Monica Cellio    schedule 04.01.2020    source источник
comment
Поскольку argc - это количество элементов в массиве argv, наивысший индекс допустимой записи равен argc-1. То есть последний аргумент - argv[argc-1]. Технически это могло сделать argv[argc] неопределенным. Было выбрано значение NULL. Это дает дополнительные способы перебора списка аргументов (проверка на NULL вместо использования argc в качестве счетчика цикла).   -  person lurker    schedule 04.01.2020
comment
Зачем нужны ссылки на данные / авторов 1970-х годов - иначе мы останемся в догадках.   -  person chux - Reinstate Monica    schedule 04.01.2020
comment
Возможно, это объясняется историческими причинами, но я не знаю, что это такое. Это ограничение позволяет циклам обходить все аргументы командной строки, используя только argv: while (*argv) puts(*argv++);. Возможно, такие петли были широко распространены во времена процесса стандартизации.   -  person Lxer Lx    schedule 04.01.2020
comment
Зачем нужны ссылки на данные / авторов 1970-х годов. Вы уверены, что argv[argc] был реализован как NULL еще в 1970-х? :)   -  person lurker    schedule 04.01.2020
comment
argv[argc] не является указателем на NULL. Это нулевой указатель. Его значение - NULL. Это не указывает на NULL.   -  person Eric Postpischil    schedule 04.01.2020
comment
@EricPostpischil какая разница между нулевым указателем и указателем на NULL?   -  person qwerty_url    schedule 24.06.2021
comment
@qwerty_url: NULL (по сути) значение, которое может иметь указатель. (Я говорю «фактически», потому что есть технические определения этого и «константы нулевого указателя», которые здесь не имеют отношения.) Указатель либо указывает на некоторый объект или функцию, либо является нулевым указателем (в этом случае он не указывает к любому объекту или функции). Если мы рассмотрим некоторый char *x, имеющий определенное значение, то либо x указывает на char, либо это нулевой указатель. Если это нулевой указатель, он ни на что не указывает; это не указывает на NULL.   -  person Eric Postpischil    schedule 24.06.2021
comment
@qwerty_url: если бы у нас был char **p, это указатель на указатель, поэтому он мог бы указывать на какое-то место, где мы сохранили нулевой указатель. Даже в этом случае это будет указатель на нулевой указатель; это не будет указатель на NULL (из-за технического определения NULL как макроса определенной формы).   -  person Eric Postpischil    schedule 24.06.2021


Ответы (4)


Это делается по двум причинам:

  1. Для дополнительной безопасности: если вы попытаетесь получить доступ к элементу за пределами [argc - 1], произойдет сбой, вместо того, чтобы интерпретировать мусор как дополнительный аргумент и сделать с ним что-то плохое, например, обработать его как имя файла и записать в файл.

  2. Для удобства: таким образом вы можете использовать argv, не зная argc.

Как это работает:

На самом деле никакого волшебства нет, вот схема памяти:

char**  |    char*     |  char[]
--------+--------------+---------
argv -> | argv[0] ->   | "arg1"
        | argv[1] ->   | "arg2"
        | argv[2] NULL |
person Mike Nakis    schedule 04.01.2020
comment
Это не отвечает на заданный вопрос. Это отвечает на вопрос, почему argv[argc] равно NULL, но задается вопрос (неверно), почему argv[argc] является указателем на NULL. - person Eric Postpischil; 04.01.2020

От

Обоснование для международных стандартных языков программирования C, редакция 5.10, апрель 2003 г.

5.1.2.2.1 Запуск программы

Указание argc и argv в качестве аргументов для main признает обширную предшествующую практику. argv [argc] должен быть нулевым указателем, чтобы обеспечить избыточную проверку конца списка, также на основе общепринятой практики.


Обновление: как указал Эрик Постпишил, это отвечает на вопрос, почему argv[argc] является нулевым указателем. Конечно, argv[argc] не указатель на NULL, как задано в вопросе (NULL - макрос, определенный как константа нулевого указателя; указатель на NULL смысла нет). Так что вопрос и ответы могут оказаться спорными.

person Lxer Lx    schedule 04.01.2020
comment
@EricPostpischil Достаточно честно. Обновлено. - person Lxer Lx; 04.01.2020

Что имеется в виду под

- argv [argc] должен быть нулевым указателем.

Это индекс argc массива argv является нулевым указателем.

Это

if (argv[argc] == NULL)

всегда будет правдой.

person Some programmer dude    schedule 04.01.2020

ИМО это для удобства while(*argv != NULL) ....

person 0___________    schedule 04.01.2020