Ich lese einen Abschnitt aus C Primer Plus über das Befehlszeilenargument argv
und habe Schwierigkeiten, diesen Satz zu verstehen.
Es steht dass,
Das Programm speichert die Befehlszeilenzeichenfolgen im Speicher und speichert die Adresse jeder Zeichenfolge in einem Array von Zeigern. Die Adresse dieses Arrays wird im zweiten Argument gespeichert. Konventionell heißt dieser Zeiger auf Zeiger für Argumentwerte
argv
.
Bedeutet dies, dass die Befehlszeilenzeichenfolgen als Array von Zeigern auf das Array von char
im Speicher gespeichert werden?
Direktes Zitieren aus C11
, Kapitel §5.1.2.2.1/p2, Programmstart, (Hervorhebung meines)
int main(int argc, char *argv[]) { /* ... */ }
[...] Wenn der Wert von
argc
größer als Null ist, müssen die Array-Memberargv[0]
bisargv[argc-1]
inklusive Zeiger auf Strings , [...]
und
[...] und die Zeichenfolgen, auf die das
argv
-Array zeigt, [...]
Im Grunde ist argv
ein Zeiger auf das erste Element eines String-Arrays hinweis. Dies kann aus der Alternativform klarer gemacht werden.
int main(int argc, char **argv) { /* ... */ }
Sie können das als Zeiger auf das erste Element eines Arrays von Zeigern auf das erste Element von char
-Arrays mit Nullterminierung umformulieren, aber ich würde lieber Strings behalten.
HINWEIS:
Um die Verwendung von "Zeiger auf das erste Element eines Arrays" zu verdeutlichen, in der obigen Antwort, folgt §6.3.2.1/p3
Außer, wenn es sich um den Operanden des
sizeof
-Operators, des_Alignof
-Operators oder des Unären&
-Operators handelt oder um ein String-Literal zum Initialisieren eines Arrays, einen Ausdruck mit dem Typ '' Array vom Typ '' wird in einen Ausdruck mit dem Typ '' Zeiger auf den Typ '' umgewandelt der auf auf das Anfangselement des Arrayobjekts zeigt und ist kein lvalue. [...]
argv
ist vom Typ char **
. Es ist kein Array . Es ist ein Zeiger auf char
. Befehlszeilenargumente werden im Speicher gespeichert, und die Adresse jedes Speicherplatzes wird in einem Array gespeichert. Dieses Array ist ein Array von Zeigern auf char
. argv
zeigt auf das erste Element dieses Arrays.
Einige Felder + ------- + + ------ + ------ + ---- --------- + ------ + argv ----------> | | | | | | | 0x100 + ------> | | | . . . . . . | | Programmname1 0x900 | | | | | | | | + ------ + ------ + ------------- + ------ + + ------- + 0x100 0x101 | | + ------ + ------ + ------------- + ------ + | 0x205 | | | | | 0x904 | + ------> | | | . . . . . . | | Arg1 | | . | | | | | + ------- + + ------ + ------ + ------------- + ------ + | . | . 0x205 0x206 | . | . | . | . + ------- +. + ------ + ------ + ------------- + ------ + | | | | | | | 0x501 + ------> | | | . . . . . . | | Argargc-1 | | | | | | | + ------- + + ------ + ------ + ------------- + ------ + | | 0x501 0x502 | NULL | | | + ------- + 0xXXX Stellt die Speicheradresse dar
1. In den meisten Fällen steht argv[0]
für den Programmnamen, aber wenn der Programmname nicht in der Host-Umgebung verfügbar ist, steht argv[0][0]
für Nullzeichen.
Dieser Thread ist so ein Zugunglück. Hier ist die Situation:
argc+1
-Elementen vom Typ char *
.argv
zeigt auf das erste Element dieses Arrays.argc
andere Arrays vom Typ char
und verschiedene Längen, die nullterminierte Zeichenfolgen enthalten, die die Befehlszeilenargumente darstellen.char
; mit Ausnahme des letzten Elements des Arrays von Zeigern, das ein Nullzeiger ist.Manchmal schreiben Leute "Zeiger auf Array von X", um "Zeiger auf das erste Element eines Arrays von X" zu bedeuten. Sie müssen die Kontexte und Typen verwenden, um herauszufinden, ob sie dies tatsächlich bedeuteten oder nicht.
argv
ist ein Array von Zeigern auf Zeichen.
Der folgende Code zeigt den Wert von argv
und den Inhalt von argv
an und führt einen Speicherabzug für den Speicher aus, auf den der Inhalt von argv
zeigt. Hoffentlich beleuchtet dies die Bedeutung der Indirektion.
#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;
}
Probelauf:
$ ./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:
$
Sie haben dieses große zusammenhängende Array von ffbff12c
bis ffbff140
, das die Befehlszeilenargumente enthält (dies ist vom Standard nicht garantiert ein zusammenhängendes Array, wird aber im Allgemeinen so gemacht). argv
enthält nur Zeiger in dieses Array, damit Sie wissen, wo Sie nach den Wörtern suchen müssen.
argv
ist ein Zeiger ... auf Zeiger ... auf Zeichen
Ja genau.
argv
ist ein char**
oder char*[]
oder einfach ein Array von char * -Pointern.
Argv [0] ist also ein char*
(eine Zeichenfolge) und argv[0][0]
ist eine char
.
Ja.
Der Typ von argv
ist char**
, d. H. Ein Zeiger auf einen Zeiger auf char
. Wenn Sie char*
als eine Zeichenfolge betrachten, ist argv
ein Zeiger auf ein String-Array.