5
\$\begingroup\$

Built so that it doesn't depend on DLLs: http://s000.tinyupload.com/?file_id=25464905355948914118

My goal is to make a console calculator with a subset of the functions that are available on a scientific calculator. This source is WIP, the dependencies that are used by this are the ones that Visual Studio 2015 gives you when you create a Win32 console app.

// MathFunction_Table.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;
//string to integer variables
string astr, bstr, cstr, r1str, r2str, stepsstr;
int a, b, c, r1, r2;
int step = 0; //steps are on 0 by default
//
//variables
int x;
string selection;
//

int main() {
    // while (true) Makes sure that it doesn't exit console application unless the user intends to
    while (true) {
        system("cls");
        cout << "\n"
            "\t \t FUNCTIONS TABLES X AND Y (Mathematics)"
            "\n"
            "\t Select:\n"
            "\n"
            "\t   Quadratic (q)\n"
            "\n"
            "\t   Linear    (l)\n"
            "\n \t \t or Quit (quit)\n"
            "\n"
            "\n --> ";
        getline(cin, selection); 

        if (selection == "quit") {
            break;
        }

        else if (selection == "q") {
            //quadratic
            system("cls");
            cout << "\n"
                "\t Quadratic: ax^2 + bx + c"
                "\n"
                "\n \t Enter value of a --> ";
            //user input for a
            getline(cin, astr);
            a = atoi(astr.c_str());  // atoi(astr.c_str()); is just a function I use to convert from string to int
            cout << "\n \t Enter value of b --> ";
            //
            //user input for b
            getline(cin, bstr);
            b = atoi(bstr.c_str());
            cout << "\n \t Enter value of c --> ";
            //
            //user input for c
            getline(cin, cstr);
            c = atoi(cstr.c_str());
            //
            //user input 2 numbers for a range of X values
            while (true) {
                cout << "\n"
                    "\t Select a range of x values to display on table ( R1 <-> x <-> R2 )\n"
                    "\n"
                    "\t *** R1 must be greater than R2. *** \n"
                    "\n"
                    "\n \t R1 --> ";
                //range
                getline(cin, r1str);
                r1 = atoi(r1str.c_str());
                cout << "\n \t R2 --> ";
                getline(cin, r2str);
                r2 = atoi(r2str.c_str());
                //steps
                cout << "\t \t Steps?\n" 
                    "\n"
                    "\t *** Make sure that R1 divided by the steps number = a whole number *** \n"
                    "\t *** otherwise it won't work!                                       *** \n"
                    "\n \t Just enter 0 if you don't need steps...\n";
                cout << "\t steps --> ";
                getline(cin, stepsstr);
                step = atoi(stepsstr.c_str());  //user input for steps
                if (r1 < r2) {
                    system("cls");
                    cout << " \n \n \t error ";
                    system("pause");
                    continue;
                }
                else {
                    break;
                }
            }
            //
            //print the table in the range
            x = r2;
            cout << "\n";
            cout << "\t-----------Table-----------\n";
            cout << endl;
            cout << "\t For the equation, " << a << "x^2 + " << b << "x + " << c << endl;
            cout << endl;
            for (x; x <= r1; x++) {
                if ( x == (r1 - r2)) {
                    x++;
                }
                x = x + step; //if there are steps, the steps will be evident if you see a difference of "step" between every X on every line
                cout << "\t X = " << x << " Y = " << (a * x * x) + (b * x) + c << endl;
                if (x == r1) {
                    cout << endl;
                    cout << "\t---------------------------\n";
                    system("pause");
                }

            }
            continue;
            //quadratic end
        }

        /*
        String to integer conversion occurs because an integer does not allow me to display error messages when there is a complicated condition
        by that I mean, I am just not bothered enough... yet.
        */ 
        else if (selection == "l") {
            //linear

            //linear end
        }

        else {
            cout << "\n \tPlease select either q or l \n \n";
            system("pause");
            continue;
        }
    }

}
\$\endgroup\$
2
  • \$\begingroup\$ "This source is WIP" Excuse my ignorance, what does this actually mean? \$\endgroup\$ Dec 26, 2015 at 2:25
  • \$\begingroup\$ WIP means "work in progress" \$\endgroup\$
    – Bizkit
    Dec 26, 2015 at 4:35

