Array of Strings to Output File - c++

I am writing a C++ code in which I have dynamically created an array of strings. I have written functions to output both the number of items in the string array as well as the array itself. The next thing I wanted to do is stored the elements of the array in a text file, but when I open the file I have written to, only the last element of the array shows up. Here is a sample of what I am doing:
int num_elem = ReadNumElem(); // my function that gets the number of elements in the array of strings
string *MyStringArray = ReadNames(num_elem); // my function that reads a file and outputs the necessary strings into the array
for(int i = 0; i < num_elem < ++i) {
ofstream ofs("C:\\Test\\MyStrings.txt")
ofs << MyStringArray[i] << endl; // I also tried replacing endl with a "\n"
}
I am new to C++, so I apologize if this is too simple, but I have been searching for some time now, and I can't seem to find a solution. The first two functions are not relevant, I only need to know how to output the data into a text file so that all the data shows up, not just the final element in the array. Thanks!

You are opening the file every time in the array and overwriting its contents.
Try:
ofstream ofs("C:\\Test\\MyStrings.txt");
for(int i = 0; i < num_elem ; ++i) {
ofs << MyStringArray[i] << endl; // I also tried replacing endl with a "\n"
}
ofs.close();

You need to declare the file outside of the loop
edit
Sorry I didn't mean to answer in one line but it has been done now anyway.

Related

Can't write string on file C++

