Проверка того, что argv[1] является целым числом C++

Для моей программы я должен убедиться, что пользователь вводит только положительный INTEGER. например, если пользователь ввел 12hi, он не должен запускать программу и печатать в std error. Я не совсем уверен, как это реализовать.

int main(int argc, char *argv[])   
{ 
    if(atoi(argv[1]) < 1)
    {
        cerr << "ERROR!"<< endl;
        return 1;
    }
    return 0;
}

5 ответов

Передай это std::istringstream и убедитесь, что все данные были обработаны:

if (a_argc > 1)
{
    std::istringstream in(a_argv[1]);
    int i;
    if (in >> i && in.eof())
    {
        std::cout << "Valid integer\n";
    }
}

Смотрите онлайн демо на http://ideone.com/8bEYJq.

Хорошо, мой пересмотренный ответ. sscanf вел себя не так, как я думал, и strtol предоставляет лучшее C-подобное решение, которое очень переносимо.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
  for (int i=1; i < argc; i++){
      char* end;
      long val = strtol(argv[i], &end, 10);
      if (argc >= 2 && !end[0] && val >= 0){
          printf("%s is valid\n", argv[i]);
      } else {
          printf("%s is invalid\n", argv[i]);
      }
  }
  return 0;
}

Пример вывода: ./a.out 10 -1 32 1000 f -12347 +4 - 10 10rubbish

10 is valid
-1 is valid
32 is valid
1000 is valid
f is invalid
-12347 is valid
+4 is invalid
--10 is invalid
10rubbish is invalid

Это работает, потому что strtol преобразует аргумент в long int. Тогда, если end[0] не находится в конце строки, он будет отличен от нуля, то есть он выдаст ошибку для 10rubbish, но будет в порядке для значений, подобных 10. Тогда, конечно, мы хотим только положительные целые числа, и я включил значение 0 в этом наборе.

atoi () сам по себе не достаточно хорош, поскольку он возвращает ноль в случае неудачи. 0 может быть допустимым вводом.

sscanf () также сам по себе недостаточно хорош, потому что он успешно преобразует строки типа 10rubbish и возвращает значение 10.

Я понимаю, что op хочет только argv[1], этот ответ просматривает все предоставленные аргументы, чтобы показать вывод множества действительных и недействительных записей.

Поскольку вы, очевидно, не возражаете против использования стандартной библиотеки C, функция

long strtol (const char* str, char** endptr, int base)

от <cstdlib> этого вполне достаточно, чтобы аргумент командной строки представлял собой (длинное) целое число с необязательным префиксом "-" или "+" и не более того. Вам просто нужно проверить, что char * хранится в endptr на возвращаемых адресах '\0', что говорит о том, что функция использовала весь аргумент.

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])   
{
    if (argc < 2) {
        return 1;
    }

    char * endp;
    long i = strtol(argv[1],&endp,10);
    if (!*endp) {
        cout << "The value of \"" << argv[1] << "\" is " << i << endl;
        return 0;
    }
    cerr << "\"" << argv[1] << "\" is not an integer" << endl;
    return 1;
}

ПОЗЖЕ... или угождаем комментариям Стива Джессопа:

#include <cstdlib>
#include <iostream>
#include <climits>

using namespace std;

int main(int argc, char *argv[])   
{
    if (argc < 2) {
        return 1;
    }

    char * endp;
    long i = strtol(argv[1],&endp,10);

    if (*endp) {
        cerr << "\"" << argv[1] << "\" is not an integer :(" << endl;
        return 1;
    }
    if (endp == argv[1]) {
        cerr << "Empty string passed :(" << endl;
        return 1;
    }
    if (i < 0) {
        cerr << "Negative " << i << " passed :(" << endl;
        return 1;
    }
    if (i <= INT_MAX) {
        cout << "Non-negative int " << i << " passed :)" << endl;
    } else {
        cout << "Non-negative long " << i << " passed :)" << endl;
    }
    return 0;

}

Функция обертки была бы для этой степени различения. И остается тот самый крайний случай, когда ввод ULONG_MAX будет принят как LONG_MAX,

Вы можете попробовать проверить, все ли символы в argv[1] являются цифрами (возможно, с ведущим знаком минус). Проверка может быть выполнена с использованием стандартной функции библиотеки isdigit(),

http://www.cplusplus.com/reference/cctype/isdigit/

Полное решение, основанное на фактическом коде OP (также доступно на http://codepad.org/SUzcfZYp):

#include <stdio.h>          // printf()
#include <stdlib.h>         // atoi()
#include <ctype.h>          // isdigit()

int main(int argc, char *argv[])   
{ 
    if( argc != 2 ) {
        return 0;
    }

    char * pWord = argv[ 1 ];
    char c = 0;
    for( int i = 0; c = pWord[ i ], c ; ++i ) {
        if( ! isdigit( c ) ) {
            return 0;
        }
    }

    int argvNum = atoi( argv[ 1 ] );
    printf( "argc = %d, argv[ 1 ] = %s, argvNum = %d\n",
        argc, argv[ 1 ], argvNum );
}

Я новичок в C++, поэтому, пожалуйста, не обращайте на меня внимания, если это не так, но не могли бы вы сгенерировать исключение и позволить пользователю повторно исправить ввод?

Я узнал несколько способов борьбы с ошибками:

  1. Если / Остальное обработка
  2. утверждать
  3. Бросить исключение

1.IF/ELSE #include

int main(int argc, int **argv) {
    if (!isdigit(argv[1])) {
        // handle code if it's not a digit.
        return 0;
    }
}

Это, наверное, самый простой способ убедиться,


2.ASSERT #include

int main(int argc, int *argv[]) {
    assert(isdigit(argv[1]));
}

* Assert завершит программу, если argv[1] не является цифрой

3.THROW #include

using namespace std;

class Except {};

int main(int argc, int **argv) {
    try {
        isdigit(argv[1]);
        throw Except();
        // this code will not be executed
        // if argv[1] is not a digit
    }
    catch (Except) {
        cout << "argv[1] is not a digit.";
        // handle exception or rethrow
    } 
}

Определенно стоит отметить, что создание исключения создаст трассировку стека, а также не будет выполнен весь код между брошенным исключением и блоком, который перехватывает исключение.

Другие вопросы по тегам