How can i fix my program using c++ file io? - c++

I have this programming project on file i/o in c++. I have read up about it but don't understand much of it yet. Regardless, I made this program that allows the user to store the profile ( name, ethnicity etc. ) of a person onto a text file and be able to retrieve it. However, i am encountering some issues with how it works.
what it does is at the start it asks the user if they want to view the previously created file or create a new one.
if view a previous file was selected the program will then spit out the whole text file
if creating a new file is selected the program will ask for the number of people then proceed to ask for the name, age, gender, species, ethnicity and mode of transport for the allocated number of people and save it onto the text file.
the problem is i am unable to set the number of people as the program ignores the variable (i.e. i set 5 people and it ignores it)
and the program ignores the first name entered by skipping it.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char names[100];
char age[100];
char gender[100];
char species[100];
char ethnicity[100];
char transport[100];
char decision[0];
string getcontent;
cout << "Would You Like to Open The Previous File Or View Your Profiles?" << endl << endl;
cout << "Enter 1 For Previous File" << endl;
cout << "Enter Anything Else To View Your Profiles: " << decision;
cin.getline(decision,5);
cout << endl << "==============================================================" << endl;
if(decision[0] == '1')
{
ifstream infile;
infile.open("File of names.txt");
while(! infile.eof())//eof stand for end of file
{
getline(infile, getcontent); //getline requires a string
cout << getcontent << endl;
}
cout << "==============================================================" << endl;
infile.close(); //closes the opened file - good practice
}
else
{
int a;
cout << "Enter The Amount Of People You Would Like To Store: ";
cin >> a;
ofstream namefile;
namefile.open("File of names.txt");
cout << "Please Set Your Team Profile." << endl;
for (int i=0; i<a; i++)
{
cout << "==============================================================" << endl;
cout << "Enter Student " << i+1 << " : ";
cin.getline(names,100);
namefile << names << endl;
cout << "==============================================================" << endl;
cout << "Enter The Age: ";
cin.getline(age,100);
namefile << age << endl;
cout << "Enter The Gender: ";
cin.getline(gender,100);
namefile << gender << endl;
cout << "Enter The Species: ";
cin.getline(species,100);
namefile << species << endl;
cout << "Enter The Ethnicity: ";
cin.getline(ethnicity,100);
namefile << ethnicity << endl;
cout << "What Is The Mode Of Transport: ";
cin.getline(transport,100);
namefile << transport << endl << endl;
}
namefile.close();
}
}
This is the output of the file:
Would You Like to Open The Previous File Or View Your Profiles?
Enter 1 For Previous File
Enter Anything Else To View Your Profiles: g
==============================================================
Enter The Amount Of People You Would Like To Store: 5
Please Set Your Team Profile.
==============================================================
Enter Student 1:==============================================================
Enter The Age:
This is the expected output:
Would You Like to Open The Previous File Or View Your Profiles?
Enter 1 For Previous File
Enter Anything Else To View Your Profiles: g
==============================================================
Enter The Amount Of People You Would Like To Store: 5
Please Set Your Team Profile.
==============================================================
Enter Student 1: John
==============================================================
Enter The Age:

