web-dev-qa-db-fra.com

Comment analyser des arguments de ligne de commande entiers en C?

Je voudrais qu'un utilisateur passe deux paramètres ou le laisse vide. Par exemple:

./program 50 50

ou

./program

Quand j'ai essayé d'utiliser int main(int argc, char *argv[]), la première chose que j'ai faite a été de changer char *argv[] En int *argv[] Mais cela n'a pas fonctionné. Ce que je veux, c'est que l'utilisateur est juste pour entrer deux entiers entre 0 et 1. Donc, si ce n'est pas deux entiers, cela devrait donner une erreur.

J'étais en quelque sorte en train de penser à donner une erreur avec les types (comme j'avais l'habitude de programmer en C #) mais quoi que j'entre, argv [1] serait de type 'char' tout le temps.

Donc ce que j'ai fait c'est

for (int i = 0; i <= 100; i++) {
    //printf("%d", i);
    if (argv[1] == i) {
        argcheck++;
        printf("1st one %d\n", i);
    }
    else if (argv[2] == i) {
        argcheck++;
        printf("2nd one %d\n", i);
    }

Cela ne fonctionne pas aussi bien. De plus, il donne un avertissement lors de la compilation, mais si je change argv avec atoi(argv[1]) par exemple, alors il donne un défaut de segmentation (core dumped) erreur.

J'ai besoin d'un moyen simple de résoudre ce problème.

ÉDITER:

J'ai donc corrigé avec atoi(), la raison pour laquelle il donnait un défaut de segmentation était parce que je l'essayais avec une valeur nulle quand je n'ai pas de paramètre. Je l'ai donc corrigé en ajoutant une condition supplémentaire. Mais maintenant, le problème est que si la valeur est disons

./program asd asd

La sortie de atoi(argv[1]) serait alors 0. Existe-t-il un moyen de modifier cette valeur?

16
Sarp Kaya

N'utilisez pas atoi() et n'utilisez pas strtol(). atoi() n'a pas de vérification d'erreur (comme vous l'avez découvert!) et strtol() doit être vérifié en utilisant la variable globale errno, ce qui signifie que vous devez définir errno à 0, puis appelez strtol(), puis vérifiez à nouveau errno pour les erreurs. ne meilleure façon est d'utiliser sscanf(), qui vous permet également d'analyser n'importe quel type primitif à partir d'une chaîne, pas seulement un entier, et de lire des formats fantaisistes (comme hex).

Par exemple, pour analyser un entier "1435" à partir d'une chaîne:

if (sscanf (argv[1], "%i", &intvar) != 1) {
    fprintf(stderr, "error - not an integer");
}

Pour analyser un seul caractère "Z" à partir d'une chaîne

if (sscanf (argv[1], "%c", &charvar)!=1) {
    fprintf(stderr, "error - not a char");
}

Pour analyser un flottant "3.1459" à partir d'une chaîne

if (sscanf (argv[1], "%f", &floatvar)!=1) {
    fprintf(stderr, "error - not a float");
}

Pour analyser un grand entier hexadécimal non signé "0x332561" à partir d'une chaîne

if (sscanf (argv[1], "%xu", &uintvar)!=1) {
    fprintf(stderr, "error - not a hex integer");
}

Si vous avez besoin de plus de gestion des erreurs que cela, utilisez une bibliothèque regex.

29
Lelanthran

Cela fera:

int main(int argc, char*argv[])
{
   long a,b;
   if (argc > 2) 
   {
      a = strtol(argv[1], NULL, 0);
      b = strtol(argv[2], NULL, 0);
      printf("%ld %ld", a,b);
   }
   return 0;
}
14
P.P

Les arguments sont toujours passés sous forme de chaînes, vous ne pouvez pas changer le prototype de main(). Le système d'exploitation et les machines environnantes passent toujours des chaînes et ne sont pas en mesure de comprendre que vous les avez modifiés.

Vous devez utiliser par exemple strtol() pour convertir les chaînes en entiers.

5
unwind

Vous voulez vérifier si

  1. 0 ou 2 arguments sont reçus
  2. deux valeurs reçues sont comprises entre 0 et 100
  3. l'argument reçu n'est pas une chaîne. Si la chaîne vient sscanf retournera 0.

La logique ci-dessous vous aidera

int main(int argc, char *argv[])
{
    int no1 = 0, no2 = 0, ret = 0;

    if ((argc != 0) && (argc != 2)) 
    {
        return 0;
    }

    if (2 == argc)
    {
        ret = sscanf(argv[1], "%d", &no1);
        if (ret != 1)return 0;
        ret = sscanf(argv[2], "%d", &no2);
        if (ret != 1)return 0;          

        if ((no1 < 0) || (no1 >100)) return 0;
        if ((no2 < 0) || (no2 >100)) return 0;          
    }

    //now do your stuff
}
2
rashok

Vous pouvez toujours utiliser atoi, vérifiez simplement si l'argument est d'abord un nombre;)
btw ppl vous dira que goto est evil, mais ils sont généralement soumis à un lavage de cerveau par des non-sensibles "goto is bad", "goto is evil", "goto is le diable " déclarations qui viennent d'être lancées sans être élaborées sur Internet.
Oui, le code spaggethi est moins gérable. Et goto dans ce contexte est d'une époque où il a remplacé les fonctions ...

    int r, n, I;
    for (I = 0; I < argc; ++I)
    {
      n = 0;
      do
        if ( !((argv + I) [n] >= '0' && (argv + I) [n] <= '9') )
        {
          err:
            fprintf(stderr,"ONLY INTEGERS 0-100 ALLOWED AS ARGUMENTS!\n");
            return 1;
        }
      while ((argv + I) [++n] != '\0')
      r = atoi(argv[I]);
      if (r > 100)
        goto err;
    }
0
Anonymous

Les choses que vous avez faites si innocemment sont des erreurs en C. Quoi qu'il en soit, vous devez prendre des chaînes ou des caractères comme arguments et plus tard, vous pouvez faire ce que vous voulez avec eux. Modifiez-les en entier à l'aide de strtol ou laissez-les être les chaînes et vérifiez chaque caractère de la chaîne dans la plage de 48 to 57 car ce sont les valeurs décimales de char 0 to 9. Personnellement, ce n'est pas une bonne idée et pas une bonne pratique de codage. Mieux les convertir et vérifier la plage entière que vous souhaitez.

0
Abhineet