Reading data from a file and sorting it into a array

closed account (zCS1vCM9)
New to programming. I need some help with a code I am writing for a school project.
I have to write a code that opens a file containing and unknown (around 1000) bank account numbers then separated by a space the balances. I am running into a issue when I run the program it crashes without giving a error. I have narrowed it down to the function Read_Data but I cannot figure out what it wrong. The code is not completed yet so bear with me. But any help would be wonderful! Thank you!
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
  #include <iostream>
#include <string>
#include <iomanip>
#include <fstream>

using namespace std;

//Function Prototype
void Read_Data(string accountNumbers[], double balance[], int &length);
void Sort_Accounts(string accountNumbers[], double balance[], int length);
int Search_Accounts(string accountNumbers[], double balance[], int length, string searchNumber);
string Read_Account_Number();





void main() {
	int i = 0, length;
	string accountNumbers[100];
	double balance[100];

	//Call Read_Data Function
	Read_Data(accountNumbers, balance, length);
	//Call Sort_Account Function
	Sort_Accounts(accountNumbers, balance, length);


	//Search account numbers
	string searchAccountNumber;
	while (true)
	{

		searchAccountNumber = Read_Account_Number();

		//Terminate loop when -99 entered
		if (searchAccountNumber == "-99")
			break;

		//Calling Binary search
		int index = Search_Accounts(accountNumbers, balance, length, searchAccountNumber);
		if (index == -1) {
			cout << "Cannot find account" << endl;
		}
		else {
			cout << (accountNumbers[index]) << "   " << (balance[index]) << endl;
		}
	}



}//end main

 //Read_Data Function Defined
void Read_Data(string accountNumbers[], double balance[], int &length) {
	int i = 0;
	//ifstream infile;
	ifstream infile("Final_Random_Accounts_Unsorted.txt");
	cout << "A";
	while (!infile.eof()) {

		infile >> accountNumbers[i] >> balance[i];
		i++;
	}
	length = i - 1;
}

//Sorting function defined
void Sort_Accounts(string accountNumbers[], double balance[], int length)
{
	int i, j, min;
	string temp;
	double tempBalance;
	for (i = 0; i < length - 1; i++)
	{
		min = i;
		for (j = i + 1; j < length; j++)
		{
			if (accountNumbers[j]<accountNumbers[min])
			{
				min = j;
			}
		}
		temp = accountNumbers[i];
		accountNumbers[i] = accountNumbers[min];
		accountNumbers[min] = temp;

		tempBalance = balance[i];
		balance[i] = balance[min];
		balance[min] = tempBalance;
	}
}

//Binary Search Function defined
int Search_Accounts(string accountNumbers[], double balance[], int length, string searchNumber)
{
	int l = 0, h = length - 1;
	int m = l + (h - l) / 2;
	while (l <= h)
	{
		m = l + (h - l) / 2;
		if (accountNumbers[m] == searchNumber) {
			return m;
		}
		else if (accountNumbers[m]<searchNumber) {
			l = m + 1;
		}
		else {
			h = m - 1;
		}
	}
	return -1;
}

string Read_Account_Number()
{
	return string();
}

I have to write a code that opens a file containing and unknown (around 1000) bank account numbers
On line 20/21 you create an array with 100 elements.

In Read_Data(...) you store one record more than existing. If on line 62 an eof occurs you still execute line 61.

So change to
1
2
3
4
5
6
7
8
9
10
11
void Read_Data(string accountNumbers[], double balance[], int &length) {
	int i = 0;
	//ifstream infile;
	ifstream infile("Final_Random_Accounts_Unsorted.txt");
	cout << "A";
	while (infile >> accountNumbers[i] >> balance[i]) { // Note: The stream returns false on eof

		i++;
	}
	length = i - 1;
}
This will still crash if the number of records in the file exceeds the array capacity. So either you use a container (like std::vector) which is unlimited or you pass the limit as well (in length). Note that you need to add code to check the limit!
@coder777

So either you use a container (like std::vector)

Wont an std::deque<char> be faster than a vector for adding elements?

