Call by reference and ostream and string manipulation recursive - c++

all!
I am trying to get my program to work correctly, and I do not think it is supposed to be recursive The program is supposed to print certain strings in a text file and put them in a text-made box.
However, I modified it incorrectly and made an infinite loop (it actually is a stack overflow, ha ha, how funny...). Any help would be much appreciated.
here is the code for the prototype (and yes #include is used):
void textBox(ostream & out, string text);
and the part in the main function and subprogram:
cout << "Part c: textBox(text)" << endl ;
cout << "---------------------" << endl ;
ofstream fout("myFile.txt");
string box = "Text in a Box!";
textBox(fout, box);
fout << endl;
string size = "You can put any text in any size box you want!!";
textBox(fout,size);
fout << endl;
string courage = "What makes the muskrat guard his musk? Courage!";
textBox(fout,courage);
void textBox(ostream & out, string text)
{
// ---------------------------------------------------------------------
// This routine outputs text surrounded by a box.
// ---------------------------------------------------------------------
ofstream myFile("myFile.txt");
textBox(cout, "Message to screen");
textBox(myFile, "Message to file");
int textSize = text.size();
out << '+' << setfill('-') << setw(textSize+1) << right << '+' << endl;
out << '|' << text << '|' << endl;
out << '+' << setfill('-') << setw(textSize+1) << right << '+' << endl;
out << setfill(' ') ;
}

It's recursive because textBox calls itself. Your program will run if you:
A) Remove both calls to textBox within textBox
or B) make textBox like this:
void textBox(ostream & out, string text)
{
int const textSize = text.size() + 1;
out << '+' << setfill('-') << setw(textSize) << right << '+' << endl;
out << '|' << text << '|' << endl;
out << '+' << setfill('-') << setw(textSize) << right << '+' << endl;
out << setfill(' ') ;
}
And create another function:
void textBoxWithInfo(ostream & out, string text)
{
textBox(cout, "Message to screen");
{ // Braces to deallocate + close myFile faster
ofstream myFile("myFile.txt");
textBox(myFile, "Message to file");
}
textBox(out, text);
}
And call the above function in main.

Related

Using C++ stream for cout or text file

I have a very simple program where I ask the user if they want to print to screen or a file. Rather than create two sets of output sections, I thought I could switch a stream to either cout or an ofstream and then output to that stream. However, I'm getting screen output no matter what.
ostream &out = cout;
do
{
cout << "Write to file (f) or screen (s)?";
cin >> yes_or_no;
} while (yes_or_no != 'f' && yes_or_no !='s');
if (yes_or_no=='f')
{
ofstream out;
out.open("Report.txt");
cout << "Writing report to Report.txt" << endl;
system("pause");
}
out << "Day: Current Value ROI" << endl;
out << "------------------------------------------" << endl;
out << setw(5) << 0;
out << "$" << setw(20) << setprecision (2) << fixed << initial_value;
out << setw(12) << "1.00" << endl;
for (int day = 1 ; day < number_of_days ; day++)
{
current_value = generateNextStockValue(current_value, volatility, trend);
out << setw(5) << day;
out << setw(20) << setprecision (2) << fixed << current_value;
out << setw(12) << setprecision (2) << fixed << current_value / initial_value;
out << endl;
}
You could put all the writing logic inside a function, and let the caller decide which output stream to write to:
void do_the_stuff(std::ostream& os)
{
// write to os
os << "blah blah" ....
}
then
if (yes_or_no=='f')
{
ofstream out("Report.txt");
do_the_stuff(out);
} else {
do_the_stuff(std::cout);
}

Print function to an output file

