Que signifie int argc, char * argv []?

508

Dans de nombreux IDE et compilateurs C ++, lorsqu'il génère la fonction principale pour vous, il ressemble à ceci:

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

Lorsque je code C ++ sans IDE, juste avec un compilateur en ligne de commande, je tape:

int main()

sans aucun paramètre. Qu'est-ce que cela signifie et est-ce vital pour mon programme?

Greg Treleaven
la source
47
Si votre programme va ignorer les arguments de ligne de commande, alors ce que vous écrivez est correct. Si votre programme doit traiter des arguments de ligne de commande, l'EDI le fait correctement.
Jonathan Leffler
30
Un conseil pour les pirates: essayez de déclarer int main(int argc, char* argv[], char* envp[])et d'imprimer le dernier argument. ;)
ulidtko
7
@ulidtko ce n'est pas bon que vous enseigniez aux débutants à introduire la vulnérabilité dans leurs programmes;)
Gab 是 好人
13
@Gab comment l'impression simple de variables d'environnement conduit-elle à une vulnérabilité? Ne transmettez pas les chaînes entachées textuellement aux system()appels, aux requêtes de base de données, etc. Comme d'habitude avec les entrées utilisateur.
ulidtko
2
@ulidtko Intéressant .. Pouvez-vous expliquer pourquoi vous n'avez pas à passer des chaînes corrompues, des requêtes db, etc. tout en utilisant un char **envpargument?
Master James

Réponses:

651

argvet argccomment les arguments de ligne de commande sont passés main()en C et C ++.

argcsera le nombre de chaînes pointées par argv. Ce sera (en pratique) égal à 1 plus le nombre d'arguments, car pratiquement toutes les implémentations ajouteront le nom du programme au tableau.

Les variables sont nommées argc( nombre d'arguments ) et argv( vecteur d'arguments ) par convention, mais elles peuvent recevoir n'importe quel identifiant valide: int main(int num_args, char** arg_strings)est également valide.

Ils peuvent également être entièrement omis, ce qui donne int main(), si vous n'avez pas l'intention de traiter les arguments de ligne de commande.

Essayez le programme suivant:

#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;
    }
}

L'exécuter avec ./test a1 b2 c3affichera

Have 4 arguments:
./test
a1
b2
c3
meagar
la source
8
argcpeut être 0, auquel cas argvpeut être NULL. C'est autorisé par la norme AFAIK. Je n'ai jamais entendu parler d'un système qui le fasse dans la pratique, mais il pourrait certainement exister et ne violerait aucune norme.
Chuck
78
@Chuck: Puisque "La valeur de argv[argc]doit être 0" (C ++ 03 §3.6.1 / 2), argvne peut pas être nul.
James McNellis
20
@Chuck: C (au moins C99) a la même exigence.
James McNellis
2
J'ai pensé que je devrais ajouter, c'est la même chose dans la plupart des systèmes, bien qu'ils soient parfois abstraits. Par exemple, dans Pascal / Delphi / Lazarus, vous obtenez; ParamStr et ParamCount (si la mémoire me sert bien). Mon point est que lorsque vous (si jamais) écrivez des applications natives dans d'autres langues / oses, il y a de fortes chances que ce qui précède soit défini pour que vous les utilisiez, et elles fonctionnent parfaitement de la même manière (nombre / liste de chaînes) dans tous les systèmes qui prennent en charge leur.
Christian
8
@ EmilVikström Non, c'est une grave erreur qui se traduit probablement par une erreur de segmentation. *NULLn'est certainement pas égal à NULL.
meagar
52

argcest le nombre d'arguments transmis à votre programme à partir de la ligne de commande et argvest le tableau d'arguments.

Vous pouvez parcourir les arguments en connaissant le nombre d'entre eux comme:

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

Supposons que vous exécutiez votre programme ainsi (en utilisant la shsyntaxe):

myprog arg1 arg2 'arg 3'

Si vous avez déclaré votre main comme int main(int argc, char *argv[]), alors (dans la plupart des environnements), votre main()sera appelé comme si:

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

Cependant, si vous avez déclaré votre principal comme int main(), il sera appelé quelque chose comme

exit(main());

et vous ne faites pas passer les arguments.

Deux choses supplémentaires à noter:

  1. Ce sont les deux seules signatures standard pour main. Si une plate-forme particulière accepte des arguments supplémentaires ou un type de retour différent, alors c'est une extension et ne doit pas être invoqué dans un programme portable.
  2. *argv[]et **argvsont exactement équivalents, vous pouvez donc écrire en int main(int argc, char *argv[])tant que int main(int argc, char **argv).
Toby Speight
la source
2
Si nous sommes techniques, basic.start.main/2autorise explicitement les versions supplémentaires définies par l'implémentation de main(), à condition que l'implémentation fournisse les deux versions prédéfinies. Donc, ils ne sont pas exactement non conformes. Le plus commun est l' un envp, qui est si bien connu dans les deux C et C ++ que c'est littéralement la toute première entrée dans la section J.5 (extensions communes) de la norme C .
Justin Time - Rétablir Monica le
1
Merci pour la belle pédanterie @Justin. Réponse mise à jour pour être plus correcte.
Toby Speight
Aucune idée - je vous suggère de créer un exemple reproductible minimal et de le demander (en supposant que le processus n'est pas suffisant pour vous aider à y répondre vous-même).
Toby Speight
9

Les paramètres pour mainreprésenter les paramètres de ligne de commande fournis au programme lors de son démarrage. Le argcparamètre représente le nombre d'arguments de ligne de commande et char *argv[]est un tableau de chaînes (pointeurs de caractères) représentant les arguments individuels fournis sur la ligne de commande.

BlueMonkMN
la source
2
Argv [] a toujours argv [arg] comme pointeur nul. et Argv [0] est toujours le (chemin complet) / executableName en tant que chaîne terminée par nul
user3629249
3
@ user3629249: Pas nécessairement; argv[0]est ce que le programme de lancement du programme C lui a donné argv[0]. Dans le cas de Bash, c'est souvent (peut-être toujours) le nom de chemin de l'exécutable, mais Bash n'est pas le seul programme qui exécute d'autres programmes. Il est permissisble, si excentrique, à utiliser: char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. Sur de nombreux systèmes, la valeur vue par le programme argv[0]sera cat, même si l'exécutable l'est /bin/ls.
Jonathan Leffler
7

La mainfonction peut avoir deux paramètres, argcet argv. argcest un intparamètre integer ( ), et c'est le nombre d'arguments passés au programme.

Le nom du programme est toujours le premier argument, il y aura donc au moins un argument dans un programme et la valeur minimale de argcsera un. Mais si un programme a lui-même deux arguments, la valeur de argcsera de trois.

Le paramètre argvpointe vers un tableau de chaînes et est appelé le vecteur d'argument . Il s'agit d'un tableau de chaînes unidimensionnel d'arguments de fonction.

moshtagh
la source
5
int main();

Ceci est une simple déclaration. Il ne peut accepter aucun argument de ligne de commande.

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

Cette déclaration est utilisée lorsque votre programme doit accepter des arguments de ligne de commande. Lorsqu'il est exécuté comme tel:

myprogram arg1 arg2 arg3

argc, ou Argument Count, sera défini sur 4 (quatre arguments) et argv, ou Argument Vectors, seront remplis avec des pointeurs de chaîne sur "myprogram", "arg1", "arg2" et "arg3". Le programme invocation ( myprogram) est inclus dans les arguments!

Alternativement, vous pouvez utiliser:

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

Ceci est également valable.

Il y a un autre paramètre que vous pouvez ajouter:

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

Le envpparamètre contient également des variables d'environnement. Chaque entrée suit ce format:

VARIABLENAME=VariableValue

comme ça:

SHELL=/bin/bash    

La liste des variables d'environnement se termine par null.

IMPORTANT: N'UTILISEZ PAS les valeurs argvou envpdirectement dans les appels à system()! Il s'agit d'un énorme trou de sécurité, car des utilisateurs malveillants pourraient définir des variables d'environnement sur des commandes de ligne de commande et (potentiellement) causer des dommages massifs. En général, ne l'utilisez pas system(). Il existe presque toujours une meilleure solution implémentée via les bibliothèques C.

adrian
la source
3

Le premier paramètre est le nombre d'arguments fournis et le second paramètre est une liste de chaînes représentant ces arguments.

Nick Gerakines
la source
7
la première entrée dans argv [0] est le nom du programme, pas un argument
user3629249
@ user3629249 Nom du programme avec chemin d'accès au programme. ;)
Master James
1

Les deux

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

sont des définitions légales du point d'entrée d'un programme C ou C ++. Stroustrup: FAQ sur le style et la technique C ++ détaille certaines des variations possibles ou légales pour votre fonction principale.

Chris Becke
la source
4
Pourrait vouloir mettre le vide dans ... int main()==> int main(void)... pour la compatibilité et la lisibilité. Je ne sais pas si toutes les anciennes versions de C permettent aux fonctions void d'avoir une liste de paramètres vide dans la déclaration.
dylnmc
1
@dylnmc cela ne donne aucun gain de lisibilité, et est exactement équivalent dans toutes les versions C ++. Ce n'est qu'en C que cela a une différence, mais seulement dans les déclarations, pas dans la définition.
Ruslan
@Ruslan Désolé, j'ai posté ceci lorsque je venais d'apprendre le C, et j'aurais peut-être lu que dans les toutes premières versions de C, il voidest nécessaire. Ne me citez pas là-dessus, et je sais maintenant que c'est un commentaire un peu stupide. Cela ne peut pas faire de mal, cependant.
dylnmc
que faire si argc <3 renvoie une erreur? qu'est-ce qui pourrait mal tourner?
AVI