Merging Files

So my teacher had told me to translate a pseudocode into c++ program...I just want to know if the codes makes sense. Sorry if it's so vague..

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
  #include <iostream>
#include <string>
#include <fstream>
using namespace std;

int main()
{
	fstream eastfile;
	fstream westfile;
	eastfile.open("eastcoast.dat");
	westfile.open("westcoast.dat");
	mergedfile.open("mergedfile.dat");
	const eastName;
	int eastBalance;
	const westName;
	int westBalance;
	const END_NAME = 'ZZZ'; 
	const areBothAtEnd = "N";
	
	getReady()
	{
		eastfile.open("EastCoastClient.dat");
		westfile.open("WestCoastClient.dat");
		mergedfile.open("Clients.dat");
		readEast()
		{
			cin >> eastfile >> eastName >> eastBalance;
			if(eof)
			{
				eastName = END_NAME;
			}
		}
		readWest()
		{
			cin >> westfile >> westName >> westBalance;
			if(eof)
			{
				westName = END_NAME;
			}
		}
		checkEnd()
		{
			if(eastName == END_NAME)
			  if(westName == END_NAME)
			  {
			  	areBothAtEnd = "Y"
			  }
		}
		
	}
	while(areBothAtEnd != "Y")
	{
		mergeRecords()
		{
			if(eastName < westName)
			{
				cout << eastName << eastBalance;
			    readEast()
			    {
				  cin >> eastfile >> eastName >> eastBalance;
			        if(eof)
			         {
				        eastName = END_NAME;
			         } 
		        }
				
			}
			else
			{
				cout << westName << westBalance;
				readWest()
		           {
			          cin >> westfile >> westName >> westBalance;
			           if(eof)
		              	{
			             	westName = END_NAME;
		            	}
		            }
			}
			checkEnd()
			{
			  if(eastName == END_NAME)
			  if(westName == END_NAME)
			  {
			  	areBothAtEnd = "Y"
			  }
			}
		}
		
    }
	 finishUp() 
	 

return 0;
	
	
}
Hello kuushie118,

The first six lines are OK except for line 4 which is best not to use.

Then it falls apart in "main".

You define two files as an "fstream", but then you try to open three files. The third file is not even defined and all three open statements are wrong.

When you define a file stream as an "fstream" it can be used either for input or output, so in the open statements you need to tell it if it is for input or output. As in:
1
2
3
eastfile.open("eastcoast.dat", std::ios::in);
westfile.open("westcoast.dat", std::ios::in);
mergedfile.open("mergedfile.dat", std::ios::out);

If my guess is correct.

Now when you include "#include <fstream>" it will include the header files "ifstream" for input and "ofstream" for output, so what you could have done is:
1
2
3
ifstream eastfile;
ifstream westfile;
ofstream mergefile;

Since they are already defined for input and output all the open statement needs is the file name.

And do not forget to define the "mergefile" before you open it.

When you open a file for input you should check to make sure it is open before you try to use it. The simplest way is:
1
2
3
4
5
6
7
if (!eastfile)
{
    std::cout << "\nyour error message\n"<<std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread"
    return 1; // <--- Leave the program becaust there is no reason to continue until you fix the
              // problem. The "1" or any number greater than zero  means there is a problem.
}

You will need to do this for both files. Change the if condition for the other file.

The test for the output file is at you choice. Its not really needed because if the file name does not exist it will create it, so there is not anything I have seen yet that will cause an open for output to fail.

Lines 20 - 50 is a function and should not be in main, but either above "main" or below"main". If below "main" you will need a proto type above main.

When I moved the function "getReady()" out side of "main" I notice that it contains three other functions. This is not right. Each function needs to be a stand alone function.

I also noticed that the "getReady function tries to open files that are already open. You need to either define and open file streams where they are needed or pass the file streams to the function.

Let me back up a bit. Lines 13, 15,17 and 18 are almost correct. You qualify them as being "const" and have a variable name, but you missed the type for the variable. Also when defining a "const" it is best to make the variable name all caps to remind you that it is defined as a "const".

When I was going over the function "checkEnd" I notices two things:
Your code:
1
2
3
4
5
6
7
8
checkEnd()
{
    if(eastName == END_NAME)
        if(westName == END_NAME)
	{
		areBothAtEnd = "Y"
        }
}

