I am in my first semester of computer program and this my third project. I am taking this class online so I do not have the in-class benefit of working with others. I have completed all of the code and the program works the way I believe it should. I would just like some more experienced eyes to glance over and offer any advice, either conceptual or functional, or point out any code that may cause some issues, thanks in advanced. (Also, I know from other threads "using namespace std;" is not the preferred way, but my professor prefers it.)

//Algorithm:
// 1. Prompt user and get problem selection using choice function
// 2. If case 1, get x-y coordinates from points one and two using reference 
//    function
// 3. Display two-point line formula from reference function
// 4. Perform two-point line equation using formula and reference functions
// 5. Display Slope-Intercept line form using formula function from reference
//    functions
// 6. If case 2, get line slope and x-y coordinates using reference function
// 7. Display Point-Slope line form from reference function
// 8. Perform point-slope line equation using value returning formula function
//    and reference functions
// 9. Display Slope-Intercept line form using formula function from reference
//    function
//10. Prompt user to determine if they want to continue program
//11. If yes, repeat functions. If no, terminate program

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

void getProblem ();//non-value returning function
void get2Pt (double& u1, double& u2, double& u3, double& u4);//non-value returning function
void display2Pt (double u1, double u2, double u3, double u4);//non-value returning function
void slpIntForm2Pt (double s1, double s2, double s3, double s4, double& m,
     double& b); //non-value returning function
void getPtSlp (double& m, double& t1, double& t2);//non-value returning function
void displayPtSlp (double m, double t1, double t2);//non-value returning function
double slpIntFromPtSlp (double m, double t1, double t2);//value returning function
void displaySlpInt (double m, double b);//non-value returning function


int main ()
{    
   double x1, y1;//Set variables
   double x2, y2;
   double m, b;
   int choice;
   char ans;

   cout << fixed << showpoint << setprecision (2);//Set precision

    do//Program menus
    {               
        getProblem ();//Call menu function        
        cin >> choice;//Input choices
        cout << endl;

        switch (choice)
        {
            case 1://Selection one from menu function

                get2Pt (x1, y1, x2, y2);//Function call
                display2Pt (x1, y1, x2, y2);//Function call
                slpIntForm2Pt (x1, y1, x2, y2, m, b);//Function call
                displaySlpInt (m, b);//Function call

                break;

            case 2://Selection two from menu function  

                getPtSlp (m, x1, y1);//Function call
                displayPtSlp (m, x1, y1);//Function call
                b = slpIntFromPtSlp (m, x1, y1);//Function call
                displaySlpInt (m, b);//Function call

                break;                

            default:
                cout << "Invalid input, please try again.\n" << endl;            
        } 
                cout << "Do you want to do another conversion? Enter Y for yes "
                     << "or N for no: ";   
                cin >> ans;
                cout << endl;
    }   

    while (ans == 'y' || ans == 'Y');
    {
        cout << "Have a great day!" << endl;
    }            

    return 0;
}

void getProblem ()//Starting menu function
{
    cout << "Select the form that you would like to convert to " 
         << "slope-intercept form:" << "\n" << endl;
    cout << "1: Two-Point form (Must know two points of the line)" << endl;
    cout << "2: Point-Slope form (Must know the line's slope and on point "
         << "on the line)" << endl;
}

void get2Pt (double& u1, double& u2, double& u3, double& u4)//Reference function
{
    cout << "Enter x-y coordinates for point one separated by a space: ";
    cin >> u1 >> u2;
    cout << endl;

    cout << "Enter x-y coordinates for point two separated by a space: ";
    cin >> u3 >> u4;
    cout << endl;
}

void display2Pt (double u1, double u2, double u3, double u4)//Display function for get2Pt
{
    cout << "Two-Point Form" << endl;
    cout << "m = ";
    if (u2 < 0)
    {
       cout << "(" << u4 << " + " << abs(u2) << ")/"; 
    }
    else
        cout << "(" << u4 << " - " << u2 << ")/";
    if (u1 < 0)
    {
        cout << "(" << u3 << " + " << abs(u1) << ")\n" << endl;
    }
    else
         cout << "(" << u3 << " - " << u1 << ")\n" << endl;     
}

void slpIntForm2Pt (double s1, double s2, double s3, double s4, double& m,
     double& b)//Formula Function for get2Pt
{
    m = (s4 - s2)/(s3 - s1);
    b = s2 - (m * s1);
}

void displaySlpInt (double m, double b)//Display function for both formula functions
{
    cout << "Slope-Intercept Form" << endl;  

    if (b > 0)
    {
       cout << "y = " << m << "x + " << b << "\n" << endl; 
    }
    else
        cout << "y = " << m << "x " << b << "\n" << endl;
}

void getPtSlp (double& m1, double& t1, double& t2)//Reference Function
{
    cout << "Enter the Slope of the Line: ";
    cin >> m1;
    cout << endl;

    cout << "Enter the x-y coordinates: ";
    cin >> t1 >> t2;
    cout << endl;
}

void displayPtSlp (double m, double t1, double t2)//Display Function from getPtSlp
{
    cout << "Point-Slope Form" << endl;

    if (t1 < 0 && t2 < 0)
    {
        cout << "y + " << abs(t2) << " = " << m << "(x + " << abs(t1) << ")\n"
             << endl;   
    }
    else if (t1 < 0)
    {
        cout << "y - " << t2 << " = " << m << "(x + " << abs(t1) << ")\n"
             << endl;   
    }
    else if (t2 < 0)
    {
        cout << "y + " << abs(t2) << " = " << m << "(x - " << t1 << ")\n"
             << endl;   
    }
    else
        cout << "y - " << t2 << " = " << m << "(x - " << t1 << ")\n" << endl;
} 

