Разбор аргументов char командной строки как целочисленных с проверкой ошибок в переполнении стека

Я пытаюсь написать программу, которая принимает два целых числа в качестве аргументов командной строки. Оба значения должны быть больше 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;
}

2

Решение

В 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, если число слишком велико или слишком мало, чтобы соответствовать типу. Оба устанавливают флаг сбоя в потоке, чтобы указать ошибки.

1

Другие решения

В этом конкретном случае 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],

0

Во-первых, вы не можете использовать 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>)

0
По вопросам рекламы [email protected]