Menu functions and passing user input between functions

Hello!

** PLEASE DON'T JUST GIVE ME AN ANSWER, THIS IS FOR UNI AND I DON'T WANT TO CHEAT BUT SINCE I STUDY WHILE TRAVELLING IT'S HARD TO DISCUSS WITH CLASS MATES ***

So, we have an assignment where the mission is to make a program which measures the execution time of two different approaches to get fibonacci numbers.


Iteration:
1
2
3
4
5
6
7
8
9
  long_type fibonacciIteration(size_t nthNumber) {
    size_t x = 0, y = 1, z = 0;
    for (size_t i = 0; i < nthNumber; i++) {
        z = x + y;
        x = y;
        y = z;
    }
    return x;
}


Recursion:
1
2
3
4
5
long_type fibonacciRecursion(size_t nthNumber) {
    if (nthNumber <= 1)
        return nthNumber;
    return fibonacciRecursion(nthNumber - 1) + fibonacciRecursion(nthNumber - 2);
}


The thing is we're supposed to have a menu with 5 different options:

1. Submenu
2. Timer
3. Print stats
4. Write to file
5. Exit

If I understand the assignment correctly the submenu is just for user input.

My code so far looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void mainMenu()
{
    bool AGAIN = true;
    do
    {
        showMenu();
        char choice;
        cout << endl << "Make your choice: ";
        cin >> choice;

        switch(choice)
        {
            case '1': subMenu();
            break;

            case '2' : fibonacciTimer();
            break;

            case '3' : printStats();
            break;

            case '4' : writeToFile();
            break;

            case '5' :
            case 'q' :
            case 'Q' : AGAIN = false;

        }
    } while (AGAIN);
}

//---------------------------------------------------------------------------
// ShowMenu
//---------------------------------------------------------------------------
void showMenu()
{
    cout << "1. SubMenu" << endl;
    cout << "2. Fibonacci Timer" << endl;
    cout << "3. Print Stats" << endl;
    cout << "4. Write to file" << endl;
    cout << "5. Exit" << endl;
}

//---------------------------------------------------------------------------
// subMenu
//---------------------------------------------------------------------------
size_t subMenu()
{
    size_t nthNumber;
    cout << "Choose your number!" << endl;
    cin >> nthNumber;
    return nthNumber;
}


Now I want this to return to the main menu to be used for the other options (which I haven't started with yet, so that's a whole other problem)

Have I done anything wrong? I guess when I get "nthNumber" back to mainMenu() I want to be able to put it in either the recursion function or the iteration function to be measured by the fibonacciTimer function?

C++ is H A R D.
Last edited on
seatea wrote:
Have I done anything wrong?


Yes, you have tried to develop the whole thing in one go.

Develop it in stages - one item at a time. Test each function or menu item as you add it.

I doubt that I'm the only one who has qualms about venturing advice about something they can't test. You haven't provided (and possibly don't actually have) complete runnable code.

Ah, fair enough!

I'll write more when I have more code to work with!
When you get your code running, you have a choice to make:
- the more old fashioned way: http://www.cplusplus.com/reference/ctime/clock/
- the more modern way: http://www.cplusplus.com/reference/chrono/duration/

There are a couple more possibilities, but probably reading up on these will be a good start.
When you get your code running, you have a choice to make:
- the more old fashioned way: http://www.cplusplus.com/reference/ctime/clock/
- the more modern way: http://www.cplusplus.com/reference/chrono/duration/

There are a couple more possibilities, but probably reading up on these will be a good start.


We have to use chrono in this assignment, so I'll definitely read up on that, thanks!

I just have to understand all the instructions first and get all the functions going and then we are off!
Consider:
lastchance wrote:
seatea wrote:
Have I done anything wrong?


Yes, you have tried to develop the whole thing in one go.


Don't make the same mistake, instead consider what is the minimal requirement for getting your program to compile and run. And then try to understand only the instructions for the first step.

In this case, I think a couple of placeholder/empty functions like
1
2
3
4
void printStats()
{
     cout << "some statistic is required here. (printStats still has to be implemented)" << endl;
}

would do the trick.

As soon as you can run your program, you can implement the small parts of it with correct implementations one at a time. Just make sure you can't forget any (for example by making them print that you still have to update them and/or by sticking to the logical order).
Last edited on
Ok, I'm really stuck.

Wall of text (and code) incomming!

So, we have two .cpp files and two .h files to work with:

main.cpp is just allowed to call the main menu function:

Main.cpp
1
2
3
4
5
6
7
#include Prototypes.h
using namespace std;

int main() {
     mainMenu();
    return 0;
}


