繁体   English   中英

关于正确设计程序C ++的困惑

[英]Confusion about correct design of a program 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;
}

我想要实现的基本流程是:输入范围,/句柄输入/,要检查的输入数,/句柄输入/

我还希望通过编写“更改范围编号 ”之类的命令,为用户提供在任何给定时间更改范围的选项

我有一些问题:

如果用户输入大于无符号long long的范围,并且如果用户基本上超过任何限制(例如,如果他输入的范围是100,那么如果他检查101),我希望程序受到控制,异常将是抓住。 我知道这需要使用try / catch / throw来实现,但是我不知道如何在保持选项更改范围的同时不使用我的代码spaghetti代码。

此外,我希望错误是枚举类型(我读到枚举适用于异常),类似于

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
};

我不知道如何使用异常处理,更不用说使用枚举。 我该如何保持这个程序的安全和运行,同时远离意大利面条代码?

我非常困惑。 如果有人可以帮我正确设计这个程序并保持可读性和效率,它将真正改善我未来的程序设计。

谢谢阅读!

你问了很多。

您想验证用户输入。 用户不应该输入大数字,非整数等。

我将首先回答这绝对不是应该使用异常的情况。 例外用于处理特殊情况。 这些是你无法预料或真正处理的。

用户输入的数字太大了? 你可以处理。 告诉他们他们的号码太大,请输入介于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
}

我喜欢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,程序将陷入循环,这不是好行为。

而不是bool的矢量你最好使用bitset ,你可以使用Eratosthene方法来确定数字是否为素数。

暂无
暂无

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

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