C++ Writing to file or console by argument - c++

Ok, so I would like to do something I myself do find rather interseting .. I want an optional argument in my function and this argument would do two things;
1. Decide whether the text is being printed to the console or to a file
2. Print it to a file if that's the case, otherwise to console
I want it to be in the same function because I want very efficient code.
This is how I tried to solve it but obviously doesn't work
void Maze::Print_maze(std::string file = "no!ne") const{
if (file != "no!ne")
std::ofstream outfile(file);
for (int i = 0; i < Map.size(); i++)
{
for (int j = 0; j < Map[i].size(); j++)
{
if (file == "no!ne")
std::cout << Map[i][j];
else
outfile << Map[i][j];
}
if (file == "no!ne")
std::cout << std::endl;
else
outfile << std::endl;
}
}
For the curious ones ..
The code is from a maze project I'm working on, I'm generating a randomized maze, solving it and there's also the possibility of reading a maze from a file then solving it.
Now all that remains is to print it to a file. But as said, rather than making two functions, I'd like to merge my normal print to console with print to a file. I'm just wondering how .. Is it possible?
My "Map[][]" is a vector <vector<char> >

void Maze::Print_maze(std::ostream& s = std::cout)
Then just pass any stream you want to write to.

The best approach is to have an std::ostream* that points to an std::ofstream, if you want to write to a file, or std::cout if you want to write to the console.
std::ostream* outputTarget = &std::cout;
void output(const std::string& message)
{
*outputTarget << message;
}
void useFileOutput()
{
static std::ofstream outFile;
if (!outFile.is_open())
outFile.open("log.txt");
outputTarget = &outFile;
}
void useCout()
{
outputTarget = &std::cout;
}

In you situation I would make 3 function, two with the signatures you want to disambiguate and one that actually does the work. This way you get the unification of having one function do the work and the cleanliness of two functions:
public:
void Maze::Print_maze(std::ostream& OutputTarget){
for (int i = 0; i < Map.size(); i++)
{
for (int j = 0; j < Map[i].size(); j++)
{
OutputTarget << Map[i][j];
}
OutputTarget << std::endl;
}
}
void Maze::Print_maze() const{
Print_maze(std::cout);
}
void Maze::Print_maze(std::string file) const{
std::ofstream Output_file(file.c_str());
Print_Maze(Output_file);
Output_file.close();
}
Passing around references to the base types allows your maze output logic to ignore the actual output type and focus on rendering the maze.
This in some obtuse sense that is unlikely to matter would also be more performant because you would not need to make a series of string comparisons.
More importantly this version with the presentation and business(maze rendering is now a business) logic separate is simpler, therefor easier to read and less bug prone.

Thanks guys, I read your replies, I'm thankful for all the good comments and efforts you put to help me. I came to a solution and I believe this is the best solution to my problem that I can come up with.
I also added a bit of error-management
void Maze::Print_maze(std::string file) const{
std::ofstream outfile(file);
// if file is open, write to file otherwise write to console
std::ostream &out= (!outfile.is_open()? std::cout : outfile);
// Check if file failed to open
if(file != "" && (!outfile.is_open()))
std::cerr << "File failed to open." << std::endl;
for (int i = 0; i < Map.size(); i++)
{
for (int j = 0; j < Map[i].size(); j++)
{
out << Map[i][j];
}
out << std::endl;
}
if(outfile.is_open())
outfile.close();
}
Edit:
Forgot to mention this ..
My Maze.h file with my class consists of this function declaration:
void Print_maze(std::string file = "") const;

Related

Can't read char array