The problem is that for example when you input a value like:
string str;
cin>>str;
and you insert "John", you are not assign "John" to str, but "John\n" (note \n, that is created when you type enter on the keyboard). A possible solution to ignore it, is using cin.ignore();
However probably your homework is to make a very simple "database", so you will have to memorize the data in an orderly way, then i will suggest you to use "struct" (it's easy, not difficult for beginners).

Related

Why isn't my file reading the inputs correctly in this program?

So I'm trying to build a program for myself(for the time being) where basically I have the option of adding in books that I've completed, including the name of the author and the dates of completion, which is supposed to add the input into a file, and then I have another option that's supposed to just read off the entries onto the txt file line by line to display each entry. The only problem is that when I'm inputting each entry, I can't seem to get passed the input for "author", and when it's stored into the file it looks like this for example: (after inputting "for whom the bell tolls") for/twhom/t0-858993460-858993460. It also doesn't seem to retain the entries past the first(incomplete) entry.
Anybody have suggestions for how I could fix this? File handling is definitely something that I've had some of the most trouble with, so I'd really appreciate figuring out how to fix similar problems I might have in the future.
Sample of what the input file should look like:
Title: Author: Date:
book1 name1 01-01-2022
book2 name2 01-02-2022
book3 name3 01-03-2022
Here's the source:
`
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Program will enter books into a file and display the amount of books read, and the completed books
int main() {
fstream completedBooks;
int booksRead,
monthOfCompletion,
dayOfCompletion,
yearOfCompletion,
option;
string bookTitle,
author,
booksFinished;
cout << "book tracker: \n" << "1.) add entry \n" << "2.) print list \n";
cout << "Enter which option you would like to choose: \n";
cin >> option;
if (option == 1) {
completedBooks.open("completedBooks.txt", ios::out);//writing into book list
if (completedBooks.is_open()) {
completedBooks << "Title: Author: Date:" << endl;
completedBooks.close();
}
completedBooks.open("completedBooks.txt", ios::app);//appending input into book list
if (completedBooks.is_open()) {//Gathering input for book
cout << "Enter the name of the most recent book you've read: \n";
cin >> bookTitle;
//Gathering input for author
cout << "Enter the name of the author of that book: \n";
cin >> author;
//Getting input for dates
cout << "Enter the month you completed the book: \n";
cin >> monthOfCompletion;
cout << "Enter the day you completed the book: \n ";
cin >> dayOfCompletion;
cout << "Enter the year you completed the book: \n ";
cin >> yearOfCompletion;
//Storing input into file
completedBooks << bookTitle << "/t" << author << "/t"
<< monthOfCompletion << dayOfCompletion << yearOfCompletion;
completedBooks.close();
}
}
if (option == 2) {
completedBooks.open("completedBooks.txt", ios::in);
if (completedBooks.is_open()) {//displaying text in book list
string line;
while (getline(completedBooks, line)) {
cout << line << endl;
}
completedBooks.close();
}
}
return 0;
}
You have to flush cin before reading the line.
If you use this, should do the trick:
if (completedBooks.is_open())
{ // Gathering input for book
cout << "Enter the name of the most recent book you've read: \n";
cin >> ws;
getline(cin, bookTitle);
// Gathering input for author
cout << "Enter the name of the author of that book: \n";
cin >> ws;
getline(cin, author);
// Getting input for dates
cout << "Enter the month you completed the book: \n";
cin >> monthOfCompletion;
cout << "Enter the day you completed the book: \n";
cin >> dayOfCompletion;
cout << "Enter the year you completed the book: \n";
cin >> yearOfCompletion;
// Storing input into file
completedBooks << bookTitle << "\t" << author << "\t"
<< monthOfCompletion << "-" << dayOfCompletion << "-" << yearOfCompletion;
completedBooks.close();
}
Altough, to get the desired output you will have to format the line to write in the file. You can use setw to give a maximum width to the title and author.

Code not allowing user input in strings after first string

I have looked around and can't seem to find an answer to this. I am new to C++ and am attempting to write a program for a class that asks the user for the first and last names of 4 students and their ages. The program will then display the input names and ages and also display the average of the ages.
The issue I am having is that the program allows for input of the first name and age but then skips over the remaining three name input fields and only allows for the remaining three ages to be input.
I apologize if this ends up being a dumb question but I really am at a loss. Any help will be greatly appreciated.
Here is the code I have thus far:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string studentname1;
cout << "Please enter the first student's full name:" << endl;
getline(cin, studentname1);
int age1;
cout << "Please enter the first student's age:" << endl;
cin >> age1;
string studentname2;
cout << "Please enter the second student's full name:" << endl;
getline(cin, studentname2);
int age2;
cout << "Please enter the second student's age:" << endl;
cin >> age2;
string studentname3;
cout << "Please enter the third student's full name:" << endl;
getline(cin, studentname2);
int age3;
cout << "Please enter the third student's age:" << endl;
cin >> age3;
string studentname4;
cout << "Please enter the fourth student's full name:" << endl;
getline(cin, studentname2);
int age4;
cout << "Please enter the fourth student's age:" << endl;
cin >> age4;
cout << "Hello from our group." << endl;
cout << "NAME AGE" << endl;
cout << studentname1 << " " << age1 << endl;
cout << studentname2 << " " << age2 << endl;
cout << studentname3 << " " << age3 << endl;
cout << studentname4 << " " << age4 << endl;
cout << "The average of all our ages is: " << (age1 + age2 + age3 + age4) / 4.00 << endl;
return 0;
}
Since the age variables are int, the cin >> age1; will leave the newline character in the input stream. When next you call getline(), you will get the remainder of that line - which is empty, and so on.
Also, you have a copy-paste bug in your code. getline(cint, studentname2); is run for students 2, 3 and 4.
You can either solve the problem by using getline() for all input:
string agestring;
getline(cin, agestring)
stringstream(agestring) >> age1;
or clear cin when you're done reading the age:
cin >> age1;
cin.ignore();

Weird Text File Output and Writing Issues

In my code:
int newEntry()
{
string input;
Client person;
char response = 'y';
//create file object and open file
fstream customer("customer.dat", ios::out | ios::app);
if (!customer)
{
cout << "Error opening file. Program aborting." << endl;
return 0;
}
do
{
cout << "Enter person information:" << endl << endl;
cout << "Name: " << endl;
getline(cin, input);
strcpy(person.name, input.c_str());
cout << endl << "Street Adress (And Apartment Number):" << endl;
cin >> person.address1;
getline(cin, input);
strcpy(person.address1, input.c_str());
cout << endl << "City, State, Zipcode: " << endl;
cin >> person.address2;
getline(cin, input);
strcpy(person.address2, input.c_str());
cout << endl << "Phone: " << endl;
cin >> person.phone;
getline(cin, input);
strcpy(person.phone, input.c_str());
cout << endl << "Account Balance: " << endl;
cin >> person.acctBal;
//input validation to ensure a non neg number
cin.ignore();
cout << endl << "Last Payment: " << endl;
cin >> person.lastPay;
//input validation to ensure a non neg number
customer.write(reinterpret_cast<char *>(&person),
sizeof(person));
cout << endl << "Do you want to enter another record? (Enter Y for Yes, N
for No) " << endl;
cin >> response;
cout << "_______________________________________________" << endl << endl;
if (toupper(response) == 'Y')
{
cin.ignore();
}
} while (toupper(response) == 'Y');
customer.close();
return 1;
}
It seems as though the block:
cout << endl << "Street Address (And Apartment Number):" << endl;
cin >> person.address1;
getline(cin,input);
strcpy(person.address1, input.c_str());
and its neighboring address 2 prompt (identical) are causing bad output to the file when
customer.write(reinterpret_cast<char *>(&person),sizeof(person));
is used to write to the file. The output is missing the very first word . For example if "211 Harvey Road" was entered, 211 would be cut off. Another example, if "Harvey Road" was entered, than it seems as though "harvey" is cut off. When (in another function) the file is read, the structure of arrays is missing the beginning, as well as the file.
On top of that, in the textfile, this is the data being written to it:
Frank Palmasani ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ Harvey Road ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ Haven, Alabama ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ 504617772 ÌÌÌÌ èŽ# èŽ#James Harris ni ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ Street AVEN ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ China. Alabama ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ 546457474 ÌÌÌÌ ð? ð?
As you can see, where the Ì are popping up is where the file and program are somehow losing the first word. I have tried everything I can think of to fix this problem, hopefully someobody else has ran into a similar problem.
I have tried changing methods of saving the data held in the structure of arrays to the file, but found that I couldn't read from the file in one large grouping. In my text book, the method I used to read out to the file is used so that is the one I believe I should follow.
However, I am considering writing each one separately on each line, and saving it precisely in the order so that I can read it in the same order, saving it to a structure of vectors. Again, I'd I would like to avoid that but would love to hear your opinion on the matter whether if you are able to help me here or not.
In case you needed it, here is my structure:
const int NAME_SIZE = 51, ADDR_SIZE = 51, PHONE_SIZE = 14;
struct Client
{
char name[NAME_SIZE];
char address1[ADDR_SIZE];
char address2[ADDR_SIZE];
char phone[PHONE_SIZE];
double acctBal;
double lastPay;
};
Your output file looks like that because you are doing a raw dump of the Client struct. So there will be 51 bytes written for name, 51 for address1, etc. Regardless of string length.
You need to properly write each field individually.
customer << input.name << endl;
customer << input.address1 << endl;
etc.....
cout << endl << "Street Adress (And Apartment Number):" << endl;
cin >> person.address1;
getline(cin, input);
strcpy(person.address1, input.c_str());
You're getting the first token, in the case you mentioned 211 and putting it in address1, then getting the rest of the line and replacing what was in address1 with it. That's where your 211 went.
You should open the file in binary mode if your intent is to write/read entire structures as a binary blob like this. If you want to store the data as text use std::string, avoid the strcpy mess, and write/read each member individually on their own ines.

C++ Won't Accept # symbol in object string? Seems to be address issue maybe?

I am so lost. I am having an issue with the following code when saving and loading data to a binary file. I have a very similar/exact piece of code that works with a different object. I think it has something to do with the email address and the # symbol in it. Here are the important functions.
/* This is my save to file function */
FILE *file=fopen("patronsave","wb");
fwrite(&buffer,sizeof(buffer),1,file);
for(int i=0;i<3;i++){
Patron_Class *ppointer = new Patron_Class();
cout << "\n" << endl;
ppointer->save(file);
}
fclose(file);
That is the function I use to save my objects to a file.
Here is my code that I am using to load the file:
vector<Patron_Class*> Patron_Entries;
FILE *file=fopen("patronsave","rb");
fread(&buffer,sizeof(buffer),1,file);
printf("Buffer: %d\n",buffer);
for(int i=0;i<buffer;i++){
Patron_Class *pointer2 =new Patron_Class(file);
Patron_Entries.push_back(pointer2);
Patron_Entries[i] -> print();
system("pause");
}
fclose(file);
If I run the save function and then immediatly run the load function it works, but if I only run the load function it crashes when it tried to load the email. Here is my class and object code:
class Patron_Class{
public:
long patron_id;
string F_name;
string L_name;
long phone_num;
string email;
string street_address;
string city;
string state;
int zip_code;
Patron_Class(){
cout << "Please enter a new ID" << endl;
cin >> patron_id;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a First name" << endl;
cin >> F_name;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a last name" << endl;
cin >> L_name;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a phone number" << endl;
cin >> phone_num;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a email" << endl;
cin >> email;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a street address" << endl;
cin >> street_address;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a city" << endl;
cin >> city;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a State via it's initials" << endl;
cin >> state;
cin.ignore(1000, '\n');
system("cls");
cout << "Please enter a zip code" << endl;
cin >> zip_code;
cin.ignore(1000, '\n');
system("cls");
cout << "You have created a new patron named: " << F_name << " " << L_name << endl;
}
Patron_Class(FILE *inputfile){
fread(&patron_id, sizeof(patron_id),1,inputfile);
fread(&F_name, sizeof(F_name),1,inputfile);
fread(&L_name, sizeof(L_name),1,inputfile);
fread(&phone_num, sizeof(phone_num),1,inputfile);
fread(&email, sizeof(email),1,inputfile);
fread(&street_address, sizeof(street_address),1,inputfile);
fread(&city, sizeof(city),1,inputfile);
fread(&state, sizeof(state),1,inputfile);
fread(&zip_code, sizeof(zip_code),1,inputfile);
}
void print(){
cout << patron_id << " " << F_name << " " << L_name << " " << phone_num << " " << email << " " << street_address << " " << city << " " << state << " " << zip_code << "\n" << endl;
}
void save(FILE *inputFile){
fwrite(&patron_id, sizeof(patron_id),1,inputFile);
fwrite(&F_name, sizeof(F_name),1,inputFile);
fwrite(&L_name, sizeof(L_name),1,inputFile);
fwrite(&phone_num, sizeof(phone_num),1,inputFile);
fwrite(&email, sizeof(email),1,inputFile);
fwrite(&street_address, sizeof(street_address),1,inputFile);
fwrite(&city, sizeof(city),1,inputFile);
fwrite(&state, sizeof(state),1,inputFile);
fwrite(&zip_code, sizeof(zip_code),1,inputFile);
}
};
Does anyone know why it might be crashing?
This is CLEARLY wrong:
string F_name;
...
fread(&F_name, sizeof(F_name),1,inputfile);
...
fwrite(&F_name, sizeof(F_name),1,inputFile);
[The same applies to all the other strings in your PatronClass - I'm using the first one for this example]
The class std::string will look something like this (for illustration purposes, the exact implementation involves several layers, some templates, and other stuff, so this is simplified for the purposes of the explanation to follow):
class string
{
char *str;
int len;
public:
...
};
So, when you do fread from the file and fwrite to the file, you are reading/writing the char *str; and int len; members from/to the file.
Let's say we start your program from scratch, with no data in the file, and we use the Patron_Class() constructor. So we read in an id, and then the F_name from the console. Let's say we enter Charles. So somehow the string class will allocate 8 bytes of memory, at the address of 0x600018. So string::str == 0x600018 and len = 8 - at location 6000018 in the heap are the letters C h a r l e s \0 [ spaces just to illustrate they are in separate memory locations]. Now we save this to a file. So the file contains 00600018 00000008. Now we stop the program and start it again, using the PatronClass(file) constructor. The heap is completely empty. We load the file data, so string::str = 0x600018 and len = 8, but that locaton 0x600018 does not contain C h a r l e s \0, but whatever the heap normally is filed with when the heap is initialized [quite likely 0]. So no wonder your name doesn't appear.
Now, the exact behaviour of your actual program is probably not the same as what I've described above, but it will NOT work right. No way, never, ever. No matter what characters you have or haven't got in names, email addresses or any other string in your code. The only reason it may APPEAR to work is that the data is still, for the most part, there in the heap, and it seems to be working because it doesn't get overwritten by something else in your case.

Why getline does not work in a switch, and cin does not take the data appropriately?

I need to take in the make model and years of the car the particular product fits. The program is going to write a file with text in it that will be an outline of the html. I need with the crucial information inserted into the correct spots to quickly be able to add products to our web page. When I use a switch statement or if statements to separate the categories of the products, the input gets messed up and does not let me answer one of the questions. I can't just use cin because I need to take dates that look like "2008 - 2009 - 2010 - 2011".
Here is what I've got so far! This one is just regular cin, I have tried getline you could quickly c I started yesterday and I'm pretty new so forgive me if this is an easy fix, but I cant find anything.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void proinfo();
int main()
{
//Sytem Information
system("TITLE This is a Beta of My Product Information Template Version 0.0.2");
//I'm using this as a welcome screen to inform users of new improvements on patches and other pertinent information to the users
cout << "Welcome To My Product Information Template Maker!!! \n It Is Still In Development" << endl;
cout << "\n\nworking features are:" << endl << "\t-None\n" << endl;
system("PAUSE");
system("CLS");
proinfo();
}
void proinfo()
{
//Declare Variables here
int loop(1), protype;
char make[256], model[256], year[256];
string getinput;
while(loop==1)
{
//This is the first menu the user sees where they have to choose what type
//of products users will be adding
system("CLS");
cout << "Welcome to My Product Information Template Version 0.0.0" << endl;
cout << "Please select the number of the product" << endl;
cout << "type you will be ading!\n" << endl;
cout << "1.Fe - Fe2 Moldings" << endl;
cout << "2.CF - CF2 Moldings" << endl;
cout << "What would you like to do? ";
cin >> protype;
if(protype==1)
{
//FE - FE2 Molding
system("cls");
cout << "You have selected" << endl;
cout << "Fe - Fe2 Moldings\n" << endl;
cout << "Please Enter the Make of the molding" << endl;
cin >> make;
cout << "Please Enter the Model of the molding" << endl;
cin >> model;
cout << "Please Enter the Years this molding fits" << endl;
cin >> year;
cout << "You have just created a template for a(n)" << year << " " << make << " " << model << endl;
cout << "Check My Documents For a file called Fe-Fe2template.txt" << endl;
//Asks to quit or restart
cout << "Would you like to make another tempalte?" << endl;
cin >> getinput;
if(getinput=="yes")
{
cout << "Great, Lets keep working!" << endl;
//End of If statement
}
system("PAUSE");
}
if(protype==2)
{
//CF - CF2 Molding
system("cls");
//Asks to quit or restart
cout << "Would you like to make another tempalte?" << endl;
cin >> getinput;
if(getinput=="yes")
{
cout << "Great, Lets keep working!" << endl;
//End of If statement
}
system("PAUSE");
//End of Protype Switch Statement
}
//End of while loop
}
//End of Proinfo()
}
Change year[256] to string year;
Change cin >> year; to getline(cin, year);
Add the line cin.ignore(); before the getline.
Your main problem is that the stream operator >> leaves the newline in the stream so when you try to use getline it reads an empty line. ignore() will chew up the newline and let you read the string you expect.
So this should get you on your way.
cin.ignore();
cout << "Please Enter the Years this molding fits" << endl;
getline(cin, year);
You have some other small problems but you'll figure them out. The worst is forgetting to terminate the loop.
if(getinput=="yes")
{
cout << "Great, Lets keep working!" << endl;
//End of If statement
}
else
{
loop = 0;
continue;
}