Каков тип аргумента командной строки `argv` в C?
Я читаю раздел от C Primer Plus о аргументе командной строки argv
, и мне трудно понять это предложение.
В нем говорится, что
Программа хранит строки командной строки в памяти и сохраняет адрес каждой строки в массиве указателей. Адрес этого массив сохраняется во втором аргументе. По соглашению, этот указатель на указатели называются argv
, для значений аргументов.
Означает ли это, что строки командной строки хранятся в памяти в виде массива указателей на массив из char
?
Ответы
Ответ 1
Непосредственное цитирование из C11
, глава §5.1.2.2.1/p2, запуск программы (основное внимание)
int main(int argc, char *argv[]) { /* ... */ }
[...] Если значение argc
больше нуля, элементы массива argv[0]
через argv[argc-1]
включительно должен содержать указатели на строки, [...]
и
[...] и строки, на которые указывает массив argv
[...]
Итак, в основном, argv
является указателем на первый элемент массива строк note. Это можно сделать более ясным из альтернативной формы,
int main(int argc, char **argv) { /* ... */ }
Вы можете перефразировать это как указатель на первый элемент массива указателей на первый элемент массивов char
с нулевым завершением, но я бы предпочел придерживаться строк.
Примечание:
Чтобы пояснить использование "указателя на первый элемент массива" в приведенном выше ответе, следуя §6.3.2.1/p3
За исключением случаев, когда это операнд оператора sizeof
, оператор _Alignof
или унарный &
или строковый литерал, используемый для инициализации массива, выражение, которое имеет type '' типа типа преобразуется в выражение с указателем типа '', чтобы набирать такие точки к исходному элементу объекта массива и не является значением lvalue. [...]
Ответ 2
argv
имеет тип char **
. Это не массив. Это указатель на указатель на char
. Аргументы командной строки хранятся в памяти, а адрес каждой ячейки памяти хранится в массиве. Этот массив представляет собой массив указателей на char
. argv
указывает на первый элемент этого массива.
Some
array
+-------+ +------+------+-------------+------+
argv ----------> | | | | | | |
| 0x100 +------> | | | . . . . . . | | Program Name1
0x900 | | | | | | |
| | +------+------+-------------+------+
+-------+ 0x100 0x101
| | +------+------+-------------+------+
| 0x205 | | | | | |
0x904 | +------> | | | . . . . . . | | Arg1
| | . | | | | |
+-------+ +------+------+-------------+------+
| . | . 0x205 0x206
| . |
| . | .
| . |
+-------+ . +------+------+-------------+------+
| | | | | | |
| 0x501 +------> | | | . . . . . . | | Argargc-1
| | | | | | |
+-------+ +------+------+-------------+------+
| | 0x501 0x502
| NULL |
| |
+-------+
0xXXX Represents memory address
<суб > 1. В большинстве случаев argv[0]
представляет имя программы, но если имя программы недоступно в среде хоста, то argv[0][0]
представляет нулевой символ.Суб >
Ответ 3
Эта нить - это крушение поезда. Вот ситуация:
- Существует массив с
argc+1
элементами типа char *
.
-
argv
указывает на первый элемент этого массива.
- Существуют
argc
другие массивы типа char
и различные длины, содержащие строки с нулевым завершающим символом, представляющие аргументы командной строки.
- Элементы массива указателей каждый указывают на первый символ одного из массивов
char
; кроме последнего элемента массива указателей, который является нулевым указателем.
Иногда люди пишут "указатель на массив X", чтобы означать "указатель на первый элемент массива X". Вы должны использовать контексты и типы для определения того, действительно ли это означало это.
Ответ 4
Да, точно.
argv
- это char**
или char*[]
, или просто массив указателей char *.
Итак, argv [0] - это char*
(строка), а argv[0][0]
- char
.
Ответ 5
Да.
Тип argv
- char**
, то есть указатель на указатель на char
. В принципе, если вы считаете, что char*
является строкой, то argv
является указателем на массив строк.
Ответ 6
argv
- массив указателей на символы.
Следующий код отображает значение argv
, содержимое argv
и выполняет дамп памяти в памяти, на которую указывает содержимое argv
. Надеюсь, это освещает смысл косвенности.
#include <stdio.h>
#include <stdarg.h>
print_memory(char * print_me)
{
char * p;
for (p = print_me; *p != '\0'; ++p)
{
printf ("%p: %c\n", p, *p);
}
// Print the '\0' for good measure
printf ("%p: %c\n", p, *p);
}
int main (int argc, char ** argv) {
int i;
// Print argv
printf ("argv: %p\n", argv);
printf ("\n");
// Print the values of argv
for (i = 0; i < argc; ++i)
{
printf ("argv[%d]: %p\n", i, argv[i]);
}
// Print the NULL for good measure
printf ("argv[%d]: %p\n", i, argv[i]);
printf ("\n");
// Print the values of the memory pointed at by argv
for (i = 0; i < argc; ++i)
{
print_memory(argv[i]);
}
return 0;
}
Пример прогона:
$ ./a.out Hello World!
argv: ffbfefd4
argv[0]: ffbff12c
argv[1]: ffbff134
argv[2]: ffbff13a
argv[3]: 0
ffbff12c: .
ffbff12d: /
ffbff12e: a
ffbff12f: .
ffbff130: o
ffbff131: u
ffbff132: t
ffbff133:
ffbff134: H
ffbff135: e
ffbff136: l
ffbff137: l
ffbff138: o
ffbff139:
ffbff13a: W
ffbff13b: o
ffbff13c: r
ffbff13d: l
ffbff13e: d
ffbff13f: !
ffbff140:
$
У вас есть этот большой непрерывный массив от ffbff12c
до ffbff140
, который содержит аргументы командной строки (это не гарантирует, что он будет соответствовать стандарту, но как это обычно делается). argv
просто содержит указатели в этом массиве, поэтому вы знаете, где искать слова.
argv
- указатель... на указатели... на символы