The basic problem is that we (in pairs) have been tasked with creating a program to - amongst other things - read in a txt file and display it as a sudoku board as part of our introduction to coding at Uni.
We have completed most of the code and have got it working sufficiently well. However, we are struggling with what I would consider to be a basic aspect of this. The code reads in the file and saves it to the classes private char 9*9 matrix. We have run a debugging print-out to check that the values are being saved to the matrix and this is indeed the case. The issue is with the getMatrixVal(int x, int y) function which we think is returning a pointer rather than the character. We have tried returning a pointer from the function and have tried saving to a pointer and then to a char variable. Unfortunately, we am not excellent on pointer's.
With the recent suspensions to University timetables, we are temporarily unable to get the advice and support we require and, hence, we are applying here for advice.
Also, we are using the qt programming software on a raspberry pi - could this have anything to do with our problems?
#include "grid.h"
#include <QDebug>
#include <QChar>
#include <QFile>
grid::grid(char matrix_value, const int x, const int y) {
matrix[x][y] = matrix_value;
//char c = matrix[x][y];
//qDebug() << QChar(c);
}
void grid::load_file() {
QFile file("/home/pi/Documents/ELEC1204/P6/SUDOKU.txt");
char character, c;
int i, j;
if(!file.open(QFile::ReadOnly)) {
qDebug() << "Error in opening file";
return;
} //Print error if message if unable to open file
for(i = 0; i < 9; i++) {
for(j = 0; j < 9; j++) {
SKIP: //Related to 'goto'
file.read(&character, sizeof(char)); //Read ini individual characters
if(character == '\xd' || character == '\xa')
goto SKIP;
//Skip character related to new lines
//Goes to 'SKIP' point in program
else if(character == 'X')
grid('_', i, j);
//Save 'X's as '_'
else
grid(character, i, j);
//Save numbers as they are
c = getMatrixVal(i, j);
qDebug() << "i = " << i << "| j = " << j << "| Character is: " << QChar(character) << "| Matrix character is: " << QChar(c);
//Print-out for debugging
}
}
file.close();
//Close file
}
// Possibly useful source:
// https://doc.qt.io/qt-5/qfile.html
// https://forum.qt.io/topic/60240/reading-file-byte-by-byte/5
char grid::getMatrixVal(const int x, const int y) {
char c = matrix[x][y];
//qDebug() << "Matrix[" << x << "][" << y << "] is: " << QChar(c);
return c;
}
void grid::printMatrix() {
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
qDebug() << matrix[i][j];
}
}
}
//Prints out matrix
//Debugging function
There is nothing wrong with getMatrixVal: it returns a character from the right place in matrix.
Your call grid(character, i, j) constructs a new grid instance that is unrelated to the current one.
Instead, just assign directly to matrix: (or use a setter function)
matrix[i][j] = character;

C++ File Output for object arrays

Does anyone know how to fout an array like the below to a .dat file?
Let me know if this is not enough information.
My console output shows 4 rows of integers with 6 columns and I want to print that to my file. I can print everything else, but can not figure this one out..
for(i=0; i < 4; i++)
{
cout << " " << i+1;
P[i].TeamOutput();
}
void TeamOutput()
{
cout << teamwork << speed << power << defence << injury << endl;
}
You almost had it. You need a specific type of ostream to output. cout is an ostream, but a special one that outputs to the system's console. You need an ostream that outputs to a file. This kind of ostream is called an ofstream and is in the header file <fstream>. Here's how you can use it with an array.
#include <iostream>
#include <fstream>
using namespace std; // It's generally bad to do this
int main()
{
// Size of array
const int SIZE = 10;
// Make the array
int some_array[10];
// Fill the array with values
for (int i = 0; i < SIZE; i++)
{
some_array[i] = i + 1;
}
// THIS is where the magic happens; make the file stream to output to
ofstream file("file.dat"); // "file.dat" can be replaced by whatever filename
// Make sure the file opened okay. Otherwise, there's an error
if (file.is_open())
{ // The file opened just file, so do whatever you need to
// Save all the info from the array to "file.dat"
for (int i = 0; i < SIZE; i++)
{
file << some_array[i] << endl;
}
// Make sure to close the 'ofstream' when you're done
file.close();
}
else
{ // The file did NOT open okay; there's an error
cout << "Error opening file.dat!" << endl;
}
}

Iteratively accessing and writing to multiple files using ofstream

