Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about correct design of a program C++

Tags:

c++

I made a small program that generates primes and lets the user check a number and see if it's a prime or not. Problem is, I'm not sure how to properly design it. This is the program:

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

The basic flow I want to achieve is: Input range, /handle input/, input number to check, /handle input/

I also want to give the user an option to change the range at any given time, by writing a command like "change range number"

I have a few problems with this:

I want the program to be under control if the user inputs a range bigger than unsigned long long, and if the user basically exceeds any limit(like for example if the range he input was 100 then if he checks for 101) an exception will be caught. I know this needs to be implemented using try/catch/throw, but I have no idea how to do that while keeping the option to change the range and without making my code spaghetti code.

Also, I want the errors to be of enum type(I read that enums are good for exceptions), something like

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

I have no idea how to use exception handling, not to mention using it with enums. How the hell do I keep this program safe and running, while keeping away from spaghetti code?

I am extremely confused. If someone could help me design this program correctly and maintain readability and efficiency, it will really improve my future program designs.

Thanks for reading!

like image 331
Lockhead Avatar asked Nov 05 '22 01:11

Lockhead


1 Answers

You asked a lot.

You want to validate user input. Users should not be able to enter huge numbers, non-integers, and so on.

I'm going to start off by answering that this is absolutely not a scenario that exceptions should be used for. Exceptions are used to handle exceptional circumstances. These are ones you can't anticipate or really deal with.

A user enters a number that's too big? You can handle that. Tell them that their number is too big, please enter a number between 1 and X.

A user enters the word apple? You can handle that. Tell them that they can only enter integers.

One way of doing this would be to make a ValidateInput function. You can have it return a number (or an enum, they're basically the same thing) to tell you whether there was an error.

In order to do the validation, you will most likely have to receive input as an std::string and then validate it before turning it into a number. Getting input as an unsigned int or similar integral type doesn't really allow you to check for errors.

This adds a bit of work, since you need to manually validate the input manually. There are libraries with functions to help with this, such as boost::lexical_cast, but that's probably too much for you right now.

Below is some very basic psuedo code to illustrate what I mean. It's only meant to give you an idea of what to do, it won't compile or do the work for you. You could extend it further by making a generic function that returns a message based on an error code and so on.

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
}
like image 74
Collin Dauphinee Avatar answered Nov 12 '22 12:11

Collin Dauphinee