Was bedeutet int argc, char * argv []?

508

In vielen C ++ - IDEs und Compilern sieht es folgendermaßen aus, wenn die Hauptfunktion für Sie generiert wird:

int main(int argc, char *argv[])

Wenn ich C ++ ohne IDE nur mit einem Befehlszeilen-Compiler codiere, gebe ich Folgendes ein:

int main()

ohne Parameter. Was bedeutet das und ist es für mein Programm von entscheidender Bedeutung?

Greg Treleaven
quelle
47
Wenn Ihr Programm Befehlszeilenargumente ignoriert, ist das, was Sie schreiben, in Ordnung. Wenn Ihr Programm Befehlszeilenargumente verarbeiten muss, macht die IDE es richtig.
Jonathan Leffler
30
Ein Hinweis für Hacker: Versuchen Sie int main(int argc, char* argv[], char* envp[]), das letzte Argument zu deklarieren und auszudrucken. ;)
Ulidtko
7
@ulidtko es ist nicht gut, dass Sie Neulingen beibringen, Schwachstellen in ihre Programme einzuführen;)
Gab 是 好人
13
@Gab Wie führt das einfache Drucken von Umgebungsvariablen zu Sicherheitslücken? Übergeben Sie die verschmutzten Zeichenfolgen nur nicht wörtlich an system()Aufrufe, DB-Abfragen usw. Wie bei Benutzereingaben üblich.
Ulidtko
2
@ulidtko Interessant .. Können Sie erklären, warum Sie bei der Verwendung von char **envpArgumenten keine fehlerhaften Zeichenfolgen, Datenbankabfragen usw. übergeben müssen ?
Meister James

Antworten:

651

argvund argcwie Befehlszeilenargumente main()in C und C ++ übergeben werden.

argcwird die Anzahl der Zeichenfolgen sein, auf die durch gezeigt wird argv. Dies ist (in der Praxis) 1 plus die Anzahl der Argumente, da praktisch alle Implementierungen dem Array den Namen des Programms voranstellen.

Die Variablen werden gemäß Konvention argc( Argumentanzahl ) und argv( Argumentvektor ) benannt, können jedoch mit jedem gültigen Bezeichner versehen werden: int main(int num_args, char** arg_strings)ist gleichermaßen gültig.

Sie können auch ganz weggelassen werden int main(), wenn Sie keine Befehlszeilenargumente verarbeiten möchten.

Versuchen Sie das folgende Programm:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
}

Wenn Sie es mit ausführen, ./test a1 b2 c3wird ausgegeben

Have 4 arguments:
./test
a1
b2
c3
meagar
quelle
8
argckann 0 sein, in diesem Fall argvkann NULL sein. Es ist von der Standard-AFAIK erlaubt. Ich habe noch nie von einem System gehört, das dies in der Praxis tut, aber es könnte sicherlich existieren und würde keine Standards verletzen.
Chuck
77
@Chuck: Da "Der Wert von argv[argc]soll 0 sein" (C ++ 03 §3.6.1 / 2), argvkann nicht null sein.
James McNellis
20
@Chuck: C (mindestens C99) hat die gleiche Anforderung.
James McNellis
2
Ich dachte, ich sollte hinzufügen, dass dies in den meisten Systemen der Fall ist, obwohl sie manchmal abstrahiert sind. Zum Beispiel erhalten Sie in Pascal / Delphi / Lazarus; ParamStr und ParamCount (wenn der Speicher mir recht tut). Mein Punkt ist, wenn Sie (wenn überhaupt) native Anwendungen in anderen Sprachen / Betriebssystemen schreiben, besteht eine gute Chance, dass die oben genannten Anwendungen für Sie definiert sind, und sie funktionieren in allen Systemen, die unterstützen, perfekt gleich (Anzahl / Zeichenfolgenliste) Sie.
Christian
8
@ EmilVikström Nein, das ist ein schwerwiegender Fehler, der wahrscheinlich zu einem Segfault führt. *NULList definitiv nicht gleich NULL.
Meagar
52

argcist die Anzahl der Argumente, die über die Befehlszeile an Ihr Programm übergeben werden, und argvdas Array der Argumente.

Sie können die Argumente durchlaufen, indem Sie die Anzahl der Argumente kennen:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}
John Boker
quelle
19

Angenommen, Sie führen Ihr Programm folgendermaßen aus (unter Verwendung der shSyntax):

myprog arg1 arg2 'arg 3'

Wenn Sie Ihre Hauptleitung als deklariert haben, wird Ihre int main(int argc, char *argv[])(in den meisten Umgebungen) main()wie folgt aufgerufen:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

Wenn Sie jedoch Ihr Haupt als deklariert haben int main(), wird es so etwas wie genannt

exit(main());

und Sie bekommen die Argumente nicht übergeben.

Zwei zusätzliche Dinge zu beachten:

  1. Dies sind die einzigen zwei Standard-Signaturen für main. Wenn eine bestimmte Plattform zusätzliche Argumente oder einen anderen Rückgabetyp akzeptiert, ist dies eine Erweiterung und sollte in einem portablen Programm nicht verwendet werden.
  2. *argv[]und **argvsind genau gleichwertig, so dass Sie schreiben können int main(int argc, char *argv[])als int main(int argc, char **argv).