Definitions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "Prototypes.h"
using namespace std;

//------------------------------------------------------------------------------
// Name: fibonacciIteration
//------------------------------------------------------------------------------
long_type fibonacciIteration(size_t nthNumber) {
    size_t x = 0, y = 1, z = 0;
    for (size_t i = 0; i < nthNumber; i++) {
        z = x + y;
        x = y;
        y = z;
    }
    return x;
}

//------------------------------------------------------------------------------
// Name: fibonacciRecursion
//------------------------------------------------------------------------------
long_type fibonacciRecursion(size_t nthNumber) {
    if (nthNumber <= 1)
        return nthNumber;
    return fibonacciRecursion(nthNumber - 1) + fibonacciRecursion(nthNumber - 2);
}

//------------------------------------------------------------------------------
// Name: mainMenu
//------------------------------------------------------------------------------
void mainMenu()
{
    bool AGAIN = true;
    do
    {
        showMenu();
        char choice;
        cout << endl << "Make your choice: ";
        cin >> choice;

        if (choice == '1')
        {
            subMenu();
        } else if (choice == '2')
        {
            AGAIN = false;
        } else
        {
            mainMenu();
        }

    } while (AGAIN);
}

//------------------------------------------------------------------------------
// Name: fibonacciTimer
//------------------------------------------------------------------------------
std::vector<Stats> fibonacciTimer(size_t nthNumber);
{ 
    (PSEUDO CODE)

    REPEAT {
    DETERMINE type of approach
    SET Stats.type
            MARK start time
    REPEAT {
    CALL appropriate Fibonacci function
    ADD Fibonacci value to Stats container
    FOR EACH 5th sequence OUTPUT information on screen**
    } IF iteration IS NOT 0*
    MARK end time
            CALCULATE duration of all needed formats
            SET duration for relevant Stats members
    } FOR each Fibonacci approach
    RETURN container filled with two Stats objects
}

//------------------------------------------------------------------------------
// Name: showMenu
//------------------------------------------------------------------------------
void showMenu()
{
    cout << endl;
    cout << "==== MAIN MENU ====" << endl;
    cout << "1. SubMenu" << endl;
    cout << "2. Exit" << endl;
}

//------------------------------------------------------------------------------
// Name: subMenu
//------------------------------------------------------------------------------
size_t subMenu()
{
    size_t nthNumber;
    cout << "Choose your number!" << endl;
    cin >> nthNumber;
    return nthNumber;
}

//------------------------------------------------------------------------------
// Name: printStats
//------------------------------------------------------------------------------
int printStats(const std::vector<Stats>& stats)
{
    cout << "Some code here later" << endl;
}

//------------------------------------------------------------------------------
// Name: writeToFile
//------------------------------------------------------------------------------
void writeToFile(const Stats& stats)
{
    cout << "Some code here later" << endl;
}


Prototypes.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Stats.h"
#include <iostream>
#include <chrono>
#include <limits>
#include <iomanip>
#include <fstream>

long_type fibonacciIteration(size_t nthNumber);
long_type fibonacciRecursion(size_t nthNumber);
std::vector<Stats> fibonacciTimer(size_t nthNumber);

void printStats(const std::vector<Stats>& stats);
void writeToFile(const Stats& stats);

void mainMenu();
size_t subMenu();
void showMenu();


Stats.h
1
2
3
4
5
6
7
8
9
10
11
#include <string>
#include <vector>

typedef unsigned long long long_type;

struct Stats {
    std::string type;
    std::vector<long_type> values;
    long_type nanosec=0, microsec=0, millisec=0;
    double sec=0;
};


If I understand the assignment correctly the mainMenu is where it's all happening. If you press 1, you go to subMenu where you can insert a number which should be stored in mainMenu and then used in either fibonacciIteration or fibonacciRecursion, depending on what the user chooses.

After all this, you're supposed to be able to actually print the results or write it to a .txt file.

I don't understand the pseudo code for the fibonacciTimer, I don't understand how to get the functions to do what I want.

I've been doing this assignment for 4 days and all I have to show for it is a faulty menu..
Take a deep deep breath and do the job in small steps as advised earlier.

You can start in a number of places:

1a If you start with the menu then just make a workable menu system and print out stubs, which means if you press button 3 it goes to part 3 of the menu, and prints out "This is a stub to the xyz function" and goes no further.

1b Then and only then, once you have all the stubs in place, go to each and connect up to the relevant function when it's been tested and working.

OR,

2a Work separately with each function and do the menu later.
2b Keep each function and its main()unit tester separate from everything else.
2c Then and only then incorporate each function in the consolidated file.
2d Then do the menu as above, filling in the stubs.

