Combine input and output streams - c++

I want to combine both input and output stream to the output stream.
I mean, if this is my code:
int num;
string str;
cout << "string: ";
cin >> str;
cout << "num: ";
cin >> num;
cout << "num is " << num << " str is " << str;
And I redirect the input stream to a txt file contains:
hey 1
My output stream will contain:
string: hey
num: 1
num is 1 str i hey
insted of:
string: num: num is 1 str is hey
I don't want to cout each variable in cin after I get my input. I want it to be automatically.

Overload std::istream::operator >> for a wrapper class and do what you like:
// Example program
#include <istream>
#include <string>
#include <vector>
class AutoCinToCoutReader {
public:
inline void write(const std::string& in) { std::cout << in << std::endl; }
};
std::istream& operator >> (std::istream& is, AutoCinToCoutReader& dt)
{
std::string in;
is >> in;
dt.write(in);
return is;
}
void read(const std::string& what, AutoCinToCoutReader& rd) {
std::cout << what << ": ";
std::cin >> rd;
}
int main()
{
AutoCinToCoutReader rd;
std::vector<std::string> fields = { "Test1", "Test2" };
for(const std::string& field : fields) {
read(field, rd);
}
}
Update:
The smallest thing I could offer is:
// Example program
#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
std::istream& operator >> (std::istream& is, std::ostream& os) {
std::string in;
is >> in;
os << in << std::endl;
return is;
}
void read(const std::string& what) {
std::cout << what << ": ";
std::cin >> std::cout;
}
int main()
{
std::vector<std::string> fields = { "Test1", "Test2" };
for(const std::string& field : fields) {
read(field);
}
}
You can not immediately write into cout from cin. In any case, you need to work around it. See the updated operator, directly outputting to cout after storing in cin.

Related

How to add unlimited count of records to .txt file in C++

I'm new to coding and I'm creating "Phone book" program. I want to add records to .txt file and for now everything is fine. When I want to add another record to file, it deletes the previous one and save only the last one entered. I want to store all records but have no idea how to do that.
Here is the peace of my code, this is header file:
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <ostream>
class Person
{
public:
std::string firstName;
std::string lastName;
std::string number;
std::string EGN;
Person()
{
init();
}
void init()
{
firstName = "";
lastName = "";
number = "";
EGN = "";
}
std::string getFirstName() const
{
return firstName;
}
std::string getLastName() const
{
return lastName;
}
std::string getNumber() const
{
return number;
}
std::string getEGN() const
{
return EGN;
}
void setFirstName(const std::string& fn)
{
firstName = fn;
}
void setLastName(const std::string& ln)
{
lastName = ln;
}
void setNumber(const std::string& num)
{
number = num;
}
void setEGN(const std::string& pin)
{
EGN = pin;
}
static void addRecord();
static void SearchRecord();
static void deleteRecord();
static void ShowRecord();
friend std::ostream & operator << (std::ostream &out, const Person & obj)
{
out << obj.getFirstName() << "\n" << obj.getLastName() << "\n" << obj.getNumber() << "\n" << obj.getEGN() << std::endl;
return out;
}
friend std::istream & operator >> (std::istream &in, Person &obj)
{
std::string firstName1;
std::string lastName1;
std::string number1;
std::string EGN1;
in >> firstName1;
in >> lastName1;
in >> number1;
in >> EGN1;
obj.setFirstName(firstName1);
obj.setLastName(lastName1);
obj.setNumber(number1);
obj.setEGN(EGN1);
return in;
}
};
and this is the function:
#include <fstream>
#include <iostream>
#include <string>
#include <ostream>
#include <iterator>
#include <sstream>
#include "pch.h"
#include "Person.h"
bool isDigit(const std::string &str)
{
return str.find_first_not_of("0123456789") == std::string::npos;
}
void Person::addRecord()
{
std::string firstName;
std::string lastName;
std::string number;
std::string EGN;
Person newRecord;
const std::string filename = "Input.txt";
std::cout << "Enter information" << "\n";
std::cout << "Enter first name:" << "\n";
std::cin >> newRecord.firstName;
//newRecord->setFirstName(firstName);
std::cout << "Enter last name:" << "\n";
std::cin >> newRecord.lastName;
//newRecord->setLastName(lastName);
std::cout << "Enter phone number:" << "\n";
std::cin >> newRecord.number;
//newRecord->setNumber(number);
std::cout << "Enter EGN:" << "\n";
while (true) //check PIN validation
{
std::cin >> newRecord.EGN;
if (isDigit(EGN))
{
//newRecord->setEGN(EGN);
break;
}
else
{
std::cout << "Enter valid EGN and try again!" << "\n";
std::cin.clear();
}
}
// Open file to write
std::ofstream out_file(filename);
// Write data to file
out_file << newRecord;
// Close file
out_file.close();
// Clear the object to be reused
//newRecord.init();
// Open file to read
std::ifstream in_file(filename);
// Read file content
in_file >> newRecord;
}
You are rewriting the output file every time you call addRecord. Instead, you should append to the file, like this:
// Open file to write
std::ofstream out_file(filename, std::ofstream::app | std::ofstream::out);
Use file open mode: append
std::ofstream(filename, std::ofstream::app);

