82 votes

Comment convertir un argument de ligne de commande en int ?

Je dois récupérer un argument et le convertir en un int. Voici mon code jusqu'à présent :

#include <iostream>

using namespace std;
int main(int argc,int argvx[]) {
    int i=1;
    int answer = 23;
    int temp;

    // decode arguments
    if(argc < 2) {
        printf("You must provide at least one argument\n");
        exit(0);
    }

    // Convert it to an int here

}

124voto

Thomas Points 63635

Puisque cette réponse a été acceptée d'une manière ou d'une autre et qu'elle apparaîtra donc en haut, bien qu'elle ne soit pas la meilleure, je l'ai améliorée en me basant sur les autres réponses et les commentaires.

La méthode C ; la plus simple, mais elle traitera tout nombre invalide comme 0 :

#include <cstdlib>

int x = atoi(argv[1]);

La méthode C avec vérification des entrées :

#include <cstdlib>

errno = 0;
char *endptr;
long int x = strtol(argv[1], &endptr, 10);
if (endptr == argv[1]) {
  std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (*endptr) {
  std::cerr << "Trailing characters after number: " << argv[1] << '\n';
} else if (errno == ERANGE) {
  std::cerr << "Number out of range: " << argv[1] << '\n';
}

La méthode C++ iostreams avec vérification des entrées :

#include <sstream>

std::istringstream ss(argv[1]);
int x;
if (!(ss >> x)) {
  std::cerr << "Invalid number: " << argv[1] << '\n';
} else if (!ss.eof()) {
  std::cerr << "Trailing characters after number: " << argv[1] << '\n';
}

Méthode alternative C++ depuis C++11 :

#include <stdexcept>
#include <string>

std::string arg = argv[1];
try {
  std::size_t pos;
  int x = std::stoi(arg, &pos);
  if (pos < arg.size()) {
    std::cerr << "Trailing characters after number: " << arg << '\n';
  }
} catch (std::invalid_argument const &ex) {
  std::cerr << "Invalid number: " << arg << '\n';
} catch (std::out_of_range const &ex) {
  std::cerr << "Number out of range: " << arg << '\n';
}

Les quatre variantes supposent que argc >= 2 . Tous acceptent les espaces en tête ; vérifiez isspace(argv[1][0]) si vous ne le voulez pas. Tous sauf atoi rejette les espaces blancs de fin de ligne.

26voto

Charles Bailey Points 244082

Notez que votre main ne sont pas corrects. La forme standard devrait être :

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

ou de manière équivalente :

int main(int argc, char **argv)

Il existe de nombreuses façons de réaliser cette conversion. Voici une approche :

#include <sstream>

int main(int argc, char *argv[])
{
    if (argc >= 2)
    {
        std::istringstream iss( argv[1] );
        int val;

        if (iss >> val)
        {
            // Conversion successful
        }
    }

    return 0;
}

0 votes

Oh, c'était mon erreur. Je l'avais à l'origine comme ça mais j'ai commencé à essayer différentes choses et j'ai oublié de le changer à nouveau.

20voto

HelloWorld Points 437

Std::stoi from string pourrait également être utilisé.

    #include <string>

    using namespace std;

    int main (int argc, char** argv)
    {
         if (argc >= 2)
         {
             int val = stoi(argv[1]);
             // ...    
         }
         return 0;
    }

3voto

Jerry Coffin Points 237758

Comme l'a souligné Whirlwind, les recommandations d'utiliser atoi ne sont pas vraiment très bonnes. atoi n'a aucun moyen d'indiquer une erreur, donc vous obtenez le même retour de la part de atoi("0"); comme vous le faites de atoi("abc"); . Le premier est clairement significatif, mais le second est une erreur manifeste.

Il a également recommandé strtol ce qui est tout à fait correct, même si c'est un peu maladroit. Une autre possibilité serait d'utiliser sscanf quelque chose comme :

if (1==sscanf(argv[1], "%d", &temp))
    // successful conversion
else
    // couldn't convert input

notez que strtol donne cependant des résultats légèrement plus détaillés -- en particulier, si vous avez un argument comme 123abc le sscanf l'appel dirait simplement qu'il a converti un nombre (123), alors que strtol vous indiquerait non seulement qu'il a converti le nombre, mais aussi un pointeur sur le fichier a (c'est-à-dire le début de la partie qu'il pourrait no convertir en un nombre).

Puisque vous utilisez C++, vous pourriez également envisager d'utiliser boost::lexical_cast . C'est presque aussi simple à utiliser que atoi mais fournit également (à peu près) le même niveau de détail dans la déclaration des erreurs que le système strtol . Le plus gros inconvénient est qu'il peut lancer des exceptions, donc pour l'utiliser, votre code doit être protégé contre les exceptions. Si vous écrivez en C++, vous devriez le faire de toute façon, mais cela force un peu le problème.

1voto

andrey Points 116

L'approche avec istringstream peut être améliorée afin de vérifier qu'aucun autre caractère n'a été inséré après l'argument attendu :

#include <sstream>

int main(int argc, char *argv[])
{
    if (argc >= 2)
    {
        std::istringstream iss( argv[1] );
        int val;

        if ((iss >> val) && iss.eof()) // Check eofbit
        {
            // Conversion successful
        }
    }

    return 0;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X