Warum brauchen wir argc, während am Ende von argv immer eine Null steht?

116

Es scheint, dass das argv[argc]immer NULLso ist , also denke ich, dass wir die Argumentliste ohne durchlaufen können argc. Eine einzelne whileSchleife wird dies tun.

Wenn es NULLam Ende immer eine gibt argv, warum brauchen wir dann eine argc?

StarPinkER
quelle
17
Es ist wahrscheinlich eine Frage der Bequemlichkeit. Bietet dem Programmierer eine einfache Möglichkeit, frühzeitig auszusteigen, wenn nicht genügend Argumente vorhanden sind, ohne eine Schleife durchzuführen. Andernfalls hätten wir sicherlich Funktionen, int argc(char *argv[])die genau dies tun :-))
cnicutar
5
Nur um klar zu sein, "\0"ist nicht dasselbe wie der NULL-Zeiger ( 0entspricht NULL in C ++)
Mats Petersson,
31
Warum muss argv [argc] NULL sein, wenn wir argc haben?
Ambroz Bizjak
7
Wie würden Sie sonst die Anzahl der Argumente in konstanter Zeit bestimmen?
Avakar
4
Denken Sie nicht, dass die Linux / Unix-Tags hier angemessen sind, da dieses Verhalten für alle Compiler in allen Betriebssystemen gelten sollte.
Darrel Hoffman

Antworten:

106

Ja, argv[argc]==NULList garantiert. Siehe C11 5.1.2.2.1 Programmstart (mein Schwerpunkt)

Wenn sie deklariert sind, müssen die Parameter der Hauptfunktion den folgenden Einschränkungen entsprechen:

Der Wert von argc ist nicht negativ. argv [argc] soll ein Nullzeiger sein.

Das Bereitstellen ist argcdaher nicht wichtig, aber dennoch nützlich. Dies ermöglicht unter anderem eine schnelle Überprüfung, ob die richtige Anzahl von Argumenten übergeben wurde.

Bearbeiten: Die Frage wurde geändert, um C ++ einzuschließen. n3337 Entwurf 3.6.1 Hauptfunktion sagt

2 ... argc ist die Anzahl der Argumente, die aus der Umgebung, in der das Programm ausgeführt wird, an das Programm übergeben werden. .... Der Wert von argc darf nicht negativ sein. Der Wert von argv [argc] soll 0 sein .

simonc
quelle
36
Und argckönnte ziemlich groß sein, da die Shell Erweiterung tut (so in ls *dem *von der Shell vor erweitert wird execvevon /bin/lsausführbaren). Auf meinem System kann ich argcmehrere hunderttausend haben.
Basile Starynkevitch
Das ist ziemlich cool, das ist mir nie in den Sinn gekommen, da ich es immer für argcausreichend gehalten habe, aber ich kann mir definitiv Situationen vorstellen, in denen diese Garantie relevant und sogar erforderlich wäre. +1
Thomas
6
@BasileStarynkevitch Die Zeit, in der ein Array von Zeigerwerten ein weiteres Mal bis NULL durchlaufen wird, um die Anzahl zu ermitteln, ist im Vergleich zu der Zeit, die bereits für die Generierung des Zeigerarrays aufgewendet wurde, winzig und im Vergleich zur tatsächlichen Verwendung jedes Argumentwerts im Programm noch irrelevanter. Und wenn Sie nur prüfen, ob die Anzahl der Argumente größer als N ist, müssen Sie nicht das gesamte Array durchlaufen. Trotzdem stimme ich voll argcund ganz zu, das war und ist eine gute Sache.
Hyde
43

Ja, argv[argc]ist garantiert ein Nullzeiger. argcwird der Einfachheit halber verwendet.

Beachten Sie unter Angabe der offiziellen Erklärung aus C99 Rationale die Worte redundante Prüfung :

Begründung für den internationalen Standard - Programmiersprachen - C §5.1.2.2.1 Programmstart

Die Spezifikation von argcund argvals Argumente zur mainAnerkennung umfangreicher früherer Praktiken. argv[argc]muss ein Nullzeiger sein, um eine redundante Prüfung für das Ende der Liste bereitzustellen, auch auf der Grundlage der üblichen Praxis.

Yu Hao
quelle
19

Es ist aus historischen Gründen und Kompatibilität mit altem Code. Ursprünglich gab es keine Garantie dafür, dass ein Nullzeiger als letztes Element des argv-Arrays vorhanden sein würde. Aber argc hat es immer gegeben.

zentrunix
quelle
... Was in gewisser Weise eine Schande ist. Wenn wir das hätten int main(char *argv[], int argc, ...), könnten einige Programme das einfach weglassen, argcweil sie es nicht brauchen. Das Gegenteil (brauchen, argcaber nicht argv) ist in einem echten Programm wahrscheinlich nie nützlich.
Hyde
@ Hyde: siehe Kommentar oben von Basile Starynkevitch
zentrunix
6

Wir "brauchen" es, weil es von verschiedenen Standards verlangt wird.

Es steht uns frei, den Wert vollständig zu ignorieren, aber da er der erste Parameter von ist main, müssen wir ihn in der Parameterliste haben. In C ++ (und wahrscheinlich nicht standardmäßigen C-Dialekten) können Sie den Parameternamen einfach weglassen, wie in diesem C ++ - Snippet (einfach in C zu konvertieren):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

In Standard C mit allgemeinen Warneinstellungen generiert ein nicht verwendeter Parameter eine Warnung, die durch eine Anweisung behoben werden kann, mit (void)argc;der der Name verwendet wird, ohne dass Code generiert wird.

argcist schön zu haben, weil sonst viele Programme die Parameter durchlaufen müssten, um die Zählung zu erhalten. Außerdem gibt es in vielen Programmiersprachen mit Arrays mit Länge keinen argcParameter, sondern nur ein Array mit den Elementen.

Hyde
quelle
Die Frage betrifft sowohl C als auch C ++. In C ist der Parametername erforderlich.