I have a pair of header files. Within IsingModel.h, publically I declare:
ofstream logfile1;
ofstream logfile2;
Then to open the relevant files (logfile1 and logfile 2 have different names) I use:
do {
name2.str(""); //reset name stringstream
n++; //increase n value
name2 << "output_" << gridSize << "_" << seed << "_" << n << "_eqmCalc.txt"; //stream created
} while (if_exist(name2.str())); //test if file already exists
logfile2.open(name2.str());
Which works in creating the file. Then, throughout the code I use the ofstreams to act on the files, for example:
logfile1 << counter << " " << calcM() << " " << calcE() << endl;
This is fine for actions that are independent for each file, however when I call the destructor I want to write the same standard information to each file. To that end, I am experimenting with iteratively writing to the files and it does not seem to work:
void IsingSystem::test() {
for (int i = 1; i = 2; i++) {
if (ofstream("logfile" + to_string(i)).is_open); {
ofstream("logfile" + to_string(i)) << "success" << endl;
}
}
}
This instead creates files called logfile1 and logfile2. As an alternative, I tried to create an array of ofstreams:
void createFileHandles() {
const int count = 2;
std::ofstream logfile[count];
}
But, I could not work out how to pass this between functions properly.
What is the proper way of handling ofstreams so that I can have multiple files open, writing different instructions to them simultaneously but also have some actions that happen to both?
You can have a vector of ofstream
vector<ofstream> ofstreams(2);
//fill vec
for (int i = 0; i < 2; i++)
{
if (ofstreams[i].is_open);
{
ofstreams[i]<< "success" << endl;
}
}
You can then pass ofstreams to functions.

C++ How to create a function writing data in file for multiple use with different names

I have some data in an array which is manipulated in about five or six steps. After each step I want the program to write a file with the manipulated data. This is the working code for that:
ofstream mirroreddata("mirroreddata.dat", ios::out);
for (int i = 0; i < n_values; i++)
{
mirroreddata << datavector[i] << "\n";
}
mirroreddata << endl;
mirroreddata.close();
The problem is, that I don't want to write this thing multiple times. I want to create a function I just have to call with the name of the file (here: mirroreddata) and n_values and the datavector. Giving the function the datavector and n_values is no problem, but how to tell her writing the data in a new file? This is the code fragment for this but it is not right:
void CreateDataOutputFile(int n_values, double* datavector)
{
ofstream mirroreddata("mirroreddata.dat", ios::out);
for (int i = 0; i < n_values; i++)
{
mirroreddata << datavector[i] << "\n";
}
mirroreddata << endl;
}
So how to call this but writing data in a new file (for example the smoothed data in file "smoothed")?
Thanks for your answers
Easy: add another parameter for the filename:
#include <string>
void CreateDataOutputFile(int n_values, double* datavector, const std::string& fname)
{
ofstream mirroreddata(fname, ios::out);
for (int i = 0; i < n_values; i++)
{
mirroreddata << datavector[i] << "\n";
}
mirroreddata << endl;
}

Printing a NumericUpDown value out of a ofstream

This should be a simple task, but I am recieving a file containing the number "1" instead of the contents of the numericUpDown control. Using breakpoints I can see the value from
ta[i]->Value is the value I would expect it to be, but then after the conversion I get a 1 in the file instead of the value.
private: void storePreviousSettings()
{
ofstream settings("prev_settings.txt");
if(settings.is_open())
{
settings << "#ta" << endl;
for(int i = 0; i < 16; i++)
{
settings << ta[i]->Value.ToString() << endl;
}
settings << "End" << endl;
settings.close();
}
}
Note: ta is defined like so:
private: NumericUpDown * ta[];
Why am I printing a "1" to the file with the ofstream instead of the value in the numericUpDown component? How can I fix this? Is there an alternative method for writing to a file can I perform?
Update/Current Failed Attempts
If I add this line:
System::String * temp = ta[i]->Value.ToString();
Before the "settings << ta[i]->Value ..." line, using break points I can see that "temp" holds the expected value, and ta[i]->Value.ToString() is working. So when ta[i]->Value.ToString() is used with the << operator something must be changing in order for me to recieve a "1" in the file instead of the value I am seeing at my break points before it is wrote to the file.
Any help or direction is appreciated. Thanks.
The problem has been solved using the following conversion on the Decimal to make it a double.
private: void storePreviousSettings()
{
ofstream settings("prev_settings.txt");
if(settings.is_open())
{
settings << "#ta" << endl;
for(int i = 0; i < 16; i++)
{
settings << System::Decimal::ToDouble(ta[i]->Value) << endl;
}
settings << "End" << endl;
settings.close();
}
}
If anyone knows the reason why using .ToString() did not work originally, please post. I am answering this in hopes that it might aid someone else in the same situation.