Я пытаюсь написать программу, которая принимает два целых числа в качестве аргументов командной строки. Оба значения должны быть больше 0. Я понимаю, что мне нужно конвертировать из char, но я только когда-либо делал это, используя atoi, что теперь я знаю, что не должен делать. Я видел, как люди используют sstreams и strtol, но я не уверен, как они будут работать в этом случае. Каков наилучший способ сделать это?
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int N = 7;
const int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if((argc != 0) && (argv[0] != NULL) && (argv[1] != NULL))
{
N = argv[0];
M = argv[1];
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" << endl;
}//Blah blah blah code here
return 0;
}
В C ++ 11 есть stoi
, stol
, stoll
за это: http://en.cppreference.com/w/cpp/string/basic_string/stol
Те бросают invalid_argument
или же out_of_range
исключения, если строка не в правильном формате.
Там нет ничего особенно плохого в использовании atoi
за исключением того, что у него нет механизма сообщения об исключениях, потому что это функция C. Таким образом, у вас есть только возвращаемое значение — проблема в том, что все возвращаемые значения atoi
являются допустимыми значениями, поэтому нет никакого способа отличить возвращаемое значение 0 от правильного анализа «0» или неудачного анализа. Кроме того, atoi не проверяет, находится ли значение за пределами доступного диапазона значений. Первую проблему легко решить, выполнив проверку самостоятельно, а вторая сложнее, поскольку она включает в себя фактический анализ строки, что в первую очередь лишает смысла использование внешней функции.
Ты можешь использовать istringstream
как это:
Pre-C ++ 11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if (iss.fail()) {
//something went wrong
} else {
//apparently it worked
}
C ++ 11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if(iss.fail()) {
if(!value) {
//wrong number format
} else if(value == std::numeric_limits<int>::max() ||
value == std::numeric_limits<int>::min()
{
//number too large or too small
}
} else {
//apparently it worked
}
Разница в том, что до C ++ 11 были обнаружены только ошибки формата (в соответствии со стандартом), а также значение «ошибка» не перезаписывалось. В C ++ 11 значения перезаписываются либо 0, если это ошибка формата, либо max / min, если число слишком велико или слишком мало, чтобы соответствовать типу. Оба устанавливают флаг сбоя в потоке, чтобы указать ошибки.
В этом конкретном случае atoi
будет работать нормально. Проблема с atoi
в том, что вы не можете различить его возвращение 0
для обозначения какой-либо ошибки и ее возврата 0
чтобы указать, что вход был 0
,
В вашем случае, однако, допустимый ввод должен быть больше 0. Вам не важно, был ли ввод 0
или что-то еще, что не может быть преобразовано. В любом случае вы устанавливаете значение по умолчанию.
Таким образом, я бы сделал что-то вроде:
int convert(char *input, int default) {
int x = atoi(input);
return x==0 ? default : x;
}
if (argc > 1)
N = convert(argv[1], 7);
if (argc > 2)
M = convert(argv[2], 8);
Обратите внимание, что argv[0]
традиционно содержит название вызываемой программы. Аргументы, переданные в командной строке, принимаются как argv[1]
через argv[argc-1]
,
Во-первых, вы не можете использовать const
квалификатор для M и N, так как вы измените их значение:
int N = 7;
int M = 8;//N is number of lines, M number of values
Во-вторых, вам не нужно проверять (argv[0] != NULL) && (argv[1] != NULL)
просто проверьте, если argc
(количество аргументов) больше или равно 3:
if(argc >= 3)
Затем вам нужно преобразовать это в целые числа. Если вы не хотите использовать atoi
и если у вас нет компилятора C ++ 11, вы должны использовать C ++ stringstream
или С strtol
stringstream ss;
int temp;
ss << argv[1]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
ss.clear(); // Clear the current content!
ss << argv[2]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
Итак, весь код будет выглядеть так:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sstream>
using namespace std;
int N = 7;
int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if(argc >= 3)
{
stringstream ss;
int temp;
ss << argv[1]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
// empty
ss.clear();
ss << argv[2]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
cout << M << " " << N;
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" <<
endl;
}//Blah blah blah code here
return 0;
}
Кроме того, заголовочные файлы C включают в себя c
префикс, а не с .h
суффикс (<cstdio>
вместо <stdio.h>
)