2

我正在尝试编写一个将两个整数作为命令行参数的程序。整数都需要大于 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;
}
4

3 回答 3

1

在 C++11 中有stoi, stol,stoll为此:http ://en.cppreference.com/w/cpp/string/basic_string/stol

如果字符串格式不正确,则抛出invalid_argument或异常。out_of_range

using 没有什么特别的错误atoi,除了它没有报告异常的机制,因为它是一个 C 函数。所以你只有返回值 - 问题是所有返回值atoi都是有效值,所以没有办法区分返回值 0 是正确解析“0”还是解析失败。此外, atoi 不会检查该值是否超出可用值范围。第一个问题很容易通过自己进行检查来解决,第二个问题更难解决,因为它涉及实际解析字符串 - 这首先破坏了使用外部函数的意义。

你可以istringstream这样使用:

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 覆盖,如果数字太大或太小而无法适应类型,则值将被覆盖。两者都在流上设置失败标志以指示错误。

于 2012-12-12T18:24:31.330 回答
0

在这种特定情况下,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]through接收argv[argc-1]

于 2012-12-12T18:22:00.163 回答
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(argument count) 是否大于或等于 3:

if(argc >= 3)

然后你需要把它转换成整数。如果您不想使用atoi,并且如果您没有 C++11 编译器,您应该使用 C++stringstream或 Cstrtol

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>

于 2012-12-12T18:26:53.483 回答