Toby Speight
quelle
2
Wenn wir technisch sind, werden basic.start.main/2explizit implementierungsdefinierte Zusatzversionen von zugelassen main(), sofern die Implementierung die beiden vordefinierten Versionen bereitstellt. Sie sind also nicht gerade nicht konform. Die häufigste ist die envp, die sowohl in C als auch in C ++ so bekannt ist , dass sie buchstäblich der allererste Eintrag in Abschnitt J.5 (Allgemeine Erweiterungen) des C-Standards ist .
Justin Time - Stellen Sie Monica am
1
Danke für die nette Pedanterie @Justin. Antwort aktualisiert, um korrekter zu sein.
Toby Speight
Keine Ahnung - ich schlage vor, Sie erstellen ein minimal reproduzierbares Beispiel und fragen es (vorausgesetzt, der Prozess reicht nicht aus, um Ihnen bei der Beantwortung zu helfen).
Toby Speight
9

Die Parameter zur mainDarstellung der Befehlszeilenparameter, die dem Programm beim Start zur Verfügung gestellt wurden. Der argcParameter stellt die Anzahl der Befehlszeilenargumente dar und char *argv[]ist ein Array von Zeichenfolgen (Zeichenzeigern), die die einzelnen Argumente in der Befehlszeile darstellen.

BlueMonkMN
quelle
2
Argv [] hat immer argv [arg] als Nullzeiger. und Argv [0] ist immer der (vollständige Pfad) / ausführbare
Name
3
@ user3629249: Nicht unbedingt; argv[0]ist das, was das Programm, das das C-Programm startet, als gegeben hat argv[0]. Im Fall von Bash ist es oft (vielleicht immer) der Pfadname der ausführbaren Datei, aber Bash ist nicht das einzige Programm, das andere Programme ausführt. Es ist zulässig, wenn auch exzentrisch, Folgendes zu verwenden : char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. Auf vielen Systemen wird der Wert vom Programm so gesehen, wie er sein argv[0]wird cat, obwohl die ausführbare Datei ist /bin/ls.
Jonathan Leffler
7

Die mainFunktion kann zwei Parameter haben, argcund argv. argcist ein integer ( int) -Parameter und die Anzahl der an das Programm übergebenen Argumente.

Der Programmname ist immer das erste Argument, daher gibt es mindestens ein Argument für ein Programm und der Mindestwert von argcist eins. Wenn ein Programm selbst zwei Argumente hat, ist der Wert von argcdrei.

Der Parameter argvzeigt auf ein String-Array und wird als Argumentvektor bezeichnet . Es ist ein eindimensionales String-Array von Funktionsargumenten.

Moshtagh
quelle
5
int main();

Dies ist eine einfache Erklärung. Es können keine Befehlszeilenargumente akzeptiert werden.

int main(int argc, char* argv[]);

Diese Deklaration wird verwendet, wenn Ihr Programm Befehlszeilenargumente annehmen muss. Wenn Sie so laufen:

myprogram arg1 arg2 arg3

argc, oder Argument Count wird auf 4 (vier Argumente) gesetzt, und argvoder Argument Vectors werden mit Zeichenfolgenzeigern auf "myprogram", "arg1", "arg2" und "arg3" gefüllt. Der Programmaufruf ( myprogram) ist in den Argumenten enthalten!

Alternativ können Sie Folgendes verwenden:

int main(int argc, char** argv);

Dies gilt auch.

Es gibt einen weiteren Parameter, den Sie hinzufügen können:

int main (int argc, char *argv[], char *envp[])

Der envpParameter enthält auch Umgebungsvariablen. Jeder Eintrag folgt diesem Format:

VARIABLENAME=VariableValue

so was:

SHELL=/bin/bash    

Die Liste der Umgebungsvariablen ist nullterminiert.

WICHTIG: Verwenden Sie KEINE argvoder envpWerte direkt in Aufrufen von system()! Dies ist eine große Sicherheitslücke, da böswillige Benutzer Umgebungsvariablen auf Befehlszeilenbefehle setzen und (möglicherweise) massiven Schaden anrichten können. Im Allgemeinen nur nicht verwenden system(). Es gibt fast immer eine bessere Lösung, die durch C-Bibliotheken implementiert wird.

Adrian
quelle
3

Der erste Parameter ist die Anzahl der bereitgestellten Argumente und der zweite Parameter ist eine Liste von Zeichenfolgen, die diese Argumente darstellen.

Nick Gerakines
quelle
7
Der erste Eintrag in argv [0] ist der Programmname, kein Argument
user3629249
@ user3629249 Programmname mit Programmpfad. ;)
Meister James
1

Beide von

int main(int argc, char *argv[]);
int main();

sind rechtliche Definitionen des Einstiegspunkts für ein C- oder C ++ - Programm. Stroustrup: In den häufig gestellten Fragen zu Stil und Technik von C ++ werden einige der Variationen aufgeführt, die für Ihre Hauptfunktion möglich oder zulässig sind.

Chris Becke
quelle
4
Vielleicht möchten Sie in int main()== ==> int main(void)... für Kompatibilität und Lesbarkeit ungültig machen . Ich weiß nicht, ob alle älteren Versionen von C zulassen, dass void-Funktionen eine leere Parameterliste in der Deklaration haben.
dylnmc
1
@dylnmc Dies ergibt keinen Lesbarkeitsgewinn und ist in allen C ++ - Versionen genau gleichwertig. Nur in C hat dies einen Unterschied, aber nur in Deklarationen, nicht in der Definition.
Ruslan
@ Ruslan Entschuldigung, ich habe dies gepostet, als ich gerade C lernte, und ich habe vielleicht gelesen, dass in sehr frühen Versionen von C das voiderforderlich ist. Zitiere mich nicht dazu und ich weiß jetzt, dass es ein etwas dummer Kommentar ist. Es kann aber nicht schaden.
dylnmc
Was ist, wenn argc <3 einen Fehler zurückgibt? Was könnte möglicherweise schief gehen?
AVI