簡體   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