2011-03-04 42 views
5

我做了一個小程序,它生成素數並讓用戶檢查一個數字,看看它是否爲素數。問題是,我不確定如何正確設計它。這是程序:關於正確設計程序的疑惑C++

#include <iostream> 
#include <vector> 

typedef unsigned long long bigint; 

std::vector<bool> sieve(size_t size) 
{ 
    std::vector<bool> primelist(size); 

    primelist[0] = false; 
    primelist[1] = false; 

    for (bigint i = 2; i < size; ++i) { primelist[i] = true; } 

    for (bigint i = 2; i * i < size; ++i) 
    { 
     if (primelist[i]) 
     { 
      for (bigint j = i; j * i < size; ++j) 
       primelist[i*j] = false; 
     } 
    } 

    return primelist; 
} 

int main() 
{ 
    bigint range; 
    bigint number; 
    std::vector<bool> primes; 

    std::cout << "Enter range: " << std::endl; 
    std::cin >> range; 

    primes = sieve(range); 

    while (1) 
    { 
     std::cout << "Enter number to check: " << std::endl; 
     std::cin >> number; 

     if (primes[number]) 
      std::cout << "Prime" << std::endl; 

     else 
      std::cout << "Not prime" << std::endl; 
    } 

    return 0; 
} 

的基本流程我要實現的是:輸入範圍,/處理輸入/輸入號碼查詢,/處理輸入/

我也想給用戶一個選擇在任何給定的時間,通過寫命令狀「變化範圍」更改範圍

我有幾個問題是:

我想如果用戶輸入的程序已得到控制範圍更大如果用戶基本上超過任何限制(例如,如果他輸入的範圍是100,那麼如果他檢查101),將會捕獲異常。我知道這需要使用try/catch/throw來實現,但我不知道如何做到這一點,同時保持選項來改變範圍,而不需要使我的代碼意大利麪代碼。

另外,我想這些錯誤是枚舉類型的(我讀的枚舉是良好的例外),像

enum errors 
{ 
    OUT_OF_RANGE = 1, //Out of the range specified by the user 
    INCORRECT_VALUE, //If user input "one" instead of 1 
    RANGE_SIGNED,  //If user inputs a signed value for range 
    NUM_LIMITS  //Number exceeds unsigned long long 
}; 

我不知道如何使用異常處理,而不是用它來提與枚舉。我該如何保持這個程序的安全和運行,同時遠離意大利麪代碼?

我非常困惑。如果有人能夠幫助我正確地設計這個程序,並保持可讀性和效率,它將真正改進我未來的程序設計。

感謝您的閱讀!

+5

專注於* one *的東西,爲了學習;這也將幫助你的問題得到答案。 – Jon 2011-03-04 18:33:28

+4

「我讀過枚舉對異常很有用......」,而不是'std :: exception'? – 2011-03-04 18:35:30

+0

@Jon這是我混亂的副作用。我一直遇到涉及用戶輸入的程序問題。我真的需要有人幫助我理解這一切。 @Travis我不知道std :: exception是什麼。我讀過關於異常處理的知識,但我不太瞭解。剛剛變得更加困惑。 – Lockhead 2011-03-04 18:35:35

回答

1

你問了很多。

您想驗證用戶輸入。用戶不應該輸入大數字,非整數等。

我打算回答這絕對不是應該使用例外情況。例外情況用於處理例外的情況。這些是你無法預期或者真正處理的。

用戶輸入的號碼太大?你可以處理。告訴他們他們的號碼太大,請輸入一個介於1和X之間的數字。

用戶輸入單詞apple?你可以處理。告訴他們他們只能輸入整數。

這樣做的一種方法是製作ValidateInput函數。你可以讓它返回一個數字(或一個枚舉,它們基本上是一樣的)來告訴你是否有錯誤。

爲了進行驗證,您很可能必須接收std::string的輸入,然後在將其轉換爲數字之前對其進行驗證。輸入爲unsigned int或類似的整數類型並不能真正讓你檢查錯誤。

這增加了一些工作,因爲您需要手動手動驗證輸入。有些函數庫可以幫助你做到這一點,比如boost::lexical_cast,但是現在對你來說可能太多了。