This may work, but it is more often written as:
1
2
3
4
5
checkEnd()
{
	if (eastName == END_NAME && (westName == END_NAME)
			areBothAtEnd = "Y"
}

For a one line statement following the if statement the {}s are not need unless you plan an adding something else later.

The big problem here is that "areBothAtEnd" is not available to the function because it is defined back in "main" and being defined as a "const" it can not be changed by the program.

in the functions "readEast" and "readWest" you are taking input from the keyboard did you mean to get this information from a file?

Also both the "readEast" and "readWest" functions are trying to give two variables a new value, but neither function has access to those variables because they are defined back in "main".

And please do not make your variable global just to solve the problem there are better ways to do this.

You said that you started with pseudocode to write the program I am curious to know what it looks like if you could post it please and any file used for input or a decent sample of the file so I know what you have to work with. Reading an input file all depends on what the file looks like.

You have some good pieces and for the most part a good start, but the code you posted need major rework to make it a usable program.

I will work on it for a little while tonight and have something tomorrow. I do not know how much you know about C++, so if you want to take some time tonight you can start at: http://www.cplusplus.com/doc/tutorial/

You should have a look at:

Variables and types
Constants
    Almost at the bottom of the page is "Typed constant expressions"
Basic Input/Output
Control Structures
Functions


That should keep you busy for awhile and give me a chance to work on the program.

Hope that helps,

Andy
Hello kuushie118,

I worked on your program last night and this morning and this is what I came up with:

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
#include <iostream>
#include <string>
#include <fstream>
#include <limits>
#include <chrono>
#include <thread>

//using namespace std;  // <--- Best not to use.

// Proto Types
//void getReady();
void readEast(std::ifstream& eastfile, std::string eastName, int eastBalance, const std::string END_NAME);
void readWest(std::ifstream& westfile, std::string westName, int westBalance, const std::string END_NAME);
void checkEnd(std::string eastName, std::string westName, char areBothAtEnd, const std::string END_NAME);
void mergeRecords(std::string eastName, std::string westName, int eastBalance, int westBalance);

int main()
{
	const std::string END_NAME = "ZZZ";
	int eastBalance{};
	int westBalance{};
	std::string eastName;
	std::string westName;
	char areBothAtEnd = 'N';
	std::ifstream eastfile;
	std::ifstream westfile;
	std::ofstream mergedfile;
	eastfile.open("eastcoast.dat");
	westfile.open("westcoast.dat");
	mergedfile.open("mergedfile.dat");  // <--- Not defined.
	
	if (!eastfile)
	{
		std::cout << "\nYour error message.\n" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // Requires header files "chrono" and "thread"
		return 1; // <--- Leave the program becaust there is no reason to continue until you fix the
				  // problem. The "1" or any number greater than zero means there is a problem.
	}

	//while (areBothAtEnd != 'Y')  // <--- Not sure what to do with this yet.
	//{
	//	checkEnd(eastName, westName, areBothAtEnd, END_NAME);
	//}

	// Finish Up
	eastfile.close();
	westfile.close();
	mergedfile.close();

	// <--- Used mostly for testing in Debug mode. Removed if compiled for release.
	// <--- Used to keep the console window open in Visual Studio Debug mode.
	// The next line may not be needid. If you have to press enter to see the prompt it is not needed.
	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n Press Enter to continue";
	std::cin.get();

	return 0;
}


//void getReady()  // <--- Files are already open.
//{
//	eastfile.open("EastCoastClient.dat");
//	westfile.open("WestCoastClient.dat");
//	mergedfile.open("Clients.dat");
//}

void readEast(std::ifstream& eastfile,std::string eastName, int eastBalance, const std::string END_NAME)
{
	eastfile >> eastName >> eastBalance;

	//if (eof)
	//{
	//	eastName = END_NAME;
	//}
}

void readWest(std::ifstream& westfile, std::string westName, int westBalance, const std::string END_NAME)
{
	westfile >> westName >> westBalance;

	//if (eof)
	//{
	//	westName = END_NAME;
	//}
}

void checkEnd(std::string eastName, std::string westName, char areBothAtEnd, const std::string END_NAME)
{
	if (eastName == END_NAME && westName == END_NAME)
		areBothAtEnd = 'Y';  // <--- Notice the single quotes.
}

void mergeRecords(std::string eastName, std::string westName, int eastBalance, int westBalance)
{
	if (eastName < westName)
	{
		std::cout << eastName << eastBalance;
	}
	else
	{
		std::cout << westName << westBalance;
	}
}

Now the code does compile, but I would not try running it yet. There is still a lot of work that needs to be done and there are parts the will likely change.

For now it is hard to say what is the best way to read the file until I see what is in the files and how the information is stored.

Line 27. First you tell the program that you will be getting the information from "cin", i.e., the keyboard then you say that the input will be coming from a file. You can use one or the other, but not both in the same line.

Read the comments in the program that I made they will help explain what I did.

This is just one possible way of writing the program. There are others as you will learn.

There is a very good possibility that you will need some more variables. In "main" and in the functions.

As soon as I know what the pseudocode is the you started with, that will let me know if the program is going in the right direction, and what is in the input files so I know how to read the files we can move forward.

Hope that helps,

Andy
Sir Andy,
Thank you for really helping me out..I'm sorry if I wasn't able to reply to you instantly..it's just that this week has been too hectic for me because of college life...I'll be sure to post the data and pseudocode here as soon as possible...sorry for the trouble and thanks again sir.
Hello kuushie118,

You are welcome and it is no trouble.

The program I showed you is just an idea of what could be done. I had to make a few more tweaks to the program and create an input before I could run it. Even the I do not know if it was right.

A hint for the future: when you start writing a program it is best to work in small pieces. Get one piece working and then move on to the next.

When I have more to work with I can really get you pointed in the right direction.

In the future it is most often better to post all your code when asking a question. This includes things like pseudocode, header files and at least a sample, or the whole file if it is short, of the input file(s) used. An output is not as necessary unless there is a problem and you show what you are getting.

Andy
Pseudocode

start
Declarations
InputFile eastFile
InputFile westFile
OutputFile MergedFile
string eastName
int eastBalance
string END_NAME = "ZZZ"
string areBothAtEnd = "N"
getReady()
while areBothAtEnd <> "Y"
mergeRecords()
endwhile
finishup()
stop

getReady()
open eastfile "EastCoastClients.dat"
open westfile "WestCoastClients.dat"
open mergedFile "Clients.dat"
readEast()
readWest()
checkEnd()
return

readEast()
input eastName, eastBalance from eastFile
if eof then
eastName = END_NAME
endif
return

reastWest()
input westName, westBalance from westFile
if eof then
westName = END_NAME
endif
return

checkEnd()
if eastName = END_NAME then
if westName = END_NAME then
areBothAtEnd - "Y"
endif
return


mergeRecords()
if eastName < westName then
output eastName, eastBalance to merged file
readEast()
else
output westName, westBalance to mergedFile
endif
checkEnd()
return


finishUp()
close eastFile
close westFile
close mergedFile
return



Data for the Code
1
2
3
4
5
6
7
8
East Coast File                                                     West Coast File
eastName            eastBalance                                   westName            westBalance
Able                        100.0                                            Chen                     200.00
Brown                     50.00                                             Edgar                   125.00
Dougherty               25.00                                             Fell                       75.00
Hanson                   300.00                                           Grand                    100.00
Ingram                   400.00
Johnson                  30.00


Output ===> kind of incomplete but this is how it should look like at the end

Able                        100.0         
Brown                     50.00  
Chen                     200.00
Dougherty               25.00  
Edgar                   125.00
Fell                       75.00
Grand                    100.00
Hanson                   300.00   
 
Last edited on
Were you supplied the pseudo code or did you write it? It seems overly complicated and a has possibly too much detail.

Remember this is C++ variables should be declared close to first use, not is one big glob at the beginning of some scope. Also since you're using C++ streams there is no need to manually close the streams in this program, just let the class destructors do their jobs.

I really don't see a need for a special string to indicate the last record. If you're using std::vector the vector knows it's size and you should use that value.

Beware of that code posted by Andy, it has a lot of bugs and a lot of code duplication.

The pseudocode was given by my prof.
Okay then this is how I would structure the program:

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
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <iomanip>

struct Record
{
    std::string name;
    double balance;
};

// Create an "alias" of std::vector<Record>
using vRec = std::vector<Record>;

// Prototypes
int getReady(vRec& east, vRec& west);
/// Note using istream and ostream here so you can pass any type of stream, file, stringstream, etc.
void readInputFile(std::istream& fin, vRec& current);
std::vector<Record> mergeRecords(vRec& east, vRec& west);
void outputRecords(std::ostream& fout, const vRec& merged);
std::ostream& operator<<(std::ostream& fout, const Record& current);

int main()
{
    // Unless read/write operations on the stream are necessary prefer ifstream and ofstream.
    std::ofstream mergedFile("mergedfile.txt");

    if(!mergedFile)
    {
        std::cerr << "Couldn't open the output file.\n";
        return 3;
    }

    std::vector<Record> east;
    std::vector<Record> west;

    if(int retVal = getReady(east, west))
        return retVal;

    // Merge the two input vectors into the output vector.
    std::vector<Record> merged = mergeRecords(east, west);

    // Output the merged records to your file.
    outputRecords(mergedFile, merged);

    // Output the merged records to the console.
    outputRecords(std::cout, merged);

    // No need to manually close the files, let the destructor do it's job.
    // Also no need for finishup() or check() since the checking is done in the various functions, and all 
    // the files are automatically closed. 

    return 0;
}
I just want to say thank you so much to everyone for helping me out. Really appreciate it :D :D
Topic archived. No new replies allowed.