Как используется в стандарте C, «A string - это непрерывная последовательность символов, оканчивающаяся и включающая первый нулевой символ» (C 2018 7.1.1 1). Это не char *
. char *
может указывать на первый символ строки и иногда упоминается в стандарте C как указатель на строку, но это неаккуратная терминология, поскольку char *
обязательно является указателем на символ - нет техническое определение того, что означает указывать на «последовательность», хотя мы можем принять его как означающее указывать на первый элемент последовательности.
Насколько я понимаю, char * argv[] = {"abc", "def"};
инициализирует массив из 2 char
указателей.
Это правильно.
И имя argv
также является указателем, который указывает на первый указатель в массиве argv
.
Это неверно, учитывая определение argv
в вопросе. Определение char * argv[] = {"abc", "def"};
определяет argv
как массив char *
. Это не указатель.
Когда массив используется как операнд sizeof
или унарный &
, он используется как массив. (Кроме того, когда массив инициализируется строковым литералом, строковый литерал используется в качестве массива.) Кроме этих случаев, когда массив используется в выражении, он преобразуется в указатель на свой первый элемент. Это преобразование является автоматическим и настолько распространено, что учащиеся могут ошибочно принять массив или имя массива за указатель, в который он преобразован. Это ошибка Массив не является указателем.
Почему некоторые говорят, что argv
это массив char
строк тогда? (как в языке программирования C от K & R).
Керниган и Ричи не говорят этого ни в одном из выпусков Язык программирования C в любом месте, указанном для argv
в индексе. В первом издании 1978 года на странице 110 говорится, что «второе (argv
) - указатель на массив строк символов, содержащих аргументы, по одному на строку». Во втором издании 1988 года они говорят на странице 114 «второй (argv
, для вектора аргумента) является указателем на массив символьных строк, содержащих аргументы, по одному на строку». В индексе также указана страница 163 для argv
, но есть лишь случайное упоминание там, ссылаясь на argv[0]
для названия программы.
Обратите внимание, что они ссылаются на argv
как указатель, а не как массив. Это связано с тем, что параметр argv
для main
является указателем. Хотя он может быть объявлен с int main(int argc, char *argv[])
, параметр, который объявлен как массив, автоматически корректируется в качестве указателя. Таким образом, char *argv[]
в объявлении main
определяет argv
как нечто отличное от заявления, которое вы показали, char * argv[] = {"abc", "def"};
. В объявлении параметра он автоматически настраивается на указатель. В отдельном определении это массив.
Хотя Керниган и Ричи ссылаются на argv
как на указатель, а не на массив, как вы написали, они говорят, что это «указатель на массив». Это также небрежная терминология. Его тип - указатель на указатель на char
, а не указатель на массив char
. Это указатель на массив только в том смысле, что это указатель на первый элемент массива char
.
Если моя гипотеза верна, %s
в printf("%s", argv[1])
вообще не ожидает char string
, скорее, указатель на char string
?
Согласно C 2018 7.21.6.1 8, для спецификатора s
, равного printf
без модификатора или точности, «аргумент должен быть указателем на начальный элемент массива символьного типа. Символы из массива записываются до (но не включая) завершающего нулевого символа ». Таким образом, нужно передать char *
(или signed char *
или unsigned char *
), который указывает на начальный символ строки.