Treat the menu as minimally functional as possible. Keep it separate from the real functionality which is the ... function(). All the menu should do is direct traffic. When the particular job is finished at the sharp end, action goes back to the (dumb) menu.

A flowchart/arrow diagram/whatever on paper is not a bad idea to keep track because even simple stuff gets overwhelming and nobody is immune to that when it comes to menus.

A lot of menus return void. There's often a lot to be gained by having a menu that returns the number/letter selected by the uses.


Have a look at this code and comments.
I would suggest you now focus on the fibonacciTimer function, until that works.
When the fibonacciTimer function should work, implement the printStats function to check it.

main.cpp
1
2
3
4
5
6
7
8
#include "Prototypes.h"

using namespace std;

int main() {
     mainMenu();
    return 0;
}


Definitions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "Prototypes.h"

using namespace std;

//------------------------------------------------------------------------------
// Name: fibonacciIteration
//------------------------------------------------------------------------------
long_type fibonacciIteration(size_t nthNumber) {
    size_t x = 0, y = 1, z = 0;
    for (size_t i = 0; i < nthNumber; i++) {
        z = x + y;
        x = y;
        y = z;
    }
    return x;
}

//------------------------------------------------------------------------------
// Name: fibonacciRecursion
//------------------------------------------------------------------------------
long_type fibonacciRecursion(size_t nthNumber) {
    if (nthNumber <= 1)
        return nthNumber;
    return fibonacciRecursion(nthNumber - 1) + fibonacciRecursion(nthNumber - 2);
}

//------------------------------------------------------------------------------
// Name: mainMenu
//------------------------------------------------------------------------------
void mainMenu()
{
    bool AGAIN = true;
    size_t choosenNumber = 0;
    do
    {
        showMenu();
        char choice;
        cout << endl << "Make your choice: ";
        cin >> choice;

        switch(choice)
        {
            case '1':   choosenNumber = subMenu();                              /// <- it is pointless to ask the user for a number if you are not going to remember it
                        break;

            case '2' :  fibonacciTimer( choosenNumber );                        /// <- restore the switch-case and provide the choosenNumber variable as the argument
                        break;                                                  /// <- restore the switch-case

            case '3' :  printStats( fibonacciTimer(choosenNumber) );            /// <- restore the switch-case and provide vector from fibonacciTimer as the argument using the choosenNumber variable
                        break;                                                  /// <- restore the switch-case

            // case '4' :  writeToFile();                                       /// I don't think you want to have this as an menu option, I expect this function should be called from the print function.
            // break;

            case '5' :                                                          /// <- restore the switch-case
            case 'q' :                                                          /// <- restore the switch-case
            case 'Q' :  AGAIN = false;                                          /// <- restore the switch-case
                        break;
            default:    break;                                                  /// <- in a switch-case, always try to define a default option to make it clear what happens with other input values. in this case nothing
        }
    } while (AGAIN);
}

//------------------------------------------------------------------------------
// Name: fibonacciTimer
//------------------------------------------------------------------------------
std::vector<Stats> fibonacciTimer(size_t nthNumber)                             /// <- remove ; here
{                                                                               /// <- pseudo code is not C++, it is a description of what you should implement in this function.
    std::vector<Stats> tempVector;                                              /// <- For now: comment the pseudo code out and make the function return an empty vector
/*
    (PSEUDO CODE)

    REPEAT {
    DETERMINE type of approach
    SET Stats.type
            MARK start time
    REPEAT {
    CALL appropriate Fibonacci function
    ADD Fibonacci value to Stats container
    FOR EACH 5th sequence OUTPUT information on screen**
    } IF iteration IS NOT 0*
    MARK end time
            CALCULATE duration of all needed formats
            SET duration for relevant Stats members
    } FOR each Fibonacci approach
    RETURN container filled with two Stats objects
*/
    return tempVector;
}

//------------------------------------------------------------------------------
// Name: showMenu
//------------------------------------------------------------------------------
void showMenu()
{
    cout << endl;
    cout << "==== MAIN MENU ====" << endl;
    cout << "1. SubMenu" << endl;
    cout << "2. Fibonacci Timer" << endl;                                       /// <- restore this option
    cout << "3. Print Stats" << endl;                                           /// <- restore this option
    // cout << "4. Write to file" << endl;                                      /// I don't think you want to have this as an menu option, I expect this function should be called from the print function.
    cout << "5. Exit" << endl;                                                  /// <- restore this option
}

