Program crashes when trying to access file, fstream --C++ - c++

I am making a user database. When I try to open the "dataBase.txt" which holds all of the users and passwords, the console pops up (which should happen since it is a console application) but it says that the program has already complete. When I close it, my computer tell me that the program had crashed. The function is saved in a class.
After some debugging the code seems to crash at ifstream fin("dataBase.txt");
No error is returned from the compiler.
The code for the function called is:
void User_Psw::UserCheck()
{
// read from the database
ifstream fin("dataBase.txt");
while (!fin.eof())
{
fin >> Usernames[sizeOfDatabase] >> Password[sizeOfDatabase];
sizeOfDatabase++; //The Number of lines in .txt
}
// rest of the program
cout << "Username: ";
cin >> username;
getNameIndex();
cout << "Password: ";
cin >> password;
if(!PasswordMatches())
{
cout << "Access denied";
}
}
I can add more code snippets if asked.

Don't use fin.eof() to control a loop. That function is only useful after a read has failed.
A likely reason for the crash, however, is that you are assigning to Usernames[sizeOfDatabase], which may be beyond Usernames.capacity(). The canonical way to append and item to a std::vector is to call push_back().
Since your containers are std::vector<std::string>, this is a better approach...
std::string username, password;
while (fin >> username >> password)
{
Usernames.push_back(username);
Passwords.push_back(password);
++sizeOfDatabase;
}
Of course, if you want to know the number of usernames or passwords once the file has been read, you can call Usernames.size() (which should be the same as Passwords.size()); this may obviate the need to keep sizeOfDatabase.
Personally, I would use a single container for usernames and (salted, hashed) passwords, rather than two separate containers; either std::map<std::string, std::string> or perhaps std::unordered_map<std::string, std::string>, making the password lookup nice and quick per username.

I think you should start by adding this to the constructor of your ifstream as you haven't specified you want the file opened for input:
ifstream fin( "dataBase.txt", ifstream::in );
if( !fin.good() )
{
cout << "Failed to open database file." << endl;
return;
}
See http://www.cplusplus.com/reference/fstream/ifstream/ifstream/ for additional literature.

Related

I am doing file input/output, and I am attempting to locate a string of characters within a json file and replace them with another string

I am currently writing a program that automates a game I play. I am doing this as a side project and I am currently stuck on a file input/output issue. All the text information stored inside the json file gets fully deleted once I finish running the program. I am trying to find certain phrase in a json file and then replace it with a different one. I made multiple functions to help assist me in doing this. I am utilizing one function to find the line specified within the file, and then another line to replace the string I located with a string I made, based on splicing using a mixture of hard-coded text and a user inputted string. I am aware that I am using cin >> rather than getline and using strings in c++ but I promise you that is not the issue at hand here. The problem is that my entire file's content is being deleted and I am not quite sure why. I will link my code below with a picture of the output and hopefully someone can help me out here because I am genuinely confused, especially since this seems like such a rudimentary task. I took out segments of the code because the entire project is pretty extensive, if there is anything missing down below or anything is unclear please let me know in the comments.
string FindFullLine(std::ifstream& file, unsigned int num){
std::string s;
for (int i = 1; i <= num; i++)
std::getline(file, s);
return s;
}
bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
^^ separate functions that are being used in this small piece of code below
string champo = " \"mainChamp\": ";
string apo = "\",";
string champ, ban, gamemode, newchamp;
cout << "What champion would you like to pick? " << endl;
cin >> champ; //getline doesnt work; cin is not causing the issue
cout << "\nWhat champion would you like to ban? " << endl;
cin >> ban;
cout << "\nWhat gamemode would you like to pick? " << endl;
cin >> gamemode;
newchamp = " \"mainChamp\": \"";
newchamp += champ;
newchamp.append(apo);
ifstream yuumi ("C:\\forfuncoding\\bot\\Yuumi Bot Extension Fix\\bot\\config.json"); //opening file stream for input
ofstream yuumi1 ("C:\\forfuncoding\\bot\\Yuumi Bot Extension Fix\\bot\\config.json"); //opening file stream for output
if(!yuumi || !yuumi1){
cout << "Error opening up files! " << endl;
exit(0);
}
string s = FindFullLine(yuumi, 2);
string temps;
string strTemp;
temps = s; //temporary val to store s
cout << s;
replace(s, s , newchamp); //first parameter is where new string is stored, second param is the old string and third param is what old string is being replaced by new string
cout << s;
while(yuumi >> strTemp)
{
if(strTemp == temps){
cout << s;
strTemp = s;
}
yuumi1 << strTemp;
}
yuumi.close(); //closes file for output
yuumi1.close(); //closes file for input
exit(0); //just for testing purposes
I have tried changing many values by passing them by reference/not by reference, I have tried using fstream with ios::out and ios::in, I have tried using getline, I have tried moving the logic around; making sure all the variables are scoped correctly. At first glance I thought the issue was in the replace function since it returns a bool but after further inspection it also works as is. Originally, the FindFullLine function was made for fstream, but I changed it to ifstream in the parameters, I don't believe that would change much however. I also tried getting rid of the ifstream and ofstream.close(); functions. I have tried practically everything I can think of.Down below is a screenshot of the format I was attempting to copy.
format of text in json file i was copying
I believe I formatted everything correctly in my code in order to match exactly what is happening in the text file. But when I run the code, everything disappears and the text file is blank. Linked down below is the output that I get, there is a cout << statement after the replace function is ran to ensure that everything is working as intended, and from the output's point of view, everything is working correctly.
output from console