I'm trying to emulate a shift register of 32 bits. But I can't even write, neither the input or output on the file. It simply runs the file and closes. There is nothing written in there. Tried some solutions here, but nothing worked so far. The input is a string of 32 bits like this
"00000000000000000000000000000011".
The output should look like this
"00000000000000000000000000001100".
Shifting two bits to the left. I haven't finished the shift yet, I'm trying to understand why it doesn't show anything.
The weird thing about this is, I've created 32 bits multiplexes the same way and it works fine.
void deslocador::shift(std::vector<std::string> entrada)
{
std::ofstream shifter("shift_left2.tv", std::ofstream::out);
std::vector<std::string> saida;
if(shifter.is_open())
{
for(unsigned int i = 0; i < 3; i++)
{
saida[i] = entrada[i];
saida[i].erase(saida[i].begin());
saida[i].erase(saida[i].begin());
saida[i] += "00";
shifter << entrada[i] << "_" << saida[i] << std::endl;
}
}else
{
std::cout << "Couldn't open file!";
}
shifter.close();
}
std::vector<std::string> saida;
This instantiates a new vector. Like all new vectors, it is completely empty, and contains no values.
for(unsigned int i = 0; i < 3; i++)
{
saida[i] = entrada[i];
This assigns four values to saida[0] through saida[3]. Unfortunately, as we've just discovered, the saida vector is completely empty and contains nothing. This attempts to assign new values to nonexistent values in the vector, so this is undefined behavior, and pretty much a guaranteed crash.
Additionally, no attempt is made to verify whether the entrada vector contains at least four values, this would be yet another reason for undefined behavior, and a crash.
It is unclear what the intent of the shown code is, so it's not possible to offer any suggestion of possible ways to fix it. The description of the code does not match its contents. It is unclear what relationship exists between "32 bits" and a vector of strings, that may or may not have four values in it.
The only thing that can be determined is that you get no output because your program crashes because of undefined behavior. Before you can assign a value to the ith element in the vector, the ith element must already exist. It doesn't, in the shown code. This results in undefined behavior and a crash.
There are various ways of placing new values in a vector. A vector can be resize()d, or new values can be push_back()ed into a vector. It is unclear what should be done in this case, so for additional information and examples, see your C++ book so you can learn more about how either approach (and other approaches) work, so you can decide how you want to do what you are trying to do.
Here is what I did to work!
void deslocador::shift(std::vector<std::string> entrada)
{
std::ofstream shifter("shift_left2.tv", std::ofstream::out);
std::vector<std::string> saida;
saida.resize(entrada.size());
if(shifter.is_open())
{
for(unsigned int i = 0; i < entrada.size(); i++)
{
saida[i] = entrada[i];
saida[i].erase(saida[i].begin());
saida[i].erase(saida[i].begin());
saida[i] += "00";
shifter << entrada[i] << "_" << saida[i] << std::endl;
}
}else
{
std::cout << "Couldn't open file!";
}
shifter.close();
}

Issue Read/Write array of structure in binary file in c++

I want to write my array structure in to a binary file.
My structure
typedef struct student{
char name[15];
vector<int> grade;
}arr_stu;
I can write and read back my data if I write and read in the same program; but if I create another program for read data only and put the binary file, it does not work because the vector grade is null.
size = 0;
unable to read from memory
Program to write array structure to file
int main()
{
arr_stu stu[100];
for (size_t i = 0; i < 100; i++)
{
strcpy(stu[i].name, randomName());
for (size_t j = 0; j < 10; j++)
{
stu[i].grade.push_back(randomGrade());
}
}
ofstream outbal("class", ios::out | ios::binary);
if (!outbal) {
cout << "Cannot open file.\n";
return 1;
}
outbal.write((char *)&stu, sizeof(stu));
outbal.close();
}
Program to read array structure to file
int main(){
feature_struc stu[100];
ifstream inbal("class", ios::in | ios::binary);
if (!inbal) {
cout << "Cannot open file.\n";
return 1;
}
inbal.read((char *)&stu, sizeof(stu));
for (size_t idx = 0; idx < 100; idx++)
{
cout << "Name : " << stu[idx].name << endl;
for (size_t index = 0; index < 10; index++)
{
cout << endl << "test: " << stu[idx].grade[index] << endl;
}
}
inbal.close();
return 0;
}
For me it seems like the use of vector pose the problem,
The reason that if we combine the two in one program it work well I think because vector is saved in the memory so it can still accessible.
Any suggestions?
You cannot serialize a vector like that. The write and read functions access the memory at the given address directly. Since vector is a complex class type only parts of its data content are stored sequentially at its base address. Other parts (heap allocated memory etc) are located elsewhere. The simplest solution would be to write the length of the vector to the file followed by each of the values. You have to loop over the vector elements to accomplish that.
outbal.write((char *)&stu, sizeof(stu));
The sizeof is a compile-time constant. In other words, it never changes. If the vector contained 1, 10, 1000, or 1,000,000 items, you're writing the same number of bytes to the file. So this way of writing to the file is totally wrong.
The struct that you're writing is non-POD due to the vector being a non-POD type. This means you can't just treat it as a set of bytes that you can copy from or to. If you want further proof, open the file you created in any editor. Can you see the data from the vector in that file? What you will see is more than likely, gibberish.
To write the data to the file, you have to properly serialize the data, meaning you have to write the data to a file, not the struct itself. You write the data in a way so that when you read the data back, you can recreate the struct. Ultimately, this means you have to
Write the name to the file, and possibly the number of bytes the name consists of.
Write the number of items in the vector
Write each vector item to the file.
If not this, then some way where you can distinctly figure out the name and the vector's data from the file so that your code to read the data parses the file correctly and recreates the struct.
What is the format of the binary file? Basically, you have to
define the format, and then convert each element to and from
that format. You can never just dump the bits of an internal
representation to disk and expect to be able to read it back.
(The fact that you need a reinterpret_cast to call
ostream::write on your object should tell you something.)

Accessing data inside an array via pointer error

I have 2 files in msg format. msg format is not important here.
car.msg
int speed;
int width;
cararr.msg
car mycar[];
I want to print all the information about all the cars that are present but I have no clue about the number of cars present(how big is the array) so I use the following technique to print the information.
so I do this:
cararr* ptr2car;
for(int i=0;mycar[i] != '\0'; i++){
cout << ptr2car->mycar[i].speed <<endl;
cout << ptr2car->mycar[i].width <<endl;
}
Despite this, I am receiving errors. I do not know what did I do wrong. I have no clue what approach should I use to get this output. please Help
Also why should I take a pointer to cararr, when I can just take an instance of cararr inst2car and do something like this:
cararr inst2car;
for(int i=0;mycar[i] != '\0'; i++){
cout << inst2car.mycar[i].speed <<endl;
cout << inst2car.mycar[i].width <<endl;
}
thanks
In general you need to know exactly what's at the end of the array. You need some sort of sentinel value to use as a delimiter to indicate the end of the array.
'\0' used in c strings is an example of such delimiter.
You need to ensure the last element in the array is such delimiter and check for it in the condition.
It's hard to give you more specific answer with such generic question.
For example, if you knew the last element will have speed -1, you can use that:
for(int i=0;mycar[i].speed != -1; i++) {

How to convert vector to string and convert back to vector

----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.

C++ Finding a line from a text file and updating/writing the line

I have a bank account file that the program should be able to read. This function works as of now with the use of ifstream. But I want the program to read the 6th line of the text file (which has the value 'balance') and then update it as needed (delete and replace with new value).
I used a for loop to find traverse through the lines. But how do I update it when needed? (Withdrawal and deposit of money updates the balance)
This is the code I have for now:
ifstream file;
string line;
file.open ("accounts.txt", ios::in);
for(int i = 0; i < 6; ++i) //6 being the 6th line
{
getline(file, line);
}
What comes next folks?
Thanks :)
If your file is very small like you've mentioned, you may bring it into an array of strings (one element per line of text). Then make changes to the array and re-write the whole array back to the file.
For example, you can read it into an arrya like this:
//assuming you've defined the array A
for(int i = 0; i < 6; i++) //NOTE: I've changed the loop counter i
{
getline(file, line);
A[i] = line;
cout << A[i] < "\n"; //This is the NEW LINE I wanted you to put
//If the ABOVE line gives nothing, you ought to check your TXT file.
}
//Change line 6
A[5] = "555.00";
//Now reopen the file to write
ofstream Account ("accounts.txt");
if (Account.is_open())
{
for(i=0;i<6;i++)
{//NOTE THAT I HAVE INCLUDED BRACES HERE in case you're missing something.
Account << A[i] << "\n"; //Loop through the array and write to file
}
Account.close();
}
I did not test this but I think it's ok.
More code: If you add the following bit of code at the end of your main code, you should see the contents from the array. And if this shows nothing that clearly means that your file is EMPTY.
for(int i = 0; i < 6; i++)
{
cout << A[i] < " This is a row with data\n";
}
Note: While I'd like to help you out on CLARIFYING issues on this forum, I think this question is going beyond the nature of this forum. Perhaps what you need is to spend some time learning the art of loops and other structures :)