@M101st329
I would advice you to read the full file into a string and than work with that string.
Example of a code i would use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
readFile(const std::string& filePath, std::string& fileContent) {
	std::ifstream inFile(filePath, std::ios::binary);
	if (inFile.is_open()) {
		auto const start_pos{ inFile.tellg() };
		inFile.ignore(std::numeric_limits<std::streamsize>::max());
		std::streamsize char_count{ inFile.gcount() };
		inFile.seekg(start_pos);
		fileContent = std::string(static_cast<std::size_t>(char_count), '0');
		inFile.read(&fileContent[0], static_cast<std::streamsize> (fileContent.size()));
		inFile.close();
	}//end of if
	else {
		std::cout << "Unable to open file\n";
		std::exit(EXIT_FAILURE);
	}//end of else
}


the libraries you would need for this code are:
1
2
3
4
5
#include<fstream>
#include<string>
#include<sstream>
#include<cstdlib>
#include<iostream> 


Why use this seemingly complicated code?
what if your file contains a null character in the middle of the file ?
while (infile >> accountNumbers[i] >> balance[i])
would stop reading because the condition would be false as NULL = 0.
same would happen if you come across Ctrl-Z which has the code 0x1A and is treated as eof.

if you want more insight on why its done the way i posted, there is a blog that perfectly explains it and gives examples:
http://cpp.indi.frih.net/blog/2014/09/how-to-read-an-entire-file-into-memory-in-cpp/

These methods are a bit more complex but its better to get used to them from the start.
Good luck :)
Wont an std::deque<char> be faster than a vector for adding elements?
Maybe: Is this even relevant...

would stop reading because the condition would be false as NULL = 0.
same would happen if you come across Ctrl-Z which has the code 0x1A and is treated as eof.
But that would be ok, because it does not match the expected content.
Maybe: Is this even relevant...

wasn't intended to neglect your advice this was a genuine question because if it is it can save time in the long run.

But that would be ok, because it does not match the expected content.

I think its a good idea to allways keep this in mind for this specific task your way will suffice and be more elegant than mine but using it as a default wouldn't be such a great idea IMO because of :

would stop reading because the condition would be false as NULL = 0.
same would happen if you come across Ctrl-Z which has the code 0x1A and is treated as eof.
@globaltourist

wasn't intended to neglect your advice
This is not the problem. What you thinking of is the so called 'Premature Optimization'. See:

http://wiki.c2.com/?PrematureOptimization

Means: First think of the most simple solution possible. Only if really required apply optimizations on it.
Means: First think of the most simple solution possible. Only if really required apply optimizations on it.


Makes sense i'l look into it.
closed account (zCS1vCM9)
I have tried both possible solutions and still get the same error. Any other ideas?
Can you copy and paste the error here ?
I'l be able to fully investigate it only in 4 hrs once i get back home. college and stuff :(
I think i have an idea.
ifstream infile("Final_Random_Accounts_Unsorted.txt");
Is it in the same file directory as your code?
If not you must provide full file path, for example:
ifstream infile("C:/Users/User/Desktop/Final_Random_Accounts_Unsorted.txt");
just right click on the file and go to properties.
I have to write a code that opens a file containing and unknown (around 1000) bank account numbers then separated by a space the balances.

Then why did you create your arrays with a size of 100?

Next look at this snippet:
1
2
3
4
5
6
void Read_Data(string accountNumbers[], double balance[], int &length) {
	int i = 0;
	//ifstream infile;
	ifstream infile("Final_Random_Accounts_Unsorted.txt");
	cout << "A";
	while (infile >> accountNumbers[i] >> balance[i]) { // Note: The stream returns false on eof 

You're using arrays and have an unknown number of accountsNumbers and balances so your while statement must also insure you never try to access those arrays out of bounds. Something like:
1
2
3
4
5
6
7
8
9
10
11
...
// In the global scope, and also used to size your arrays.
const int ARRAY_SIZE = 1000;
...
   // In main(), and by the way main() must return an int in a C++ program,

   string accountNumbers[ARRAY_SIZE];
   double balance[ARRAY_SIZE];
...

while (i < ARRAY_SIZE && infile >> accountNumbers[i] >> balance[i]) { // Note: The stream returns false on eof 


And note that last comment is not 100% correct. While it will indeed return false on eof(), it actually returns false on any error, including eof().



closed account (zCS1vCM9)
Hey guys made some progress today, the program now displays the correct account number and balance (see line 29 before the search function). Now when I enter a account number to search the program runs a loop from the cout << "Cannot find account" << endl; instead of providing the correct account number and balance. By the way I am using Visual Studios on Windows 10. I don't understand why it would run a loop on that.

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

using namespace std;

//Function Prototype
void Read_Data(string accountNumbers[], double balance[], int &length);
void Sort_Accounts(string accountNumbers[], double balance[], int length);
int Search_Accounts(string accountNumbers[], double balance[], int length, string searchNumber);
string Read_Account_Number();





void main() {
	int i = 0, length;
	const int maxsize = 999;
	string accountNumbers[maxsize];
	double balance[maxsize];

	//Call Read_Data Function
	Read_Data(accountNumbers, balance, length);
	//Call Sort_Account Function
	Sort_Accounts(accountNumbers, balance, length);

	cout <<"Account Number: "<< accountNumbers[1] << " Balance is: " << balance[1] << endl;

	//Search account numbers
	string searchAccountNumber;
	cout << "please enter account number" << endl;
	cin >> searchAccountNumber;
	while (true)
	{

		searchAccountNumber = Read_Account_Number();

		//Terminate loop when -99 entered
		if (searchAccountNumber == "-99")
			break;

		//Calling Binary search
		int index = Search_Accounts(accountNumbers, balance, length, searchAccountNumber);
		if (index == -1) {
		cout << "Cannot find account" << endl;
		}
		else {
			cout << (accountNumbers[index]) << "   " << (balance[index]) << endl;
		}
	}



}//end main

 //Read_Data Function Defined
void Read_Data(string accountNumbers[], double balance[], int &length) {
	int i = 0;
	ifstream infile;
	ifstream infile("Final_Random_Accounts_Unsorted.txt");
	while (infile >> accountNumbers[i] >> balance[i]) { // Note: The stream returns false on eof

		i++;
	}
	length = i - 1;
}

//Sorting function defined
void Sort_Accounts(string accountNumbers[], double balance[], int length)
{
	int i, j, min;
	string temp;
	double tempBalance;
	for (i = 0; i < length - 1; i++)
	{
		min = i;
		for (j = i + 1; j < length; j++)
		{
			if (accountNumbers[j]<accountNumbers[min])
			{
				min = j;
			}
		}
		temp = accountNumbers[i];
		accountNumbers[i] = accountNumbers[min];
		accountNumbers[min] = temp;

		tempBalance = balance[i];
		balance[i] = balance[min];
		balance[min] = tempBalance;
	}
}

//Binary Search Function defined
int Search_Accounts(string accountNumbers[], double balance[], int length, string searchNumber)
{
	int l = 0, h = length - 1;
	int m = l + (h - l) / 2;
	while (l <= h)
	{
		m = l + (h - l) / 2;
		if (accountNumbers[m] == searchNumber) {
			return m;
		}
		else if (accountNumbers[m]<searchNumber) {
			l = m + 1;
		}
		else {
			h = m - 1;
		}
	}
	return -1;
}

string Read_Account_Number()
{
	return string();
}
Last edited on
what is the purpose of
Read_Account_Number();
?
why did you decide to return string() ?
maybe do something like this:

1
2
3
4
5
6
string Read_Account_Number()
{
        string accountNum;
        cin >> accountNum;
	return accountNum;
}


I think this function is the cause of your problem because of the following.
you do this:
searchAccountNumber = Read_Account_Number();
and searchAccountNumber still doesn't store anything, you just returned string() object to it
than you do the following:
int index = Search_Accounts(accountNumbers, balance, length, searchAccountNumber);
that will allways return -1 unless you have an account number that is blank i.e.: ""
and this keeps looping on forever and ever
closed account (zCS1vCM9)
That fixed the problem globaltourist. Thank you a lot, I overlooked that and thought the fault was in the search function.

Again thank you!
Np :)
Topic archived. No new replies allowed.