Could I use `std::cin` for another input if I've exited it using `Ctrl+D`(EOF)?

I have this exercise from Programming principles and practice using C++ by B. Stroustrup:
Design and implement a Name_pairs class holding (name,age) pairs where
name is a string and age is a double . Represent that as a vector<string>
(called name ) and a vector<double> (called age ) member. Provide an input operation read_names() that reads a series of names. Provide a read_ ages() operation that prompts the user for an age for each name. Provide
a print() operation that prints out the ( name[i] , age[i] ) pairs (one per line)
in the order determined by the name vector. Provide a sort() operation
that sorts the name vector in alphabetical order and reorganizes the age vector to match. Implement all "operations" as member functions. Test
the class (of course: test early and often).
Here I show the part that causes the problem only for the brevity sake:
std::istream& Name_pairs::read_names(std::istream& in){
for(std::string str; in >> str; )
name.push_back(str);
in.clear();
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// the following lines are added just for testing the stream state
int x;
std::cout << "x: ";
std::cin >> x;
std::cout << x << '\n';
return in;
}
Now if I call the member function:
Name_pairs{}.read_names(std::cin);
I get prompted to enter names until I hit EOF (Ctrl+D). At that moment I follow it by clear and ignore to reset the input buffer. But I am not prompted to input x!!?
I've seen some suggestions that I should trigger a constant string as an exit mark like std::string quit = "quit; if(str == quit) break; but I don't want this; I want to use Ctrl+d then get input again. In other words can I use the input stream after pressing Ctrl+D?
I've tried the very program on windows 10 and Code::blocks for windows and it worked fine! I press Ctrl+D; the loop breaks then I am prompted to input x.
So how could I fix the problem? thanks
There is no standard way to reuse a closed/terminated stream, including cin.
Once cin is closed/terminated, it can't be reused by standard means. However, there may be non-standard, platform-specific ways to reopen it. Check your compiler/platform documentation.
That being said, nothing in the requirements you have shown will prevent you from prompting the user for the number of names to enter and then using an ordinary for loop, or simply asking the user to enter a termination string to stop reading. Rather than relying on Ctrl-D/Ctrl-Z to stop the reading, which is very platform-specific behavior.
It works on Windows because Ctrl+D isn't the EOF key combo on Windows, it's the end-of-text character. Ctrl+Z (plus Enter) is the EOF marker on Windows.
If cin actually hits EOF, it's done. Your code only works on Windows because you didn't actually hit EOF on Windows.
The most common (and obnoxious, IMHO) way is to first ask how many.
std::vector <std::string> names;
int n;
std::cout << "How many names? ";
std::cin >> n;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
while (n--)
{
std::string name;
getline( std::cin, name );
names.push_back( name );
}
The way I prefer is to simply terminate on the first empty line:
std::vector <std::string> names;
std::cout << "Enter names, one per line. Press ENTER twice to finish.\n";
while (true)
{
std::cout << "name? ";
std::string name;
getline( std::cin, name );
if (name.empty()) break;
names.push_back( name );
}
Now that you have a vector of names, you can ask for an age to go with each one:
std::vector <int> ages;
for (auto name : names)
{
std::cout << name << "’s age? ";
int n;
std::cin >> n;
ages.push_back( n );
}
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
Another common way, which is a variation of the “empty line” method I just showed you, is to use a sentinel value to terminate the input. It can be anything, like having the user enter “done” as the final name, or “-1” or something. You can guess my opinion on that nonsense.
As always, make sure you are reading your assignment correctly. If unsure, email your professor and ask clarification. Remember to ask an intelligent question, which shows your professor you aren’t just begging for an answer.