1 Answer 1

4
\$\begingroup\$

Your code has several issues that make it very hard to read.

Remove stdafx.h

Remove the #include "stdafx.h" line as that is a Windows-only precompiled header which hampers portability. Also, you aren't using any of the functionality inside that header.

Remove the global variables

//string to integer variables
string astr, bstr, cstr, r1str, r2str, stepsstr;
int a, b, c, r1, r2;
int step = 0; //steps are on 0 by default
//
//variables
int x;
string selection;
//

All of these variables are NOT necessary to have as global variables. You should always declare your variables in the smallest scope possible. This allows you to take advantage of C++'s resource management effectively while allowing you (or the programmer reading your code) to more easily identify the variables. I found myself having to scroll up and down many times throughout your code to remember what was declared where. It also has the nice effect of not cluttering the global namespace with variables.

Main function and if-elseif-else

I generally believe that the main function should be as small as possible while handling most of the I/O requests of a program. In this case, your main function houses all of the logic of the program which isn't a good thing. You can split up your main into a switch statement and have each case call a helper function to do the heavy lifting. Also, you use the following logic a lot in your program:

read an integer from input and store it in a string. Convert the string to a number

Why not wrap this up into a function?

int GetUserNum(istream &is = std::cin)
{
    string val;
    getline(is, val);
    is.ignore();
    return stoi(val);
}

You also have what's called "spaghetti logic" with all those continue and break statements. These should be replaced with do-while loops that keep prompting the user for new values if some condition isn't met. Finally, your quadratic table printing is unnecessarily complicated and filled with bugs. For example, it seems that your steps variable is to allow the x value to be incremented by some user-defined number yet you're letting x be incremented every time by the loop. This will cause you to miss some steps on the graph. Moreover, you never actually check whether r1 is cleanly divisible by steps in your code. You can express your table drawing logic in a single small loop.

for (int x = r2; x <= r1; x += steps) {
     cout << (a * x * x) + (b * x) + c << "\n";
}

After cleaning up the code a bit, your general program logic could then be this:

int GetUserNum(istream &is = std::cin)
{
    string val;
    getline(is, val);
    is.ignore(); // needed for multiple istream reads
    return stoi(val);
}

// TODO: implement
void HandleLinear()
{

}

void PrintQuadraticTable(int r1, int r2, int steps, int a, int b, int c)
{
    for (int x = r2; x <= r1; x += steps) {
        cout << (a * x * x) + (b * x) + c << "\n";
    }
}

void HandleQuadratic()
{
    cout << "A value?\n";
    int a_val = GetUserNum();

    cout << "B value?\n";
    int b_val = GetUserNum();

    cout << "C value?\n";
    int c_val = GetUserNum();

    int r1 = 0, r2 = 0;
    do {
        cout << "R1? Make sure R1 > R2\n";
        r1 = GetUserNum();

        cout << "R2?\n";
        r2 = GetUserNum();
    } while (r1 <= r2);

    int steps = 0;
    do {
        cout << "Steps? Make sure steps divides cleanly into R1.\n";
        steps = GetUserNum();
    } while (r1 % steps != 0);

    PrintQuadraticTable(r1, r2, steps, a_val, b_val, c_val);
}

int main()
{
    while (true) {
        /* Give user some prompt */
        string answer;
        getline(cin, answer);
        switch (answer) {
        default:
            cout << "Invalid option!\n";
            return 1;
        case "quit":
            cout << "Quitting\n";
            return 0;
        case "l":
            HandleLinear();
            break;
        case "q":
            HandleQuadratic();
            break;
        }
    }
}

Notice that by having a few helper functions around, we were able to:

  1. Get rid of duplicate code
  2. Remove many unnecessary comments by giving functions good, descriptive names
  3. Organize our code into logical units
  4. Keep the main function clutter-free and allow the reader to have a better idea of the high-level logic of the program.
  5. Get rid of all the global values and allow us to declare variables only when we needed to.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.