I am about to be finished with a program I am writing and have reached a roadblock.
I am trying to print the contents of a function called print which is called by a pointer.
My problem is I need to print the contents of the function to an output file and am not sure how.
This is my print function:
void English::Print(){
int formatlength = 38 - (static_cast<int>(firstName.size() + lastName.size()));
cout << firstName << " " << lastName;
cout << setw(formatlength) << finalExam;
cout << setprecision(2) << fixed << setw(11) << FinalGrade();
cout << setw(4) << Lettergrade() << endl;
}
This is the implementation of the print function:
for (int i = 0; i <= numStudents - 1; i++) {
if (list[i]->GetSubject() == "English") {
list[i]->Print();
}
}
Where the for loop is cycling through my list of Students.
My goal is that the list[i]->Print() will print to my output file.
Simply replace cout with an ostream object, something like :
void English::Print(ostream& fout){
//ofstream of("myfile.txt", std::ios_base::app);
int formatlength = 38 - (static_cast<int>(firstName.size() + lastName.size()));
fout << firstName << " " << lastName;
fout << setw(formatlength) << finalExam;
fout << setprecision(2) << fixed << setw(11) << FinalGrade();
fout << setw(4) << Lettergrade() << endl;
}
Also, you can overload << operator too in your class English
friend ostream& operator <<( ostream& os, const English& E )
{
//
return os;
}
And then can simply use:
fout << list[i] ;
Besides the answers above, I think you should try this way, using the C's original file redirection function:
Put this instruction in the first line of your main function:
int main(){
freopen("out.txt", "w", stdout);
//your codes
The "out.txt" is the file you wanna to put the data in, "w" means you want to write in the file, and stdout is the standard output stream that has been redirected.

String formatting (c++)

I tried to format output strings in my console application (like a table)
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|";
cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout << "\n-----------------\n\n";
But as result my output looks like this
What's wrong with my upper string formatting?
I used the same code as you did and got the same output until I removed the \t at the end of the line. See the new code:
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t|";
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "|";
cout.width(8);
cout.setf(ios::left);
cout << x << "|";
cout << "\n-----------------\n\n";
As already noted, it's the tabs that are causing the problem.
I would not stop at just removing the tabs though. As it stands right now, your code is highly repetitive and next to impossible to maintain. I'd do a (nearly) complete rewrite, with a couple of functions to cut down on the repetition. My first cut would probably look something like this:
// format a value in a field of specified width, followed by a separator
template <class T>
string field(T val, int w, char sep = '|') {
stringstream b;
b << setw(w) << left << fixed << setprecision(3) << val << sep;
return b.str();
}
// generate a separator for a specified number of fields,
// each of a specified width
string sep(int c, int w, char val = '-') {
string s(c * (w + 1), val);
return string("\n") + s + "\n";
}
int main() {
static const int w = 8;
double F = 1.234, x = 3.45;
string s = sep(2, w);
cout << "\n" << s;
cout << field("F", w) << field("x", w) << s;
cout << field(F, w) << field(x, w) << s;
}
Seems to me that this makes the code rather more readable and quite a bit more maintainable. For example, if we decided to display an a and b on the next line, it would seem fairly obvious to add something like:
cout << field(a, w) << field(b, w) << s;
...and we wouldn't have to look very hard to be pretty sure it was going to match up with the previous line. Likewise, if we wanted to change a column width, etc.
You may try:
cout << "\n\n-----------------\n";
cout << setw(8) << left << "F\t\t|"; // insert more tab here
cout << setw(8) << left << "x\t|";
cout << "\n-----------------\n";
//...
cout.width(8);
cout.setf(ios::left);
cout << fixed << setprecision(3) << F << "\t|";
cout.width(8);
cout.setf(ios::left);
cout << x << "\t|";
cout << "\n-----------------\n\n";
The console screen looks suspiciously Windows like.
If you are using Windows, you can use the Win32 API to format output more precisely.
In particular, you can use SetConsoleCursorPosition.
COORD position = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, position);
std::cout<<"This will be printed starting at position x, y"<<std::endl;
Try this:
#include <iostream>
#include <iomanip>
#include <map>
#include <string>
using namespace std;
int main()
{
map< float, float > table =
{
{ 8232.0f, 89.0f },
{ 8232.1f, 89.0f },
{ 8232.2f, 89.0f },
{ 8232.3f, 89.0f },
{ 8232.4f, 89.0f },
{ 8232.5f, 89.0f },
{ 8232.6f, 89.0f },
{ 8232.7f, 89.0f },
{ 8232.8f, 89.0f },
};
const size_t CELL_WIDTH = 25;
const string CELL_LINE( CELL_WIDTH, '=' );
// print the header of table
cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl
<< '|'
<< left << setw( CELL_WIDTH ) << "F" << '|'
<< setw( CELL_WIDTH ) << "R" << "|\n|"
<< CELL_LINE << '|' << CELL_LINE << '|' << endl;
// print the body
// change cout precision
cout << fixed << setprecision( 3 );
for ( auto it : table )
cout << "| " << setw( CELL_WIDTH - 1 ) << it.first
<< "| " << setw( CELL_WIDTH - 1 ) << it.second
<< "|\n";
// print the footer
cout << '|' << CELL_LINE << '|' << CELL_LINE << '|' << endl;
return 0;
}
this is the result:

getline not working as expected