下面是一些非常基本的僞代碼來說明我的意思。它只是爲了讓你知道該怎麼做,它不會爲你編譯或做這項工作。您可以通過製作一個基於錯誤代碼等返回消息的泛型函數來進一步擴展它。

enum error_code { 
    SUCCESS,   // No error 
    OUT_OF_RANGE,  // Out of the range specified by the user 
    INCORRECT_VALUE, // If user input "one" instead of 1 
    RANGE_SIGNED,  // If user inputs a signed value for range 
    NUM_LIMITS  // Number exceeds unsigned long long 
}; 

// This function will check if the input is valid. 
// If it's not valid, it will return an error code to explain why it's invalid. 
error_code ValidateInput(const std::string& input) { 
    // Check if input is too large for an unsigned long long 
    if (InputIsTooLarge) 
    return NUM_LIMITS; 
    // Check if input is negative 
    if (InputIsNegative) 
    return RANGE_SIGNED; 
    // Check if input is not an integer 
    if (InputIsNotInteger) 
    return INCORRECT_VALUE; 
    // If we make it here, no problems were found, input is okay. 
    return SUCCESS; 
} 

unsigned long long GetInput() { 
    // Get the user's input 
    std::string input; 
    std::cin >> input; 

    // Check if the input is valid 
    error_code inputError = ValidateInput(input); 

    // If input is not valid, explain the problem to the user. 
    if (inputError != SUCCESS) { 
    if (inputError == NUM_LIMITS) { 
     std::cout << "That number is too big, please enter a number between " 
     "1 and X." << std::endl; 
    } 
    else if (inputError == RANGE_SIGNED) { 
     std::cout << "Please enter a positive number." << std::endl; 
    } 
    else if (inputError == INCORRECT_VALUE) { 
     std::cout << "Please enter an integer." << std::endl; 
    } 
    else { 
     std::cout << "Invalid input, please try again." << std::endl; 
    } 

    // Ask for input again 
    return GetInput(); 
    } 
    // If ValidateInput returned SUCCESS, the input is okay. 
    // We can turn it into an integer and return it. 
    else { 
    return TurnStringIntoBigInt(input); 
    } 
} 

int main() { 
    // Get the input from the user 
    unsigned long long number = GetInput(); 

    // Do something with the input 
} 
+0

如果無法預料或處理異常,爲什麼該語言具有「catch」關鍵字? – aaz 2011-03-05 00:11:22

+0

一個公平的問題,但有點含糊。在這裏,請閱讀。 http://www.boost.org/community/error_handling.html – 2011-03-05 12:33:25

+0

這是創建交互式程序的最佳方式嗎? – Lockhead 2011-03-06 08:34:56

1

我喜歡Dauphic的回答,特別是因爲它說明了將問題分解爲多個部分並逐個解決問題。我會,但是,確實GetInput稍有不同:

unsigned long long GetInput() { 
    // Get the user's input 
    std::string input; 

    error_code inputError; 
    // Repeatedly read input until it is valid 
    do { 
    std::cin >> input; 
    inputError = ValidateInput(input); 

    if (inputError == NUM_LIMITS) { 
     std::cout << "That number is too big, please enter a number between " 
     "1 and X." << std::endl; 
    } 
    // ...handle all other cases similarly 
    } while(inputError != SUCCESS); 

    // If ValidateInput returned SUCCESS, the input is okay. 
    // We can turn it into an integer and return it. 
    return TurnStringIntoBigInt(input); 
} 

遞歸的解決方案是好的,但有,好,是遞歸的和不斷增長的堆棧中的缺點。在這種情況下,這可能不是什麼大問題,但這是需要注意的。

至於如何編寫ValidateInput,基本上你會掃描字符串中的無效字符,如果沒有找到,檢查該值是否適合你選擇的整數類型,直到用例如一個變量讀入變量爲止。 >>

備註:此解決方案存在嚴重缺陷,因爲它不檢查std::cin的狀態。如果用戶要通過EOF,即按^ D,則程序會卡在循環中,這不是很好的行爲。

+0

謝謝!如何檢查用戶是否通過EOF? – Lockhead 2011-03-14 21:12:50

+0

查看例如「std :: ios」文檔。在那裏:) – Ilkka 2011-03-15 16:34:23

0

而不是一個向量布爾你最好使用bitset 這樣,你可以使用Eratosthene方法來確定一個數是否爲素數。