Editing a text file if searched value is present

I have just a couple issues here with my code. It works but I'm not advanced enough to do what I want to yet. Nor do I know how to word it for a google search. I have a Blackjack game that I'm doing and want to know how to edit certain lines of the file depending on user input. Simpler, I want a user to be able to open the game and start with their balance from the last time they were playing(a save and load feature). My issues are the balance and the username are on the same line in the text file (purposefully) and I want to assign the variables to those in the text file. I know I'm on the right track, I just dont know where to go from here. Thanks for the help in advance. If I broke a rule of posting, I'm sorry.
input username
if username is present in file
edit balance on leave
if username isnt present in file
create new user
Here is my code for the load function:
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
string word;
for (int x = 0; in >> word; x++);
{
user1.name = word;
user1.balance = word;
}
cout << user1.name << endl;
cout << user1.balance << endl;
in.close();
}
else
cout << "Cannot open a file";
}
void save(userAcc user1)
{
user1.balance = "1000";
cout << "Enter a username: ";
cin >> user1.name;
ofstream out;
out.open("Balances.txt", ios_base::app);
if (out.is_open())
{
out << user1.name << " " << user1.balance << endl;
out.close();
}
else
cout << "Cannot open a file";
}
In
for (int x = 0; in >> word; x++);
remove the trailing ;. It ends the statement before the body of the for loop, separating the two. The for spins around doing nothing but reading the file until it ends and incrementing the unused variable x and the following code block will be run exactly once, storing whatever is in word (and since the loop will exit when the read into word fails, what's in word will depend on the C++ Standard version the the compiler's been set to use) into user1.
Once the ; is removed, the for loop will read into word until no more words can be read from the file. Every word read is copied into the same userAcc writing over the previous word. When the file hits the end in >> word will fail and the loop will exit. The last word in the file will then be printed out, all other words having been overwritten.
Naïve fixing of this would look something like
void load(userAcc user1)
{
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
while (in >> user1.name // read name in from file
>> user1.balance) // read balance in from file
{ // loop will exit when it cannot read a name and a balance from the file
// for now we're just printing out what's read from the file.
cout << user1.name << endl << user1.balance << endl;
}
// in.close(); not needed. File will automatically close when in goes out of scope.
}
else
cout << "Cannot open a file";
}
But we probably want to do more than print out all of the users in the file, so let's put them into a convenient resizable container like std::vector.
vector<userAcc> load() // takes no parameters, returns list of accounts
{
vector<userAcc> accounts;
ifstream in;
in.open("Balances.txt");
if (in.is_open())
{
userAcc user1; // account we can read into
while (in >> user1.name >> user1.balance)
{
accounts.push_back(user1); // store account
}
}
else
cout << "Cannot open a file";
return accounts; // hand accounts read back to caller.
}
Use of the function would be something like
vector<userAcc> accounts = load();
The save function looks pretty much good-to-go as written.

How do I correctly use "getline(cin, input);"