Am I building a correct way of organizing characters so I can count them?

The code is supposed to be able to count the characters in total then count each time they appear within a text file. I tried building a struct that makes an array which is an integer and char array at the same time so that I can have the counting in the same place as my array. But now I am stuck. I've looked online a lot but cannot find what I need to help me. Anyone got some advice? Also in the code if you see anything that should be changed I appreciate the tips! I am newer at c++ so go easy on me please.
Structs, multiple arrays, searching internet for answers
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
struct letters {
int count;
char letter;
};
constexpr int SIZE = 10000;
std::string fileName, word;
int count = 0, charCount = 0;
int Alphabet[26];
letters chars[];
void getFileName(std::string& fileName);
int countWords(int& count, std::string& fileName, std::string word);
int countChar(int& charCount, std::string& fileName, letters chars[]);
void sortChars(letters chars[SIZE], int SIZE);
int main()
{
getFileName(fileName);
countWords(count, fileName, word);
countChar(charCount, fileName, chars);
sortChars(chars, SIZE);
return 0;
}
void getFileName(std::string& fileName)
{
std::cout << "Please enter the name of the file followed by the type (ex: text.txt) : " << std::endl;
std::getline(std::cin, fileName);
}
int countWords(int& count, std::string& fileName, std::string word)
{
count = 0;
std::ifstream infile(fileName);
while (infile >> word) {
count++;
}
std::cout << count << std::endl;
return count;
}
int countChar(int& charCount, std::string& fileName, letters chars[])
{
std::ifstream infile(fileName);
while (infile >> chars->letter) {
count++;
}
std::cout << charCount;
return charCount;
}
void sortChars(letters chars[SIZE], int SIZE)
{
int i = 0;
std::ifstream infile(fileName);
while (infile >> chars[i].letter) {
for (int i = 0; i <= chars->count; i++) {
if (infile == chars[i].letter) {
chars[i].count++;
}
}
}
}
void printCount()
{
std::cout << count << std::endl;
std::cout << charCount << std::endl;
std::ifstream infile(fileName);
}
The struct should count the number of times 'A' or 'a', should be able to convert to one case, but I can do this after it counts one or the other. My tester file is in all lowercase so that would be a good place to start.
Even bigger hint, use a std::unordered_map to count the characters:
#include <cstdlib> // EXIT_FAILURE
#include <cctype> // std::isupper(), std::tolower()
#include <string> // std::string<>, std::getline()
#include <unordered_map> // std::unordered_map<>
#include <iostream> // std::ifstream
#include <fstream> // std::cout, std::cerr
int main()
{
std::string file_name;
if (!std::getline(std::cin, file_name)) {
std::cerr << "Input error. :(\n\n";
return EXIT_FAILURE;
}
std::ifstream is{ file_name };
if (!is.is_open()) {
std::cerr << "Couldn't open \"" << file_name << "\" for reading. :(\n\n";
return EXIT_FAILURE;
}
std::size_t num_words = 0;
std::unordered_map<char, std::size_t> char_counts;
for (std::string word; is >> word; ++num_words) {
for (auto ch : word) {
if (std::isupper(ch))
ch = std::tolower(ch);
++char_counts[ch];
}
}
for (auto const &count : char_counts)
std::cout << "'" << count.first << "': " << count.second << '\n';
std::cout << "Number of words: " << num_words << "\n\n";
} // when control reaches the end of main() without encountering a return-statement
// it has the same effect as return 0;
If you insist on splitting that few lines of code up into functions:
#include <cstdlib> // EXIT_FAILURE
#include <cctype> // std::isupper(), std::tolower()
#include <string> // std::string<>, std::getline()
#include <unordered_map> // std::unordered_map<>
#include <iostream> // std::ifstream
#include <fstream> // std::cout, std::cerr
std::string get_file_name()
{
std::cout << "Filename: ";
std::string file_name;
if (!std::getline(std::cin, file_name))
std::cerr << "Input error. :(\n\n";
return file_name;
}
std::ifstream open_file(std::string file_name)
{
std::ifstream file{ file_name };
if (!file.is_open())
std::cerr << "Couldn't open \"" << file_name << "\" for reading. :(\n\n";
return file;
}
std::size_t get_file_stats(std::istream &is, std::unordered_map<char, std::size_t> &char_counts)
{
std::size_t num_words = 0;
for (std::string word; is >> word; ++num_words) {
for (auto ch : word) {
if (std::isupper(ch))
ch = std::tolower(ch);
++char_counts[ch];
}
}
return num_words;
}
int main()
{
std::string file_name{ get_file_name() };
if (!file_name.length())
return EXIT_FAILURE;
std::ifstream is{ open_file(file_name) };
if (!is.is_open())
return EXIT_FAILURE;
std::unordered_map<char, std::size_t> counts;
std::cout << "Number of words: " << get_file_stats(is, counts) << "\n\n";
for (auto const &count : counts)
std::cout << "'" << count.first << "': " << count.second << '\n';
}