double slpIntFromPtSlp (double m, double t1, double t2)//Value function for getPtSlp
{
    double b;

    b = t2 - (m * t1);
    return (b);
}

Building it with the following set of warning switches:

-Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Waggregate-return -Wcast-align -Wcast-qual -Wconversion -Wdisabled-optimization -Werror -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winline -Winvalid-pch -Wlong-long -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpadded -Wpointer-arith -Wredundant-decls -Wshadow -Wstack-protector -Wstrict-aliasing=2 -Wswitch-default -Wswitch-enum -Wunreachable-code -Wunused -Wunused-parameter -Wvariadic-macros -Wwrite-strings

gives only a slight whinge about the function setprecision on line 43, which is as much about the return type from that function being unspecified in the standard as anything else, and running your program under valgrind gives a clean bill of health, so frankly you're already in the top ten percent of C++ programmers :)

Thank you for checking it out. Concerning line 43, is there a better or more preferred way to acomplish precision? What are the draw-backs to the way it is written now?

To some extent, it's just the compiler being really manic because all the warnings are turned on. If you look up function call has aggregate value you can read about the meaning of the warning (and it's interesting to find something with an unspecified return type). It could be silenced by using
cout.precision(2);
instead, but it's really not a problem.

While the program looks good functionally, I would like to make some stylistic suggestions.

  1. You generally want to separate the functions which operform computation from those which do input and output. This principle of decoupling serves to make the program more modular and easier to fix and modify. Separating model from presentation is an important factor in making code reusable, as well, and thus it is a good habit to get into.

  2. The opposite principle, encapsulation, says that whenever possible, related data should be bundled together into a composite structure, and that the operations on the data structure should be bundled with it as well. Again, this makes the code more modular, by separating concerns. If you have covered structs or classes in your coursework, it would make sense to define a Coordinate structure (either a struct or a class) which can be passed around and operated on as a unit.

  3. It is much, much better to use explicit function returns rather than passing values back via reference parameters; it makes it clearer what the purpose and value of the function is if the function is returning a value explicitly. Reference passing of return values is based on side effects, and often opaque ones at that; unless you thoroughly document the reference side effect, future maintainers may not even notice it, and even then misunderstandings tend to creep in. This makes for another reason to bundle the data into structures - you can pass a compound structure via function return, making multiple valued returns unnecessary in most cases.

  4. You generally want to separate the functions implementing the actual operations from the program as a whole, especially if you are defining a data structure and functions/methods to operate upon it. The general practice is to put the struct/class definitions and function prototypes in a header file, and the actual functions in a separate implementation file, then link them together with the main program only after they are finished.

I definitely understand the concepts that you are talking about but we have not yet covered struct or class, nor have we covered explicit functions yet (at least it does not sound familiar). It sounds though that those concepts help create a cleaner more efficient code. The one thing I think I can do, if I understand it correctly, is order my functions in an order use (ie. reference, display, or formulas)

By explict function, all I mean is a function which explicitly returns a value. For example:

int foo(int bar)
{
    return 23 * bar;
}

which would be used like so:

int quux;

quux = foo(17);    // quux now assigned the value 23 * 17 == 391

It is related to why most procedural sub-routines are referred to as 'functions' in the first place: a function with a return value is conceptually and semantically similar to a mathematical function (though they aren't strictly the same thing; a mathematical function defines a relationship between its domain and its co-domain, while a C++ function defines a computation that returns a value).

As for compound data structures, I can see that you haven't covered them, which means that it probably means that you aren't free to use them for this project; however, I can explain them ahead of time for you so you will have a bit of a leg up when you do cover them.

In C++, struct and class are basically the same, except for the visibility of the members; however, structs are usually used for POD (Plain Old Data, that is, member variables but not member functions). For this reason, I'll cover structs first, then shift to classes afterwards.

A struct basically is a name for a group of related variables. Unlike an array, which is homogeneous (that is, every element is the same type) and indexed (i.e., the elements are referred to by number rather than name), a struct's member variables are named, and can be of different types. For your particular case, you would probably want to define a Point2D type, and then use that to define a Line2D type.

struct Point2D
{
   double x, y;
};

struct LineSegment2D
{
    Point2D start, end;
};

The member variables can be accessed using the member reference operator (or dot operator, .), like so:

LineSegment2D line_1;
line_1.start.x = 2.0;
line_1.start.y = 1.1;
line_1.end.x = 4.5;
line_1.end.y = 3.8;

How you could apply this to re-writing your functions might go like so:

LineSegment2D* getLineSegment() //Reference function
{
    LineSegment2D* line = new LineSegment2D();

    cout << "Enter x-y coordinates for the start point: ";
    cin >> line->start.x >> line->start.y;
    cout << endl;
    cout << "Enter x-y coordinates for end point: ";
    cin >> line->end.x >> line->end.y;
    cout << endl;

    return line;
}

You'll notice that the syntax has changed slightly here; this is because we are returning a pointer to a dynamically allocated struct, which means that instead of the member reference operator, we need to use the member indirection operator, (->) for the part that is actually the pointer. You can then get the pointer to this newly allocated LineSegment2D variable like so:

LineSegment2D* line = getLineSegment();

However, you will need to remember to free the allocated memory aafterwards when you are finished with that structure:

delete line;

Now, you might ask, why use a pointer and allocate the structure on the heap like this, rather than just passing the result back? The reason is because structs cannot be passed back as values, and since local variables are allocated on the stack and then deallocated when the function returns, a reference to a struct that is local to the function would end up pointing to invalid memory. Thus, we need to allocate a fresh struct from free memory, which can be passed around as a pointer and accessed even long after the function that built it closed.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.