//------------------------------------------------------------------------------
// Name: subMenu
//------------------------------------------------------------------------------
size_t subMenu()
{
    size_t nthNumber;
    cout << "Choose your number!" << endl;
    cin >> nthNumber;
    return nthNumber;
}

//------------------------------------------------------------------------------
// Name: printStats
//------------------------------------------------------------------------------
void printStats(const std::vector<Stats>& stats)                                     /// <- Correct int printStats to void printStats to match the declaration in the Prototypes header
{
    cout << "Some code here later" << endl;
}

//------------------------------------------------------------------------------
// Name: writeToFile
//------------------------------------------------------------------------------
void writeToFile(const Stats& stats)
{
    cout << "Some code here later" << endl;
}


Prototypes.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Stats.h"
#include <iostream>
#include <chrono>
#include <limits>
#include <iomanip>
#include <fstream>

long_type fibonacciIteration(size_t nthNumber);
long_type fibonacciRecursion(size_t nthNumber);
std::vector<Stats> fibonacciTimer(size_t nthNumber);

void printStats(const std::vector<Stats>& stats);
void writeToFile(const Stats& stats);

void mainMenu();
size_t subMenu();
void showMenu();


Stats.h
1
2
3
4
5
6
7
8
9
10
11
#include <string>
#include <vector>

typedef unsigned long long long_type;

struct Stats {
    std::string type;
    std::vector<long_type> values;
    long_type nanosec=0, microsec=0, millisec=0;
    double sec=0;
};
That is super helpful, thanks a lot!

The assignment is very poorly written and hard to understand (something my uni is quite famous for..) but I asked my teacher and it's supposed to be only two options from mainMenu

- Run Measurements and Exit.

The Run Measurements option should call the subMenu where you input the number you want fibonaccied(!). After that, everything should be automatized.

So, am I thinking correctly with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//------------------------------------------------------------------------------
// Name: mainMenu
//------------------------------------------------------------------------------
void mainMenu()
{
    bool AGAIN = true;
    size_t nthNumber;
    do
    {
        showMenu();
        char choice;
        cout << endl << "Make your choice: ";
        cin >> choice;

        if (choice == '1')
        {

            nthNumber = subMenu();
            cin.get();
            fibonacciTimer(nthNumber);

        } else if (choice == '2')
        {
            AGAIN = false;
        } else
        {
            mainMenu();
        }

    } while (AGAIN);
}


If yes, I can start the fibonacciTimer! Though I'm having a hard time understanding even the pseudo code.

Once the user input a number the fibonacciTimer should do both the recursive and iterative fibonacci calculations and then output them both.

So I have to save the output from the fibonacci functions in a vector and then somehow get the fifth calculations out somehow?

When will this make sense to me?!
For now: forget about the menu.

Your assignment is not about the menu, it is about measuring the time required for the program to calculate the fibonacci numbers. The menu is only helpful to start that process, but it is not relevant for your task.
If you have more options in your menu, you can test smaller parts of your program separately, so for the time being: keep the menu with as many options as you can.

In the end you will probably end up with something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void mainMenu()
{
    bool AGAIN = true;
    size_t choosenNumber = 0;
    do
    {
        showMenu();
        char choice;
        cout << endl << "Make your choice: ";
        cin >> choice;

        switch(choice)
        {
            case '1':   choosenNumber = subMenu();
                        printStats( fibonacciTimer(choosenNumber) );
                        break;
            case '2' :        
            case 'q' :        
            case 'Q' :  AGAIN = false;
                        break;
            default:    break;        
        }
    } while (AGAIN);
}

But for now that will only make it more difficult for you to implement the next step.

For the fibonacciTimer function I think you have to do a couple on things:
1. Measure time between the start of the function and the return of the fibonacciIteration
2. Create an Stats object and store the results in it
3. Store the Stats object in the tempVector.
4. Do the same (1, 2 and 3) for the fibonacciRecursion function
5. Repeat step 1 to 4 for the nthNumber times

Think of these as 5 separate problems. I would start solving the first one:
- Write a function that writes the time it took to execute the fibonacciIteration function to cout.
I think this is somewhere near of what you mean?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//------------------------------------------------------------------------------
// Name: fibonacciTimer
//------------------------------------------------------------------------------
std::vector<Stats> fibonacciTimer(size_t nthNumber)
{
    std::vector<Stats> tempVector;
    size_t recursion = fibonacciRecursion(nthNumber);
    size_t iteration = fibonacciIteration(nthNumber);
    bool AGAIN = true;

    do
    {
        Stats Iteration;
        Iteration.type = "Iteration";
        auto timeStart = std::chrono::high_resolution_clock::now();
        
        do
        {
            fibonacciIteration(nthNumber);
            AGAIN = false;

        } while (AGAIN);

        auto timeStop = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(timeStop - timeStart).count();

        cout << duration << endl;
        cin.get();
        AGAIN = false;

    } while (AGAIN);


    return tempVector;
}


Though, I did not store the results in a Stats object because I don't know how!
According to the pseudo code I'm supposed to add fibonacci values to the "Stats container".

When I run this I just get '0' from the chrono timer?

EDIT:

Chrono timer works! I it just shows 0 when the input is low!
Last edited on
What are you doing in these two lines?
1
2
size_t recursion = fibonacciRecursion(nthNumber);
    size_t iteration = fibonacciIteration(nthNumber);

I think you will be more efficient if you just don't do that.

Also: why do you have the two do-while loops?
As soon as the innerloop is executed once, both loops will terminate, so why create them in the first place if they are not looping?

I would try to clean this function up a bit. Also while trying to get things working it is often easier to create some extra local variables and put less functions in line. So I would suggest to create a variable that contains the difference between timeStart and timeStop, subsequently cast that variable and output the result of it. This is not necessary, but it often helps you understand what is happening.

So if you've got this timer working, store the results in the Stats object.
seatea wrote:
Though, I did not store the results in a Stats object because I don't know how!
According to the pseudo code I'm supposed to add fibonacci values to the "Stats container".

You already seem to store the type string in it, so I think you know how to do that.

Currently your Stats object is local, as soon as AGAIN becomes false and you leave the do-while loop the object is deleted from memory.
To preserve the object you want to push the object into the vector.
Some progress(?)

Our professor is really strict with us following the pseudo code, that's why it's two do-while loops. Since the pseudo says:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

    REPEAT = do {
    DETERMINE type of approach = Stats Iteration
    SET Stats.type = Iteration.type = "Iteration"
            MARK start time = chrono
    REPEAT = do {
    CALL appropriate Fibonacci function = size_t SIZEiteration = fibonacciIteration(nthNumber);
    ADD Fibonacci value to Stats container = Iteration.values.push_back(SIZEiteration) ? This will only get one number, not the sequence?
tempVector.push_back(Iteration)
    FOR EACH 5th sequence OUTPUT information on screen** for(auto e : tempVector)
Somehow get just the 0th,5th,10th,15th sequence of fibonacci result (0, 5, 55, 610, 6765)
    } IF iteration IS NOT 0* = while (iteration != 0) - *"Repeat execution from nthNumber until (and including) 0. If nthNumber to find is 30, then all
Fibonacci values within the sequence range of 30...0 will be included."?
    MARK end time chrono
            CALCULATE duration of all needed formats = Calculate the chrono time to long_type nanosec=0, microsec=0, millisec=0;
    double sec=0;
            SET duration for relevant Stats members = Noo idea
    } FOR each Fibonacci approach = For both Recursive and Iteration
    RETURN container filled with two Stats objects Send two struct Class objects to an array?


This is how I'm picturing it my head, NO idea if it's correct or not.

Right now I have this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//------------------------------------------------------------------------------
// Namn: fibonacciTimer
// Uppgift: -
// Indata: void
// Utdata: void
//------------------------------------------------------------------------------
std::vector<Stats> fibonacciTimer(size_t nthNumber)
{
    std::vector<Stats> tempVector;
    int i;
    bool AGAIN = true;

    do
    {
        Stats Iteration;
        Iteration.type = "Iteration";
        auto timeStart = std::chrono::high_resolution_clock::now();

        do
        {
            size_t iteration = fibonacciIteration(nthNumber);
            Iteration.values.push_back(iteration);
            tempVector.push_back(Iteration);
            for(auto e : tempVector)
            {
                cout << e.type;
                cout << " " << nthNumber << "'th value: ";
                cout << iteration << endl;
                cin.get();
            }

        } while (nthNumber <= 0);

        auto timeStop = std::chrono::high_resolution_clock::now();
        long_type duration = std::chrono::duration_cast<std::chrono::microseconds>(timeStop - timeStart ).count();

        cout << "The duration of this task: " << duration << " microseconds." << endl;
        AGAIN = false;

    } while (AGAIN);


    return tempVector;
}


But this doesn't really give me the correct output:

=====================
===== MAIN MENU =====
1. Measure
2. Timer - Test only
2. Print - Test only
4. Exit
=====================
=====================

Make your choice:4
Iteration 4'th value: 3
The duration of this task: 1987 microseconds.
Last edited on
Registered users can post here. Sign in or register to post.