How to read data from a text file into a struct

I'm completely new to C++ and currently I'm trying to read very basic text file which look like this:
Dr John Doe
British
2
Soccer
Swimming
and my expected output should look like:
My information
Name: John Doe
Nationality: British
I have 2 hobbies:
1. Soccer
2. Swimming
My header file:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;
const int MAX = 80;
const int MAXNO = 5;
enum Title {Miss, Mrs, Mr, Dr, Unknown};
struct Date
{
int day;
int month;
int year;
};
struct MyInfo
{
char name [MAX];
char national [MAX];
int noOfHobbies;
char hobby [MAXNO][MAX];
};
void getMyInfo (fstream& , char[] , MyInfo&);
void displayMyInfo (MyInfo);
My functions:
#include "Lab_1.h"
void getMyInfo (fstream& afile,char fileName[], MyInfo& x) {
afile.open (fileName);
if (!afile)
{
cout << "Binary file " << fileName << " opened for creation failed" << endl;
exit (-1);
}
cout << "\n" << "Begin reading of " << fileName << endl;
string line;
while(getline(afile, line))
{
afile >> x.national;
afile >> x.noOfHobbies;*/
if (afile >> x.name >> x.national >> x.noOfHobbies) {
cout << "Name: " << x.name << ", "
<< "National: " << x.national << ", "
<< "noOfHobbies: " << x.noOfHobbies << ", "
<< endl;
}
}
}
void displayMyInfo (MyInfo x) {
}
My main function:
#include "Lab_1.h"
int main () {
fstream afile;
MyInfo x;
string fileName;
getMyInfo(afile,"textfile.txt",x);
//displayMyInfo(x);
afile.close ();
}
The above code output nothing because I just put everything I understand over the forum with similar question. Since I'm already stuck for 1 day even though I've already done a lot of research but most of them suggest to use vector which I'm not familiar with at this moment, so can someone give me a solution to this problem? Thank you very much for your help in advance.
Random act of madness kindness:
Live On Coliru
#include <fstream>
#include <set>
struct Person {
std::string name;
std::string nationality;
std::set<std::string> hobbies;
friend std::istream& operator>>(std::istream& is, Person& into) {
size_t n = 0;
if (getline(is, into.name) &&
getline(is, into.nationality) &&
is >> n && is.ignore(1024, '\n'))
{
while (n--) {
std::string hobby;
if (getline(is, hobby))
into.hobbies.insert(hobby);
else
is.setstate(std::ios::failbit);
}
}
return is;
}
};
#include <iostream>
int main() {
std::ifstream ifs("input.txt");
Person p;
if (ifs >> p) {
std::cout << "My information\n";
std::cout << p.name << "\n";
std::cout << p.nationality << "\n";
std::cout << "I have " << p.hobbies.size() << " hobbies:\n";
size_t counter = 0;
for(auto const& hobby : p.hobbies) {
std::cout << ++counter << ". " << hobby << "\n";
}
} else {
std::cerr << "Parse failure\n";
}
}

