Hello

I have a problem where when if I call my 'Display' function from within my 'Menu' function it(the 'Display' function) does not work. But if I call my 'Display' function from within my 'Read'function it does work.

When I say it doesn't work, I mean the information extracted from a text file is not passed/sent to the 'Display' function, so the output of 'Display' is just all zeros?

Can you tell me why this occurs & how I can fix it? :)

Here is my program:

// In this example the 'Display' function is called within the 'Menu' function
// This example does not work; meaning the information grabbed from the text file
// is not output (passed) to the 'Display' function & I dont know why?

#include<iostream>
#include <iomanip>
#include<string>
#include<fstream>

using namespace std;

struct budget {
	double expenditures[199];
	double budget_limit;
	double total_expenditure;
};

budget stats;

int counter = 0;

void menu();
void read(budget stats);
void display(budget stats, int counter);


int main()
{
	/// Set Expenditures array elements to zero.
	memset(stats.expenditures,0,199);

	menu();

	return 0;
}

void menu()
{
	int option;
	double purchase;

	cout << "//////////Personal Budget\\\\\\\\\\" << endl;
	cout << "\n(1) Adjust Budget\n(2) Change Budget Cap\n(3) Budget Summary\n";
	cout << "Please choose your option(1-3): " << flush;
	cin >> option;

	switch(option) {
	case 1:
		read(stats);
		display(stats, counter);
		break;
	default:
		cout << "Incorrect input";
	}
}

void read(budget stats)
{
	ifstream infile;

	infile.open("data.txt");

	if (!infile)
	{
		cout << "Failed to open file";
	}

	infile >> stats.budget_limit;
	// use for statement to take in all payments
	while (infile) {
		infile >> stats.expenditures[counter];
		counter++;
	}

	counter = (counter-1);

	infile.close();

}

void display(budget stats, int counter) {

	cout << "\nBudget cap is: " << stats.budget_limit << endl;

	for (int i=0; i<counter; i++)
	{
		stats.total_expenditure += stats.expenditures[i];
		cout << "Purchase " << i+1 << ": " << stats.expenditures[i] << "\n";
	}

	cout << "----------------------------------------------\n";
	cout << "Total expenses = " << stats.total_expenditure << endl;
	cout << "----------------------------------------------\n";

	if (stats.total_expenditure > stats.budget_limit) {
		cout << "BUDGET OVERRUN!! by " << (stats.total_expenditure-stats.budget_limit);
	}
	else {
		cout << "Congratulations you are within your budget cap by $";
		cout << (stats.budget_limit-stats.total_expenditure);
	}
}

Here is the program where it works; the text file contents are sent to display:

// The only difference is that 'Display' function is called within the 'Read' function
// This example works; meaning the information grabbed from the text file is output
// in the display function.

#include<iostream>
#include <iomanip>
#include<string>
#include<fstream>

using namespace std;

struct budget {
	double expenditures[199];
	double budget_limit;
	double total_expenditure;
};

budget stats;

int counter = 0;

void menu();
void read(budget stats);
void display(budget stats, int counter);


int main()
{
	/// Set Expenditures array elements to zero.
	memset(stats.expenditures,0,199);

	menu();

	return 0;
}

void menu()
{
	int option;
	double purchase;

	cout << "//////////Personal Budget\\\\\\\\\\" << endl;
	cout << "\n(1) Adjust Budget\n(2) Change Budget Cap\n(3) Budget Summary\n";
	cout << "Please choose your option(1-3): " << flush;
	cin >> option;

	switch(option) {
	case 1:
		read(stats);
		break;
	default:
		cout << "Incorrect input";
	}
}

void read(budget stats)
{
	ifstream infile;

	infile.open("data.txt");

	if (!infile)
	{
		cout << "Failed to open file";
	}

	infile >> stats.budget_limit;
	// use for statement to take in all payments
	while (infile) {
		infile >> stats.expenditures[counter];
		counter++;
	}

	counter = (counter-1);

	infile.close();

	display(stats, counter);

}

void display(budget stats, int counter) {

	cout << "\nBudget cap is: " << stats.budget_limit << endl;

	for (int i=0; i<counter; i++)
	{
		stats.total_expenditure += stats.expenditures[i];
		cout << "Purchase " << i+1 << ": " << stats.expenditures[i] << "\n";
	}

	cout << "----------------------------------------------\n";
	cout << "Total expenses = " << stats.total_expenditure << endl;
	cout << "----------------------------------------------\n";

	if (stats.total_expenditure > stats.budget_limit) {
		cout << "BUDGET OVERRUN!! by " << (stats.total_expenditure-stats.budget_limit);
	}
	else {
		cout << "Congratulations you are within your budget cap by $";
		cout << (stats.budget_limit-stats.total_expenditure);
	}
}

Exact contents of text file are:

300
7.95
2.3
15

Why are you using a global variable 'stat' ? You're passing it to your functions right? So make it local to main.

you;re passing the 'stats' BY VALUE.
the only reason you see the correct output in the second case is because the 'read' stats is reading into it's own stats and passing BY Value it's copy of stats to the display routine.

neither 1 or 2 is probably doing what you meant. if you put a breakpoint at the end of either 'main' and looked into the global 'stats' you would see that it is still full of zeros.

you need to pass the address of stats into the functions (&stats) and have the function use the *stats to read into.
(or use references, ie the function definitions/declarations say:

read (budget &stats)

instructively, look at the asm output and see the huge copies going on before the calls.

Why are you using a global variable 'stat' ? You're passing it to your functions right? So make it local to main.

sorry, Niek_e, the same problem exists even if stats is local to main. the value of the the variable is being passed. not its address.

the changes are all taking place on the stack space, not the variable space.

sorry, Niek_e, the same problem exists even if stats is local to main. the value of the the variable is being passed. not its address.

I know. I didn't say it was the answer to the problem, I just started with the first thing that needs changing and then go from there. So: yes, you're right. The struct needs to be passed by reference. But first make it local to main :)

Thanks for the help so far :)

Just to be clear are you guys saying that I shouldn't use a struct at all & just use variables created in main?

For eg; instead of

void read(budget stats)

do

void read(double& cap, double& expenditures[], double& total)
void display(double& cap, double& expenditures[], double& total)

instructively, look at the asm output and see the huge copies going on before the calls.

I am not sure what you mean, I have been learning programming for about 6 mnths now, could you explain a little more :)

Thanks for the help so far :)

Just to be clear are you guys saying that I shouldn't use a struct at all & just use variables created in main?

For eg; instead of


do

No. using the 'struct' to encapsulate related data is far preferred than not using the struct. you just need to pass the address to it around instead of passing it by value.

also, having it be global is ok (doens't need to be declared local to main()). if it's local to main, and you're going to use it often, you'd have to have all your calls from main have to pass it down as a parameter. of course, this is a 'potato'/'potatoe' problem...:-)

what I meant by the ASM thing is not overly important. i just meant that by not passing the address (a 4 or 8 byte copy) the pass by value is copying the whole struct of (i don't remember the struct definition) but was it 200 doubles and several other variables which is close to what 2K?

This article has been dead for over six months. Start a new discussion instead.