I'm trying to display a text file data into columns using a class structure and getline() function to read through the textfile and the dump the data into a vector class. But it seems that the program didn't even run to my 'while' loop then quitting the program. The textfile is not empty.
Below is my code:
void ScrambleWordGame::displayScoreChart() {
//open file
fstream readScoreChart("ScoreChart.txt");
string line = "";
//vector to store data in
vector<personResult> perResult;
personResult person;
//while file is open, do stuff
if(readScoreChart.is_open())
{
//check through the file
readScoreChart.seekp(0,ios::end);
//get the size of the file's data
size_t size = readScoreChart.tellg();
if(size == 0)
cout << "No results yet. Please TRY to win a game. AT LEAST~" << endl;
else
{
//create the 1st row with 4 column names
cout << left
<< setw(20) << "Player Name "
<< setw(20) << "Winning Time "
<< setw(20) << "No. Of Attempts "
<< setw(20) << "Game Level " << endl;
//fill the second line with dashes(create underline)
cout << setw(70) << setfill('-') << "-" << endl;
//read the file line by line
//push the 1st line data into 'line'
cout << getline(readScoreChart,line);
while(getline(readScoreChart,line))
{
//create stringstream n push in the entire line in
stringstream lineStream(line);
//reads the stringstream and dump the data seperated by delimiter
getline(lineStream,person.playerName,':');
getline(lineStream,person.winningTime,':');
getline(lineStream,person.noOfAttempts,':');
getline(lineStream,person.gameLvl);
//sort the results based on their timing
//sort(perResult.begin(),perResult.end(),pRes);
//display the results
cout << left
<< setfill(' ')
<< setw(25) << person.playerName
<< setw(22) << person.winningTime
<< setw(17) << person.noOfAttempts
<< setw(16) << person.gameLvl
<< endl;
}
}
}
readScoreChart.close();
}
Edit: Example of the TextFile
Joel:3:1:1
Mary:5:2:2
John:25:3:1
Your file pointer is at the end of the file after your first seek. You need to reposition it to the beginning of the file.
if(size == 0)
{
cout << "No results yet. Please TRY to win a game. AT LEAST~" << endl;
}
else
{
readScoreChart.seekp(0,ios::begin);
// all you other stuff
}
You need to seek back to the beginning of the file to be able to read. Better still, just don't seek to the end in the first place.
I'd re-structure the code a bit -- write an operator>> to read a record from a file, and an operator<< to write a record to a file.
class person {
std::string name;
std::string winning_time;
std::string num_attempts;
std::string level;
public:
bool operator<(person const &other) const {
return std::stoi(winning_time) < std::stoi(other.winning_time);
}
friend std::istream &operator>>(std::istream &in, person &p) {
std::string buffer;
std::getline(in, buffer);
std::istringstream is(buffer);
std::getline(is,p.name,':');
std::getline(is,p.winning_time,':');
std::getline(is,p.num_attempts,':');
std::getline(is,p.level);
return in;
}
friend std::ostream &operator<<(std::ostream &os, person const &p) {
return os << std::setw(25) << p.name
<< std::setw(22) << p.winning_time
<< std::setw(17) << p.num_attempts
<< std::setw(16) << p.level;
}
};
With those in place, the rest gets quite a bit simpler:
void show_header(std::ostream &os) {
cout << left
<< setw(20) << "Player Name "
<< setw(20) << "Winning Time "
<< setw(20) << "No. Of Attempts "
<< setw(20) << "Game Level " << "\n";
std::cout << std::string(70, '-');
}
void game::displayScoreChart(){
std::ifstream in("ScoreChart.txt");
// read the data:
std::vector<person> people{std::istream_iterator<person>(in),
std::istream_iterator<person>()};
if (people.empty()) {
std::cout << "No scores yet."
return;
}
// sort it by winning time:
std::sort(people.begin(), people.end());
show_header(std::cout);
// display it:
for (auto const &p : people)
std::cout << p << "\n";
return 0;
}
As a simple replacement if you don't have a C++11 compiler, an stoi can be written something like this:
int stoi(std::string in) {
return strtol(in.c_str(), NULL, 10);
}

C++ - How to reset the output stream manipulator flags [duplicate]

This question already has answers here:
Restore the state of std::cout after manipulating it
(9 answers)
Closed 4 years ago.
I've got a line of code that sets the fill value to a '-' character in my output, but need to reset the setfill flag to its default whitespace character. How do I do that?
cout << setw(14) << " CHARGE/ROOM" << endl;
cout << setfill('-') << setw(11) << '-' << " " << setw(15) << '-' << " " << setw(11) << '-' << endl;
I thought this might work:
cout.unsetf(ios::manipulatorname) // Howerver I dont see a manipulator called setfill
Am I on the wrong track?
Have a look at the Boost.IO_State_Savers, providing RAII-style scope guards for the flags of an iostream.
Example:
#include <boost/io/ios_state.hpp>
{
boost::io::ios_all_saver guard(cout); // Saves current flags and format
cout << setw(14) << " CHARGE/ROOM" << endl;
cout << setfill('-') << setw(11) << '-' << " " << setw(15) << '-' << " " << setw(11) << '-' << endl;
// dtor of guard here restores flags and formats
}
More specialized guards (for only fill, or width, or precision, etc... are also in the library. See the docs for details.
You can use copyfmt to save cout's initial formatting. Once finished with formatted output you can use it again to restore the default settings (including fill character).
{
// save default formatting
ios init(NULL);
init.copyfmt(cout);
// change formatting...
cout << setfill('-') << setw(11) << '-' << " ";
cout << setw(15) << '-' << " ";
cout << setw(11) << '-' << endl;
// restore default formatting
cout.copyfmt(init);
}
You can use the ios::fill() function to set and restore the fill character instead.
http://www.cplusplus.com/reference/iostream/ios/fill/
#include <iostream>
using namespace std;
int main () {
char prev;
cout.width (10);
cout << 40 << endl;
prev = cout.fill ('x');
cout.width (10);
cout << 40 << endl;
cout.fill(prev);
return 0;
}
You can manually change the setfill flag to whatever you need it to be:
float number = 4.5;
cout << setfill('-');
cout << setw(11) << number << endl; // --------4.5
cout << setfill(' ');
cout << setw(11) << number << endl; // 4.5
The null character will reset it back to the original state:
setfill('\0')