C++ Array structure

I have made a book storage program in c++. It is program which loops over 3 times so the user can input 3 books but now I want user to pick the amount of book user wants to enter and I have no clue how to do it. It would be helpful and here is my code
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct Book{
string name;
int release;
}Issue[3];
int main(){
//local variable
int i;
string release_dte;
//interface
cout << "Welcome to Book Storage CPP" << endl;
//for handler
for (i = 0; i < 3; i++){
cout << "Book: ";
getline(cin, Issue[i].name);
cout << "Release Date: ";
getline(cin, release_dte);
Issue[i].release = atoi(release_dte.c);
}
cout << "These are your books" << endl;
for ( i = 0; i < 3; i++){
cout << "Book: " << Issue[i].name << " Release Date: " << Issue[i].release << endl;
}
system("pause");
return 0;
}
The best way is to use std::vector. For example
#include <vector>
//...
struct Book{
string name;
int release;
};
int main()
{
size_t issue_number;
std::cout << "Enter number of books: ";
std::cin >> issue_number;
std::vector<Book> Issue( issue_number );
//...
Otherwise you should dynamically allocate the array yourself. For example
Book *Issue = new Book[issue_number];
and in the end of the program you need to release the allocated memory
delete []Issue;
Extending (and critiquing) Vlad's answer, you won't need the amount of the books beforehand if you utilize stream iterators. You can also overload the stream extractor for Book so that the extraction is correctly implemented by the iterators:
std::istream& operator>>(std::istream& is, Book & b)
{
if (!is.good())
return is;
std::string release_date;
if (std::getline(is >> std::ws, b.name) &&
std::getline(is >> std::ws, release_date))
{
b.release = std::stoi(release_date);
}
return is;
}
And later in main() you would still use std::vector<Book>, only using the iterator overload of the constructor to generate the objects:
int main()
{
std::vector<Book> Items(std::istream_iterator<Book>{std::cin},
std::istream_iterator<Book>{});
...
}
For printing you can overload the inserter which implements the logic for printing:
std::ostream& operator<<(std::ostream& os, const Book & b)
{
return os << "Book: " << b.name << '\n'
<< " Release Date: " << b.release;
}
And invoking this inserter using std::copy:
std::copy(Items.begin(), Items.end(),
std::ostream_iterator<Book>(std::cout << "These are your books: \n", "\n"));
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Book {
string name;
int release;
Book(string _name, int _release) {
name = _name;
release = _release;
}
};
int main() {
vector<Book> books;
string name;
int release;
while(cin >> name >> release) {
books.push_back(Book(name,release));
}
for(int i=0; i<(int)books.size(); ++i) {
cout << books[i].name << " - " << books[i].release << endl;
}
return 0;
}

text file contents to array

I have a text file-> info.txt which contains the follow Id,games,amount
info.txt
1,left4dead,50
2,warcraft3,60
I know how to extract the details using vectors with my codes shown below.
stock.h
#ifndef stock_stock_h
#define stock_stock_h
#include <iostream>
class stock {
public:
stock() {
columnOneText = " ";
columnTwoText = " ";
}
stock(std::string columnOneText,
std::string columnTwoText
);
std::string getColumnOne();
std::string getColumnTwo();
void setItemId(std::string columnOneText);
void setItemDescription(std::string columnTwoText);
private:
std::string columnOneText, columnTwoText;
};
#endif
main.cpp
#include "stock.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
stock::stock(string columnOneText,
string columnTwoText)
{
setItemId(columnOneText);
setItemDescription(columnTwoText);
};
string stock::getColumnOne() {
return columnOneText;
}
string stock::getColumnTwo() {
return columnTwoText;
}
void stock::setItemId(string columnOneText) {
this->columnOneText = columnOneText;
}
void stock::setItemDescription(std::string columnTwoText) {
this->columnTwoText = columnTwoText;
}
int main(){
vector<stock> itemDetails;
string line;
string columnOneText;
string columnTwoText;
ifstream readFile("info.txt");
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
//consturctor
stock splitedColumns(columnOneText,
columnTwoText
);
itemDetails.push_back(splitedColumns);
}
readFile.close();
cout << "this is column One in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnOne() << " " << endl;
}
cout << "this is column Two in text file" << endl;
for (int i =0; i<itemDetails.size(); i++) {
cout << itemDetails[i].getColumnTwo() << " " << endl;
}
}
what I don't really know is how to extract the details using arrays instead of using vectors.
I have tried this but it doesn't seem to work
string line;
string columnOneText;
string columnTwoText;
string columnOneTextArray[7];
while(getline(readFile,line)) {
stringstream iss(line);
getline(iss, columnOneText,',');
getline(iss, columnTwoText, ',');
for(int i=0; i<8; i++) {
columnOneTextArray[i] = columnOneText;
cout << columnOneTextArray[i];
}
}
You guys might ask why do I want to do it in arrays instead of using vector,
I just curious and exploring how it can be done using arrays.
You problem can be solved in a lot simpler manner by using struct definitions in addition to using vectors (your use of classes is a bit of overkill, IMHO):
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <sstream>
//this utilizes a more idiomatic naming convention as opposed to `columnX`
typedef struct Stock {
int id;
std::string games;
int amount;
} Stock;
//Syntactic sugar for easier output
std::ostream& operator << (std::ostream& in, const Stock& stock) {
in << stock.id << " " << stock.games << " " << stock.amount;
return in;
}
int main() {
std::string filename = "info.txt";
std::fstream ifile;
std::vector <Stock> inventory;
Stock stock_t;//a temporary Stock variable
std::string temp;
ifile.open(filename.c_str(), std::ios::in);
if (!ifile.is_open()) {
std::cerr << "There was a problem opening the input file: \"" << filename << "\"\n";
exit(1);
}
while (ifile >> temp) {
std::istringstream iss(temp);
int column = 0;
//break each constituent line by using the comment as a delimiter:
while(std::getline(iss, temp, ',')) {
if (column == 0) {
stock_t.id = std::atoi(temp.c_str());
}
else if (column == 1) {
stock_t.games = temp;
}
else if (column == 2) {
stock_t.amount = std::atoi(temp.c_str());
}
++column;
}
inventory.push_back(stock_t);
}
for (int i = 0; i < inventory.size(); ++i) {
std::cout << inventory[i] << "\n";
}
ifile.close();
return 0;
}
Which outputs:
1 left4dead 50
2 warcraft3 60