繁体   English   中英

在C ++中使用错误检查将命令行char参数解析为int

[英]Parsing command line char arguments as ints with error checking in C++

我正在尝试编写一个将两个int作为命令行参数的程序。 两个整数都必须大于0。我知道我需要从char转换,但是我只使用过atoi来做到这一点,而现在我知道我不应该这样做。 我已经看到人们使用sstream和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中, stolstoistolstollhttp : stoll

如果字符串格式不正确,则会抛出invalid_argumentout_of_range异常。

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

在这种情况下, 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[argc-1]作为argv[1]接收。

首先,您不能对M和N使用const限定词,因为您将更改它们的值:

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或C的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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM