Find data from file and assigning to struct members

Hi guys, I need some insight on my code here,

So I have a file that have the following stored:

username password name mobile ic

In this part of my code, I intend to read over this file and identify the username. If the username matches with "inUser" (the username that the user input), I want to retrieve the name, mobile and ic stored in the same line as the matching username.

Upon retrieving the details, i need to assign them to the struct members shown below, which will be stored in a separate file later in the codes.

My problem:
1. I'm pretty sure my while loop to find the username and outputting the name , mobile etc is wrong (bc my compiler popup "logic error") but im not sure how to change it to make it work
2. is this "username password name mobile ic" even a good way of storing data


note that this is not the full code, im only testing it and i am not supposed to use vector pointer etc.

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

using namespace std;

//I need these global variables bc i will be using it across functions
int Choice1;
int Mobile, Ic;
string User, Pass, Name, inUser, inPass;

struct Customer {
	string user, pass, name;
	int mobile, ic;
}customer;

struct Booking {
	Customer customer;
	int day, month, year;
	double start, end, price;
	string dayOfWeek; // not used here

};

Booking booking[200][5] = { 0 };


int main()
{
    inUser = "jojo"; // I just assume the user input "jojo" here
    
    bool status = false;
	ifstream c("customer.txt");

	if (!c)
		cout << "Unable to open file!\n";
	else
		while(!status && (c >> User >> Pass >> Name >> Mobile >> Ic))
			status = (inUser == User); //loop until they matches

	//after reading the relevant details from customer files, assign the name, mobile and ic to the struct members
	booking[1][1].customer.user = User;
	booking[1][1].customer.name = Name;
	booking[1][1].customer.mobile = Mobile;
	booking[1][1].customer.ic = Ic;

	c.close();
	
	//just to check if it works or not
	cout << booking[1][1].customer.user << endl;
	cout << booking[1][1].customer.name << endl;
	cout << booking[1][1].customer.mobile << endl;
	cout << booking[1][1].customer.ic << endl;
	
system("pause");
    return 0;
}
std::logic_error is a type of exception. It would be produced by the program itself running, not the compiler. It's important to know the difference.

The code you have shown is a bit unrefined, but I actually don't see where it would throw such an exception. I can only assume that the code is throwing an exception in a part you have cut out.

PS: Instead of having global variables, you can pass local variables to different functions as needed.

is this "username password name mobile ic" even a good way of storing data
Are we talking about real life? In real life, if you have a lot of data, you might use something a bit more sophisticated than a text file, such as a database. And you should never put a password in plaintext. If these are customer passwords you need to authenticate against, the password should be securely hashed and salted inside the database.

For a school assignment, it's fine. It's a linear search through the file. You could add more complicated logic to make lookup be faster (e.g. offsets that indicate when in the file usernames that start with 'j' begin), but if it's just an assignment, it's not a problem.
Last edited on
Hmm I actually cut out this part just to run it, maybe i missed some stuff while singling this part out

And no im not talking bout real life cos im barely starting in programming, thanks for that info tho :)

Aside from the throwing of exception, do you see any problems with the while loop i constructed to find and read data?

Last edited on
My bad, you're right, your example is sufficient.

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid

A null string is being created, because of your line 26.
Remove the = { 0 } from it.

What that is doing is attempting to equivalent to doing:
booking[0][0].customer.user = 0; which unfortunately compiles and throws a runtime exception.

You can just have it be:
1
2
Booking booking[200][5] {};
instead
Last edited on
Lines 8-11: No these do not need to be global just because you use them across functions.
Variables you use across functions should be passed as arguments. Variables should be as local as possible. User, Pass, Name, Mobile, Ic are used only in main, therefore they should be local to main. If you fall into the bad habit of making everything global, you will have a mess when you program gets large.

Line 39: The >> operator stops at whitespace. This is going to cause you problems with the Name field if names are more than one word. i.e. John Doe. You will get only John, then try and read "Doe" as the mobile number which will fail because mobile is an int.

Line 26: Why is Booking a 2 dimensional array? I guessing that you presuming a user can have multiple bookings. That's fair enough, but you're not keeping track of how many bookings a user (Customer) has. I think you have your data structures wrong. A Booking array should be an array within Customer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Booking 
{  int day, month, year;
    double start, end, price;
    string dayOfWeek; // not used here
};
struct Customer 
{   string user, pass, name;
    int mobile, ic;
    int num_bookings;
    Booking booking[5];
};

int num_customers {0};
Customer [200];


Lines 43-46,51-54: Why are you using subscripts of [1][1]? The first element of an array is 0, not 1.
Ohh, i thought line 26 is just initializing it


okk, now it is partially working but for the integers, they are cout - ing different numbers.
etc. 2147483647 instead of 020930030774
Do you have any idea why this would happen?
log2( 20930030774 ) is > 34. Your number overflows a 32-bit integer.
If the number in the file is only used for purposes of identification, and arithmetic is not performed on it, it most likely should be stored as a string instead of as a number.
Last edited on
@Ganado, thanks for ur help!

@AbstractionAnon,

what would be the solution for line39 if the name contain whitespaces?

I like ur modification to the struct! thanks!
and its a two-dimension it is used in my full code :) i forgot to mention it in my original post
Use std::getline() to obtain a string from the specified stream that contains white-space.

Note that getline() doesn't ignore leading white space chars and removes the terminating char (usually \n). stream extraction >> ignores leading white space chars but doesn't remove the terminating white-space char.

Mixing >> with getline() needs to be carefully done.

Last edited on

@seeplus, like this?

1
2
3
4
5
if (!c)
		cout << "Unable to open file!\n";
	else
		while(!status && (c >> User >> Pass >> getline(c, Name) >> Mobile >> Ic))
			status = (inUser == User); //loop until they matches 
Probably not but depends upon the format of the data. As you're coded it, Name will also probably also contain Mobile and Ic - as getline() gets all chars upto and including the specified terminator char which by default is \n.

What is the format of the file? If Name can contain white space chars, there needs to be some way of determining where Name ends and Mobile starts.
ahh i didnt think of that

Format:

1
2
3
4
5
username password name mobile ic
username1 password1 name1 mobile1 ic1
.
.
.


how do i determine that tho?
like putting name as the last entity in the line instead?
That would be the easiest - assuming that mobile and ic also don't contain white space chars.
Topic archived. No new replies allowed.