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.
Related
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;
}
}
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.
I'm using this code to output nodes of a huffman tree to a text file with a certain formatting. All the node outputs within the if block run as expected, but the first output in the else block is missing the '0' fill character after the "L:". It should output "L:076" but instead is outputting "L: 76". The cout looks correct but the text file isn't. All future loops through the else block output like they should, it's only the first loop that is missing the fill character. Here's a picture of my output
void preOrder(node* tree, std::ofstream& of) {
if (tree->label > 0) {
of << "I:" << tree->label << " ";
}
else {
std::cout.width(3);
std::cout << std::right;
std::cout.fill('0');
std::cout << int(tree->ch) << std::endl;
of << "L:";
of << of.fill('0');
of << std::right;
of << int(tree->ch);
of << " ";
return;
}
preOrder(tree->left, of);
preOrder(tree->right, of);
}
From cppreference.com:
The second form (2) sets fillch as the new fill character and returns the fill character used before the call.
"The second form" is the non-const version, that applies here. So my guess (I never used fill myself and I cannot compile your code as it is) would be that the call is correctly applied and then you put the old fill character (blank space presumably) to the stream, because you do:
of << of.fill('0');
Also, I noticed that you dont set the width of of.
Because you're hiding something naughty from us.
#include <iostream>
int main()
{
std::cout.width(3);
std::cout << std::right;
std::cout.fill('0');
std::cout << 3 << std::endl;
return 0;
}
Outputs 003 (live example).
Please provide an MCVE and I'll edit my answer to help you.
Let's say I have a program that does the follow:
for (i=1; i<10; i++)
{
computeB(i);
}
where the computeB just outputs a list of values
computeB(int i)
{
char[6] out_fname="output";
//lines that compute `var` using say, Monte Carlo
string fname = out_fname + (string)".values";
ofstream fout(fname.c_str());
PrintValue(fout,"Total Values", var);
}
From another file:
template <class T>
void PrintValue(ofstream & fout, string s, T v) {
fout << s;
for(int i=0; i<48-s.size(); i++) {
fout << '.';
}
fout << " " << v << endl;
}
Before implementing that loop, computeB just outputted one file of values. I now want it to create multiple values. So if it originally created a file called "output.values", how can I write a loop so that it creates "output1.values", "output2.values", ..., "output9.values"?
EDIT: I forgot to mention that the original code used the PrintValue function to output the values. I originally tried to save space and exclude this, but I just caused confusion
Disregarding all the syntax errors in your code ...
Use the input value i to compute the output file name.
Use the file name to construct an ofstream.
Use the ofstream to write var to.
Here's what the function will look like:
void combuteB(int i)
{
char filename[100];
sprintf(filename, "output%d.values", i);
ofstream fout(filename);
fout << "total values";
fout << " " << var << endl; // Not sure where you get
// var from. But then, your
// posted code is not
// exactly clean.
}
You can use std::to_string() to convert from an int to a string:
void computeB(int i)
{
if (std::ofstream fout("output" + std::to_string(i) + ".values"))
fout << "total values" << " " << var << '\n';
else
throw std::runtime_error("unable to create output file");
}
I'm working on a project that deals with creating two strings, a username and a password. The two elements make an object of an Account. In the main, there is an Array of Accounts that is initialized at 10.
I have a Save & Quit option, which saves the Username on one line and the Password on the next in the same file. A pair of lines signifies another account.
My question is, how do you properly save the data from the Array of Accounts, then load the data from the previous Array of Accounts?
I get a std::bad_alloc memory error every time I try the loadAccounts() function. I've several different methods, but to no avail.
So far I've come up with this for saving the array (works just as it should so far) :
void saveAccounts(Account accs [], int numIndexes)
{
std::ofstream savefile("savedata.sav", std::ofstream::binary); // By re-initializing the file, the old contents are overwritten.
for (int i = 0; i < numIndexes; i++)
{
savefile << accs[i].getUsername() << endl;
savefile << accs[i].getPassword() << endl;
}
savefile.close();
}
As for my loading function I have :
Account* loadAccounts() // Load the data from the file to later print to make sure it works correctly.
{
cout << "LOADING ACCOUNTS!" << endl;
std::ifstream loadfile("savedata.sav", std::ifstream::binary);
Account * acc_arr; // The "Array" to be returned.
Account tmp_arr [10]; // The array to help the returned "Array."
acc_arr = tmp_arr; // Allowing the "Array" to be used and returned because of the actual array.
if (loadfile.is_open())
{
int i = 0;
while (loadfile.good())
{
cout << "Loadfile is good and creating Account " << i+1 << "." << endl; // For my own benefit to make sure the data being read is good and actually entering the loop.
std::string user;
std::getline(loadfile, user);
std::string pass;
std::getline(loadfile, pass);
Account tmpAcc(user, pass);
tmp_arr[i] = tmpAcc;
++i;
}
Account endAcc = Account(); // The default constructor sets Username to "NULL."
tmp_arr[i] = endAcc;
}
loadfile.close();
cout << "ACCOUNTS LOADED SUCCESSFUL!" << endl;
return acc_arr;
}
I've gathered that I can return an array by using a pointer and an actual array to do that same, since an array can't actually be returned.
I try to use the returned array here, which I'm trying to "copy" over the loaded array to the Array that will actually be printed. Later, I'll print the array (acc_arr) to ensure that the loaded array was loaded successfully :
else if (selection == 'l' || selection == 'L')
{
Account * tmp_acc_arr = new Account [10];
tmp_acc_arr = loadAccounts();
_getch();
for (size_t i = 0; i < size_t(10); i++)
{
if (tmp_acc_arr[i].getUsername() == "NULL")
{
break;
}
acc_arr[i] = tmp_acc_arr[i];
cout << "Added Account " << i << " succesfully." << endl;
}
}
The error is caused by this last block of code. I've checked to make sure the data copied correctly by using
EDIT: Awkward... by using an if statement to make sure the data within the tmp_acc_arr actually has data stored once it was returned and initialized in the main.
tmp_arr ist local in loadAccounts and on the stack. It will be invalid once loadAccounts() returns. Your return value is an invalid stack-pointer.
You could hand your pointer tmp_acc_arr to the function as an argument and fill it with the values from your file.
You should also check for overflow or better use STL containers like std::vector.
edit
void loadAccounts(Account * acc_memory, std::allocator<Account> alloc, size_t acc_array_size) // Load the data from the file to later print to make sure it works correctly.
{
Account *end_of_construction = acc_memory;
try
{
cout << "LOADING ACCOUNTS!" << endl;
std::ifstream loadfile("savedata.sav", std::ifstream::binary);
if (loadfile.is_open() && loadfile.good())
{
size_t i = 0;
for (size_t i=0; i<acc_array_size; ++i)
{
if (loadfile.good())
{
cout << "Loadfile is good and creating Account " << i+1 << "." << endl; // For my own benefit to make sure the data being read is good and actually entering the loop.
std::string user, pass;
std::getline(loadfile, user);
if (loadfile.good())
{
std::getline(loadfile, pass);
alloc.construct(end_of_construction++, user, pass);
}
else alloc.construct(end_of_construction++);
}
else alloc.construct(end_of_construction++);
}
}
loadfile.close();
cout << "ACCOUNTS LOADED SUCCESSFUL!" << endl;
}
catch (...)
{
size_t num_constructed = end_of_construction-acc_memory;
for (size_t i=0; i<num_constructed; ++i) alloc.destroy(acc_memory + i);
throw;
}
}
Used like
size_t const num_elements = 10;
std::allocator<Account> acc_alloc;
Account * tmp_acc_arr = acc_alloc.allocate(num_elements);
loadAccounts(tmp_acc_arr, acc_alloc, num_elements);
// do stuff
for (size_t i=0; i<num_elements; ++i) acc_alloc.destroy(tmp_acc_arr + i);
acc_alloc.deallocate(tmp_acc_arr, num_elements);
You return a pointer that points to an array that is destroyed as soon as you exit the function. Using that pointer leads to undefined behavior, that is BAD.
As you observed, array is not a valid return type, so to return it actually you shall put it inside a struct, and return the struct.