Fstreams C++ has extra spaces on writing - c++

I figured some stuff out, but I suck at fstreams, and this is just killing me, for BREED + DESC, they have a space between them and name, but when I remove them completely then I get no spaces and it works again. Could someone tell me what I'm doing wrong?
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
const int NAME_SIZE = 100;
const int BREED_SIZE = 100;
const int DESC_SIZE = 250;
const int REASON_SIZE = 250;
//creating the struct
struct animal
{
//members
char name[NAME_SIZE];
char breed[BREED_SIZE];
char desc[DESC_SIZE];
char reason[REASON_SIZE];
float age;
float weight;
int day;
int month;
int year;
float length;
};
class petAdoption
{
public:
petAdoption();
void enroll(animal newAnimal[], int & count);
void read(animal newAnimal[], int & count);
//void display(animal & newAnimal);
//void adopt(animal & newAnimal);
private:
};
petAdoption::petAdoption()
{
}
int main()
{
int count = 0;
animal * newAnimal = new animal[count];
petAdoption adopt;
adopt.read(newAnimal, count);
adopt.enroll(newAnimal, count);
delete[] newAnimal;
}
void petAdoption::read(animal newAnimal[], int & count)
{
int pets = 0;
ifstream read;
read.open("pets.txt");
if(!read)
{
cout << "Checking... File doesn't exist!" <<endl;
}
else
{
while(!read.eof())
{
read.getline(newAnimal[pets].name, NAME_SIZE, '\n');
read.ignore(100, '\n');
++pets;
}
count = pets + 1;
}
read.close();
for (int i = 0; i < pets; ++i){
read.open(newAnimal[i].name);
if( !read)
{
cout << "Checking... File doesn't exist!" <<endl;
}
else{
while(!read.eof())
{
read.getline(newAnimal[i].name, NAME_SIZE, '\n');
read.getline(newAnimal[i].breed, BREED_SIZE, '\n');
read.getline(newAnimal[i].desc, DESC_SIZE, '\n');
read.getline(newAnimal[i].reason, REASON_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[i].age;
read >> newAnimal[i].weight;
read >> newAnimal[i].day;
read >> newAnimal[i].month;
read >> newAnimal[i].year;
read >> newAnimal[i].length;
read.ignore(100, '\n');
}
}
read.close();
}
}
/*
ENROLL FUNCTION
*/
void petAdoption::enroll(animal newAnimal[], int & count)
{
//making a write variable
ofstream write;
//stores the name into the struct member
cout << "Please enter a name: ";
cin.get(newAnimal[count].name, NAME_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a breed: ";
cin.get(newAnimal[count].breed, BREED_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a desc: ";
cin.get(newAnimal[count].desc, DESC_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a reason (EG: eats people): ";
cin.get(newAnimal[count].reason, REASON_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter an age (EG: 5): ";
cin >> newAnimal[count].age;
cin.ignore(100, '\n');
cout << "Please enter a weight (in LBS): ";
cin >> newAnimal[count].weight;
cin.ignore(100, '\n');
cout << "Please enter a day (EG: 2): ";
cin >> newAnimal[count].day;
cout << "Please enter a month (EG: 11): ";
cin >> newAnimal[count].month;
cout << "Please enter a year (EG: 2002): ";
cin >> newAnimal[count].year;
cout << "How long has the pet been in a shelter? (in months): ";
cin >> newAnimal[count].length;
//error
if(!write)
{
cout << "Invalid File" << endl;
}
else{
write.open(newAnimal[count].name, ios::app);
write << newAnimal[count].name << '\n'
<< newAnimal[count].breed << '\n'
<< newAnimal[count].desc << '\n'
<< newAnimal[count].reason << '\n'
<< newAnimal[count].age << '\n'
<< newAnimal[count].weight << '\n'
<< newAnimal[count].day << '\n'
<< newAnimal[count].month << '\n'
<< newAnimal[count].year << '\n'
<< newAnimal[count].length << '\n';
write.close();
}
if(!write)
{
cout << "Invalid File";
}
else {
write.open("pets.txt", ios::app);
write << newAnimal[count].name << '\n';
write.close();
}
}

As people mention (in response to an earlier version of this question already) you shall not use eof() to control your loop . Furthermore you shall test that you successfully received your input after you [attempted] to read it.
The problem with extra newlines at the end if a line is due to your use of get() rather than getline(): the former retains the stop character while the latter does not. You should als consider using std::string together with std::getline(): it reads arbitrary length strings.

Related

Why the count in my main is not updated when i entered new patient info?

Why the count in my main is not updated when I entered new patient info? I don't know why for case 2 in my add function, the count in main will never increase. It remains at 20 only(same with my input text) even after I type in new patient info.
Here is my code:
struct PATIENT
{
string id;
string name;
string age;
string address;
string doc;
string diagnosis;
string status;
string date;
};
struct LIST
{
PATIENT patient[100];
};
void get_data(LIST* p, int* count);
void add(LIST* p, int* count);
int main()
{
LIST p;
int count, choice;
get_data(&p, &count);
cout << "The count is: " << count;
add(&p, &count);
}
void get_data(LIST* p, int* count)
{
int num = 0;
ifstream inFile;
inFile.open("input.txt");
if (!inFile)
{
cout << "Error to open an input file\n";
exit(0);
}
else
{
while (num < 100 && !inFile.eof())
{
getline(inFile, p->patient[num].id);
getline(inFile, p->patient[num].name);
getline(inFile, p->patient[num].age);
getline(inFile, p->patient[num].address);
getline(inFile, p->patient[num].doc);
getline(inFile, p->patient[num].diagnosis);
getline(inFile, p->patient[num].status);
getline(inFile, p->patient[num].date);
num++;
}
}
*count = num;
inFile.close();
}
void add(LIST* p, int* count)
{
system("cls");
int patientSelect = 2;
switch (patientSelect)
{
case 1: cout << "Existing patient";
break;
case 2:system("cls");
cout << "\t\t\t\tNew patient" << endl;
cout << "\t\t\t\t===========" << endl;
cout << "Enter patient ID: ";
cin.ignore();
getline(cin, p->patient[*count].id);
cout << "Enter patient name: ";
getline(cin, p->patient[*count].name);
cout << "Enter age: ";
cin >> p->patient[*count].age;
cin.ignore();
cout << "Enter address: ";
getline(cin, p->patient[*count].address);
cout << "Enter attending doctor's name: ";
getline(cin, p->patient[*count].doc);
cout << "Enter diagnosis: ";
getline(cin, p->patient[*count].diagnosis);
cout << "Enter patient status: ";
getline(cin, p->patient[*count].status);
cout << "Enter consultation date: ";
getline(cin, p->patient[*count].date);
*count++;
system("PAUSE"); system("cls"); main();
break;
case 3: system("cls"); main();
default:cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "Invalid input, please try again..." << endl;
system("PAUSE"); system("cls");
}
}
My output in main:
The count is 20(after add function)
This is c++ operator precedence. See e.g. https://en.cppreference.com/w/cpp/language/operator_precedence
Change *count++ to (*count)++. If you don't do this, your code is equivalent to *(count++), which is valid c++, but it just does nothing...
But I would rather pass an int reference to the functions, and not a pointer to int. This makes coding simpler and less error prone.
Another problem is that you call main again from inside add. But in main you start from scratch: read the data, etc. All you changes will always be overwritten. Please consider that:
void setup(LIST& p, int& count) {
get_data(&p, &count);
}
void update(LIST& p, int& count) {
while (true) {
cout << "Command (0:exit, 2:add, etc.): ";
int choice=0;
cin >> choice;
if (choice==0) {
break;
}
cout << "The count is: " << count;
add(&p, &count); /// <= I would also pass choice here as argument and use it instead of patientSelect, but please check your business logic.
}
}
int main()
{
LIST p;
int count=0;
setup(p, count);
update(p, count);
}
And of course, do NOT call main from anywhere any more. Remove all those calls to main.

Deleting a record from text file

I have got an assignment project to make a program using C++ which maintains a list of Students (their name, age, and GPA) in a text file. The program has the following functionality:
Insertion of record
Deletion of record
Searching of record
Updating a record
When deleting a record my code takes a string name as input and removes it from the text file. However the next two lines in the file (age & gpa for that student) are left. How do I remove those too?
Following is the code for my program.
#include <iostream>
#include <fstream>
using namespace std;
void writing();
void deleting();
void searching();
class student {
public:
int age = 0;
string name;
void SetGpa(float x)
{
gpa = x;
}
float GetGpa()
{
return gpa;
}
private:
float gpa = 0.0;
};
int main()
{
int opt;
cout << "Please Enter an option number to continue:\n ";
cout << "\nPress 1 for New Record insertion";
cout << "\nPress 2 for Record Deletion";
cout << "\nPress 3 for Searching a Record";
cout << "\nPress 4 for Updating a Record";
cout << "\nEnter option Number: ";
cin >> opt;
switch (opt)
{
case 1:
{
writing();
break;
}
case 2:
{
deleting();
break;
}
case 3:
{
searching();
break;
}
case 4:
{
deleting();
writing();
cout << "Record has been updated! ";
break;
}
}
}
void writing()
{
float a;
student moiz;
cout << "Please enter name of student: ";
cin >> moiz.name;
cout << "Please enter the age of student: ";
cin >> moiz.age;
cout << "Pleae enter the Gpa of student: ";
cin >> a;
moiz.SetGpa(a);
ofstream myfile;
myfile.open("record.txt", ios::app | ios::out);
myfile << endl << moiz.name << endl;
myfile << moiz.age << endl;
myfile << moiz.GetGpa();
myfile.close();
}
void deleting()
{
string line, name;
cout << "Please Enter the name of record you want to delete: ";
cin >> name;
ifstream myfile;
ofstream temp;
myfile.open("record.txt");
temp.open("temp.txt");
while (getline(myfile, line))
{
if (line != name)
temp << line << endl;
}
cout << "The record with the name " << name << " has been deleted if it exsisted" << endl;
myfile.close();
temp.close();
remove("record.txt");
rename("temp.txt", "record.txt");
}
void searching()
{
ifstream fileInput;
fileInput.open("record.txt");
string line, search;
cout << "Please enter the term to search: ";
cin >> search;
for (unsigned int curLine = 0; getline(fileInput, line); curLine++)
{
if (line.find(search) != string::npos)
{
cout << "found: " << search << " on line: " << curLine << endl;
}
else
{
cout << "Error! Not found on Line" << curLine << endl;
}
}
}
You can add an else clause to your statement checking the name, and introduce a counter of how many of the following lines should be skipped after name was found:
int skip = 0;
while (getline(myfile, line)) {
if ((line != name) && !(skip > 0)) {
temp << line << endl;
}
else {
if(skip == 0) {
skip = 2; // Skip the next two lines also
}
else {
--skip;
}
}
}

Over looping (Cout) in C++

#include <iostream>
#include <string>
#include <cctype>
using namespace std;
char hold;
string name;
char num1;
char num2;
int main() {
cout << "Hello!\n";
cout << "Tell me your name?: ";
cin >> name;
cout << "Well well well, if it isn't "<< name << "!\n";
cout << "Enter a NUMBER " << name << ": ";
cin >> num1;
while(!isdigit(num1)) {
cout << "Enter a NUMBER " << name << ": ";
cin >> num1;
}
cin >> hold;
system("pause");
return 0;
}
The problem is, it is overlooping the cout. How do I fix it?
Thanks.
A better way is to use std::stringstream (note: include sstream)
int getNumber()
{
std::string line;
int i;
while (std::getline(std::cin, line))
{
std::stringstream ss(line);
if (ss >> i)
{
if (ss.eof())
{
break;
}
}
std::cout << "Please re-enter your input as a number" << std::endl;
}
return i;
}
This replaces your while loop, and you make the call after asking for a number as you already figured out how to do.
The following is a shortened version of the original attempt. However, as with the original, it only checks a single character.
If I changed num1 to be an int then i'd need to check whether the input was valid as #Dieter Lucking mentioned.
#include <iostream>
using namespace std;
int main() {
char num1;
do {
cout << "\nEnter a number: ";
cin >> num1
} while(!isdigit(num1));
}
A bit of a variation on staticx's solution, which will pass Dieter Lücking's echo "" | test line.
I use an istringstream and get input until no more standard input or I get valid input. I pushed it all into a templated Get function that can be used for any type; you just need to give it a prompt for the user:
Get() function
template<typename T>
void Get(T& toSet, std::string prompt) // read from cin
{
std::string nextIn;
cout << prompt;
getline(cin >> std::ws, nextIn);
istringstream inStream(nextIn);
while(cin && !(inStream >> toSet))
{
inStream.clear();
cout << "Invalid Input. Try again.\n" << prompt;
getline(cin >> std::ws, nextIn);
inStream.str(nextIn);
}
if (!cin)
{
cerr << "Failed to get proper input. Exiting";
exit(1);
}
}
And you'd use it like so:
int myNumber = 0;
Get(myNumber, "Please input a number:");
Full code:
Live Demo
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template<typename T>
void Get(T& toSet, std::string prompt) // read from cin
{
std::string nextIn;
cout << prompt;
getline(cin >> std::ws, nextIn);
istringstream inStream(nextIn);
while(cin && !(inStream >> toSet))
{
inStream.clear();
cout << "Invalid Input. Try again.\n" << prompt;
getline(cin >> std::ws, nextIn);
inStream.str(nextIn);
}
if (!cin)
{
cerr << "\nFailed to get proper input. Exiting\n";
exit(1);
}
}
int main()
{
string name;
int num1 = -1;
cout << "\nHello!\n";
Get(name, "\nTell me your name?:");
cout << "\nWell well well, if it isn't "<< name << "!\n";
Get(num1, std::string("\nEnter a NUMBER, ") + name + ": ");
cout << "\nYou entered number: " << num1 << std::endl;
return 0;
}

Shopping cart assignment, concepts on getline()

I've been working on a shopping cart assignment lately and couldn't understand why would this code below not work.
I have to write a code that will output name, cost and quantity of items, for three items without using arrays.
At the end of the maximum of three items I have to display out the total cost of the items. Currently I'm stuck because after I add in a second item, it appears that the program does not ask for the first input (Item name). Here's the code:
#include <iostream>
int main() {
int total;
std::cout << "Item name:";
std::string itemName;
std::getline(std::cin,itemName);
std::cout << "Cost(in cents):";
int cost;
std::cin >> cost;
std::cout << "Quantity:";
int quantity;
std::cin >> quantity;
std::cout << "Do you want to add more items? (Y/N)";
char option;
std::cin >> option;
if (option == 'y') {
std::cout << "Item name:";
std::string itemName2;
std::getline(std::cin,itemName2);
std::cout << "Cost(in cents):";
int cost2;
std::cin >> cost2;
std::cout << "Quantity:";
int quantity2;
std::cin >> quantity2;
std::cout << "Do you want to add more items? (Y/N)";
char option2;
std::cin >> option2;
if (option2 == 'y') {
std::cout << "Item name:";
std::string itemName3;
std::getline(std::cin,itemName3);
std::cout << "Cost(in cents):";
int cost3;
std::cin >> cost3;
std::cout << "Quantity:";
int quantity3;
std::cin >> quantity3;
total = cost*quantity + cost2*quantity2 + cost3*quantity3;
std::cout << "Total value:" << total;
}
else {
total = cost*quantity + cost2*quantity2;
std::cout << "Total value:" << total;
}
}
else {
total = cost*quantity;
std::cout << "Total value:" << total;
}
return 0;
}
After I input 'y' after every item input, the code would somehow skip my input for itemName and output the 'Cost(in cents):' together with 'Item name:' in the same line.
I do think that it's got something to do with the getline() function, but I do not know exactly what. Any help is greatly appreciated.
Frsitly, you are using getline and haven't included <string> header file.
2ndly, you may be facing issue because of cin buffer. you should use cin.ignore() after taking input for option for extracting the characters and discarding or other option may be clearing cin buffer.
cin.ignore() will work for ignoring 1 character in stream.
you can try std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
This will extract as many characters till ``\n''
I tried following code on VS2012, and it worked properly.
#include <iostream>
#include <string>
int main() {
int total;
std::cout << "Item name:";
std::string itemName;
std::getline(std::cin,itemName);
std::cout << "Cost(in cents):";
int cost;
std::cin >> cost;
std::cout << "Quantity:";
int quantity;
std::cin >> quantity;
std::cout << "Do you want to add more items? (Y/N)";
char option;
std::cin >> option;
std::cin.ignore();
if (option == 'y') {
std::cout << "Item name:";
std::string itemName2;
std::getline(std::cin,itemName2);
std::cout << "Cost(in cents):";
int cost2;
std::cin >> cost2;
std::cout << "Quantity:";
int quantity2;
std::cin >> quantity2;
std::cout << "Do you want to add more items? (Y/N)";
char option2;
std::cin >> option2;
std::cin.ignore();
if (option2 == 'y') {
std::cout << "Item name:";
std::string itemName3;
std::getline(std::cin,itemName3);
std::cout << "Cost(in cents):";
int cost3;
std::cin >> cost3;
std::cout << "Quantity:";
int quantity3;
std::cin >> quantity3;
total = cost*quantity + cost2*quantity2 + cost3*quantity3;
std::cout << "Total value:" << total;
}
else {
total = cost*quantity + cost2*quantity2;
std::cout << "Total value:" << total;
}
}
else {
total = cost*quantity;
std::cout << "Total value:" << total;
}
system("pause");
return 0;
}
For details on cin.ignore() see this link.
You should use
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
For remove \n, remained after inputting option.
you can do:
std:cin>>itemName
instead of doing:
std::getline(std::cin,itemName)
This would be the easiest approach for the strings without spaces!

C++ FSTREAM & classes

Okay so when I started using classes to make functions, it gives me an error file is invalid, normally doesn't if I don't use classes. If you run it, enter in some info, and then run it again, normally it should read in the data correctly, it still reads it in, but it says there's an error. I don't really know what I'm doing wrong, any tips? Thanks!
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
const int TEMP_SIZE = 10;
const int NAME_SIZE = 100;
const int BREED_SIZE = 100;
const int DESC_SIZE = 250;
const int REASON_SIZE = 250;
const int ID_SIZE = 50;
//creating the struct
struct animal
{
char name[NAME_SIZE];
char ID[ID_SIZE];
char breed[BREED_SIZE];
float age;
float weight;
char desc[DESC_SIZE];
char reason[REASON_SIZE];
int day;
int month;
int year;
float length;
};
struct adopted
{
char hostName[100];
char hostAddress[100];
int numPets;
};
class petAdoption
{
public:
petAdoption();
//~petAdoption();
void enroll(animal newAnimal[]);
void read(animal newAnimal[]);
private:
int count;
int numPets;
int * pets;
};
petAdoption::petAdoption()
{
count = 0;
pets = NULL;
numPets = 0;
}
void petAdoption::enroll(animal newAnimal[])
{
cout << "Please enter your pet's name: ";
cin.get(newAnimal[count].name, NAME_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter a unique ID for your pet (combinations of numbers EG: 432FD3): ";
cin.get(newAnimal[count].ID, ID_SIZE, '\n');
cin.ignore(100, '\n');
cout << "What type of breed is your pet?: ";
cin.get(newAnimal[count].breed, BREED_SIZE, '\n');
cin.ignore(100, '\n');
cout << "How old is your pet?: ";
cin >> newAnimal[count].age;
cin.ignore(100, '\n');
cout << "How much does your pet weigh? (in LBS): ";
cin >> newAnimal[count].weight;
cin.ignore(100, '\n');
cout << "Please describe your pet's personality!: ";
cin.get(newAnimal[count].desc, DESC_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please explain why the pet is being put up for adoption: ";
cin.get(newAnimal[count].reason, REASON_SIZE, '\n');
cin.ignore(100, '\n');
cout << "Please enter your pet's day of birth (1-31): ";
cin >> newAnimal[count].day;
cin.ignore(100, '\n');
cout << "Please enter your pet's month of birth (1-12): ";
cin >> newAnimal[count].month;
cin.ignore(100, '\n');
cout << "Please enter your pet's year of birth (1900-2012) : ";
cin >> newAnimal[count].year;
cin.ignore(100, '\n');
cout << "Please enter the length of time your pet has spent in a shelter (in months): ";
cin >> newAnimal[count].length;
cin.ignore(100, '\n');
/*** WRITES the pet ID into the list of pets***/
ofstream write;
write.open("pets.txt", ios::app);
write << newAnimal[count].name << '\n';
write.close();
/*** WRITES EACH PET INFO ****/
//this opens the file / creates a file if it's not made yet
//and it writes the pet's information
write.open(newAnimal[count].name, ios::app);
write << newAnimal[count].name << '\n'
<< newAnimal[count].ID << '\n'
<< newAnimal[count].breed << '\n'
<< newAnimal[count].age << '\n'
<< newAnimal[count].weight << '\n'
<< newAnimal[count].desc << '\n'
<< newAnimal[count].reason << '\n'
<< newAnimal[count].day << '\n'
<< newAnimal[count].month << '\n'
<< newAnimal[count].year << '\n'
<< newAnimal[count].length << '\n';
//this closes the file
write.close();
}
void petAdoption::read(animal newAnimal[])
{
ifstream read;
//open the file apps.txt
read.open("pets.txt");
//if apps.txt doesn't exist, then print out this error
if(!read)
{
cout << "pets.txt doesn't exist! This is your first time!" <<endl;
}
//else if it does exist, read in the names and store them back
//into the struct member name(s)
else
{
//while the document isn't empty
//read in each line
while(!read.eof())
{
read.getline(newAnimal[count].name, NAME_SIZE, '\n');
++count;
}
count = count-1;
}
//close the file
read.close();
for (int i = 0; i < count; ++i)
{
//open the file of the name of the app
read.open(newAnimal[count].name);
//if the file doesn't exist
//then we probably deleted it
//without removing it from the apps.txt
//but it prints out an error
if( !read)
{
cout << "invalid file!" <<endl;
}
//however if the file does exist,
//read in each line and store them back
//into the struct members
while(!read.eof())
{
read.getline(newAnimal[count].name, NAME_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].ID, ID_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].breed, BREED_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[count].age;
read.ignore(100, '\n');
read >> newAnimal[count].weight;
read.ignore(100, '\n');
read.getline(newAnimal[count].desc, DESC_SIZE, '\n');
read.ignore(100, '\n');
read.getline(newAnimal[count].reason, REASON_SIZE, '\n');
read.ignore(100, '\n');
read >> newAnimal[count].day;
read >> newAnimal[count].month;
read >> newAnimal[count].year;
read >> newAnimal[count].length;
read.ignore(100, '\n');
}
//close the file
read.close();
}
}
int main()
{
animal newAnimal[10];
petAdoption adopt;
adopt.read(newAnimal);
adopt.enroll(newAnimal);
}
I think I know what's going on. when you say read.open("pets.txt"); it should say read.open("pets.txt"),ios::app because then it so snot delete the data it already stores. Also go in to your file explorer and search pets.txt and read it to see what's going on. I hope I helped you.