I am writing a program that is to convert text that a user gives. I have tried this method by itself in a test program and it works perfectly; however when I try to implement it into the larger program, the user cannot give the program an input to store. The relevant code is as follows:
int main()
{
string str = "NULL";
int mappings = 0;
readMappings(mappings);
receiveInput(str);
displayInput(mappings, str);
return 0;
}
void readMappings(int &count)
{
ifstream readMappings; // Creates the function "readMappings"
string filename; // Generates the filename variable to search for mapping document
cout << "Enter the filename of the mapping document: ";
cin >> filename; // User enters filename
readMappings.open(filename); // "readMappings" function opens the given mappings document
while (!readMappings.is_open())
{
cout << "Unsble to open file. Please enter a valid filename: "; // If the user enters an invaled filename, the program will ask again
cin >> filename;
readMappings.open(filename);
}
if (readMappings.good()) // Mapping document is successfully opened
{
readMappings >> count; // Reads first line
}
readMappings.close(); // If everything fails in this function, the document will close
}
void receiveInput(string &input)
{
char correctness;
do {
cout << "\nPlease enter the text you would like to be converted to NATO:\n";
getline(cin, input);
cout << "You are about to convert: \"" << input << "\".\nIs this correct? (Y/N)" << endl;
cin >> correctness;
} while (correctness == 'N' || correctness =='n');
}
I thought it may have been the program waiting for another input from the user so I added a variable I assumed it would already fill, but it did not fix my solution. In my opinion, the problem is in the receiveInput function, but I could be wrong. Thanks in advance for any assistance.
Also, I am using function prototypes with correct reference variables.
I see two problems:
1) You're not checking for an EOF condition, after invoking std::getline().
2) You are mixing together both std::getline and the >> operator. Now, there's actually nothing technically wrong with that, but both std::getline and the >> operator have very nuanced semantics, when it comes to error checking and input consuming, that you need to get 100% right, in order to correctly use them together.
Just replace your usage of the >> operator with std::getline, so you're using std::getline exclusively, and make sure to check for fail() or eof(). You will find plenty of examples of how to correctly check for end of file and failure conditions, with std::getline, here on stackoverflow.com.

Odd behavior in C++ program

I am writing a program that I allow the user to specify an input file to open and when I test with incorrect file names, the program is behaving very weird and it seems to have something to do with the input buffer, but I don't know where to begin other than using getline() instead of cin >> but I have already tried that.
here is the code that I think may be the problem:
bool openfile(ifstream&);
string userInput();
int main()
{
// ...
while (!openfile(inputFile))
openfile(inputFile);
string input = userInput();
// ...
}
bool openfile(ifstream &inputFile)
{
string filename;
cout << "Please enter the name of the file or type quit to exit the program: ";
cin >> filename;
cout << endl;
if (filename == "quit")
exit(4);
else
inputFile.open(filename);
if (!inputFile)
{
cout << "The file \"" << filename << "\" could not be opened or does not exist.\n";
return false;
}
return true;
}
string userInput()
{
string englishSentence;
cout << "Please enter a sentence or type quit to exit the program: \n";
getline(cin, englishSentence);
if (englishSentence == "quit")
exit(4);
return englishSentence;
}
Those are the two functions that read any input. openfile() is called first as you can see. Any help is greatly appreciated. Let me know if you suspect something else in my code and I will paste it.
while (!openfile(inputFile))
openfile(inputFile);
What this does is attempt to open the file twice each iteration, as long as the first attempt fails. Also, you need to make sure that inputFile is closed before attempting to open it again since it appears that you're reusing the same file object repeatedly.
Certainly first try something like:
while (!openfile(inputFile))
;
You can just do:
while (!openfile(inputFile));
Since the way you have it it would request an input filename twice if it fails the first time.
Basically to outline the problem:
Begin Loop
Request Filename
Invalid Filename
Request Replacement Filename
Return to start of the loop (Checks again)
Some problems I see from your code:
int main(); { ... } does not define the main function. You need to drop the semicolon, or it won't even compile.
while (!openfile(inputFile)) openfile(inputFile); repeats openfile(inputFile) unnecessarily. If the first one (in the condition) fails and the second one (in the body) succeeds, a third call will be made (in the condition) to check if the loop should continue. What you probably want is just while (!openfile(inputFile)) { }.
You open a file in openfile and never use it in the subsequent userInput.