I'm using a stringstream to generate "dynamically", the name of the files I need to open and this is my code:
for (int img=0; img<5; img++)
{
stringstream stream;
string *s=new string("myfile");
stream << img << ".png"
s->append(stream.str());
.. other code
the problem is than the first time the program flows into the loop it works fine, the second time stream does not has the value "1.png", but has value null... so when I try to open the file I get a null pointer.
ho do I fix this?
A simpler solution:
for (int img = 0; img < 5; ++img)
{
std::string s = "myfile" + ('0' + img) + ".png";
// do something useful with s
}
If numbers are bigger than 9, you can use std::to_string(img) instead.
Try allocating your string before your loop.
string *s = new string("myfile");
for(;;;){} //forloop
// use s here.
delete s; // always delete dynamically allocated memory.
Related
I'm attempting to create a vector called mems which is declared using the returned vector from my myMembers() function. For some reason when I use the line:
vector<string> mems = myMembers(); It returns an error:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
This error doesn't appear at compilation, but instead it appears once the program reaches this line of code. I've been researching for a few hours on what to do to fix it, but I'm really not sure.
The code that I've written so far is as follows:
vector<string> Person::myMembers(){
fstream file;
file.open("myFile.txt");
string myLine;
vector<string> mems;
while(getline(myFile, myLine)){
vector<string> myLine = split(myLine, ',');
mems.push_back(myLine.at(0));
for (int i = 5; i < myLine.size(); i++){
mems.push_back(myLine.at(i));
}
}
return mems;
}
The above function will get the name at index 0, and the list of names from index 5 to n. It will then place these names into a vector called mems, and return it.
(I should make you aware that split is a function I've written which will simply split a line by a specified delimiter, and then put it into a vector).
Then, later in my code, I create a new vector, called mems, and set it equal to the output of myMembers()
vector<string> mems = myMembers()
I know that it's the above line of code that's causing the error, but I don't know why, or how to fix it.
Any help would be greatly appreciated.
Thanks for your time :)
Edit
Upon mention that the error might be a part of the splitString, please find the code for my SplitString function below:
vector<string> split(string myString, char delimiter){
string temp = 0;
vector<string> splitString;
for (int i = 0; i < myString.size(); i++){
if (myString[i] != delimiter){
temp += myString[i];
} else {
splitString.push_back(temp);
}
}
return splitString;
}
I've discovered the issue for the program. The split() function was causing the error, because temp was initialised as string temp = 0; which meant it was trying to initialise a string with an integer value.
The correct code for the split() function is as follows:
ector<string> split(string myString, char delimiter){
string temp = "";
vector<string> splitString;
for (int i = 0; i < myString.size(); i++){
string temp = "";
if (myString[i] != delimiter){
temp += myString[i];
} else {
splitString.push_back(temp);
}
}
return splitString;
}
This then lets the split() function return a non-null string, and allows the program to run as it should.
I got an issue with sprintf buffer.
As you can see in the code down below I'm saving with sprintf a char array to the buffer, so pFile can check if there's a file named like that in the folder. If it's found, the buffer value will be assigned to timecycles[numCycles], and numCycles will be increased. Example: timecycles[0] = "timecyc1.dat". It works well, and as you can see in the console output it recognizes that there are only timecyc1.dat and timecyc5.dat in the folder. But as long as I want to read timecycles with a for loop, both indexes have the value "timecyc9.dat", eventhough it should be "timecyc1.dat" for timecycles[0] and "timecyc5.dat" for timecycles1. Second thing is, how can I write the code so readTimecycles() returns char* timecycles, and I could just initialize it in the main function with char* timecycles[9] = readTimecycles() or anything like that?
Console output
#include <iostream>
#include <cstdio>
char* timecycles[9];
void readTimecycles()
{
char buffer[256];
int numCycles = 0;
FILE* pFile = NULL;
for (int i = 1; i < 10; i++)
{
sprintf(buffer, "timecyc%d.dat", i);
pFile = fopen(buffer, "r");
if (pFile != NULL)
{
timecycles[numCycles] = buffer;
numCycles++;
std::cout << buffer << std::endl; //to see if the buffer is correct
}
}
for (int i = 0; i < numCycles; i++)
{
std::cout << timecycles[i] << std::endl; //here's the issue with timecyc9.dat
}
}
int main()
{
readTimecycles();
return 0;
}
With the assignment
timecycles[numCycles] = buffer;
you make all pointers point to the same buffer, since you only have a single buffer.
Since you're programming in C++ you could easily solve your problem by using std::string instead.
If I would remake your code into something a little-more C++-ish and less C-ish, it could look something like
std::array<std::string, 9> readTimeCycles()
{
std::array<std::string, 9> timecycles;
for (size_t i = 0; i < timecycles.size(); ++i)
{
// Format the file-name
std::string filename = "timecyc" + std::to_string(i + 1) + ".dat";
std::ifstream file(filename);
if (file)
{
// File was opened okay
timecycles[i] = filename;
}
}
return timecycles;
}
References:
std::array
std::string
std::to_string
std::ifstream
The fundamental problem is that your notion of a string doesn't match what a 'char array' is in C++. In particular you think that because you assign timecycles[numCycles] = buffer; somehow the chars of the char array are copied. But in C++ all that is being copied is a pointer, so timecycles ends up with multiple pointers to the same buffer. And that's not to mention the problem you will have that when you exit the readTimecycles function. At that point you will have multiple pointers to a buffer which no longer exists as it gets destroyed when you exit the readTimecycles function.
The way to fix this is to use C++ code that does match your expectations. In particular a std::string will copy in the way you expect it to. Here's how you can change your code to use std::string
#include <string>
std::string timecycles[9];
timecycles[numCycles] = buffer; // now this really does copy a string
I'm trying to assign some characters from a string to another string as follows:
string s2;
int ind = -1;
for(int i = 0; i < ch; i++)
{
s2[++ind] = s[i];
}
s2[++ind] = '\0';
Now when I try to print s2 using
cout << s2 << endl;
It prints nothing on the black screen. But when I use char array in place of string declaration for s2, then s2 gets printed successfully. I think both a string and char array's characters can be accessed in the same way. Cannot understand why this happened. Some info about this?
You cannot access the ++indd element of an empty string. Use string's operator += to append a char to the string.
Your code contains Undefined Behavior!
At the beginning your string size is zero and you do not resize it. As a result required memory is not allocated and proper information in string is not updated.
Small string optimization probably prevents a crash which should happen.
Two ways to fix it:
// crappy solution - to match your pattern
string s2;
for(int i=0;i<ch;i++)
{
s2.push_back(s[i]);
}
// a good one
string s2(s, s + strlen(s));
I have three string file that will be stored into dynamic array, but I just try one of three file to test if this succed, so I'll do the same way to handle the three file i have.
the goal i'll shown the string that I get from the file to a ListView
this my code.
void __fastcall TFrmNewPeta::showDefaultRute() {
std::string lineDataAwal;
std::ifstream ifs_Awal;
int tempIndexAwal = 0;
ifs_Awal.open("DefaultDataAwal");
/*counting the line*/
while(std::getline(ifs_Awal,lineDataAwal)){++tempIndexAwal;}
/*use dynamic array to stored string*/
std::string *s = new std::string[tempIndexAwal];
for(int dx=0;dx<tempIndexAwal;dx++)
{
while(std::getline(ifs_Awal,lineDataAwal))
s[dx] = lineDataAwal[dx++];
}
for(int dex =0;dex<tempIndexAwal;++dex)
{
ItemDefult = ListView1->Items->Add();
ItemDefult->Caption = String(IntToStr(dex + 1));
ItemDefult->SubItems->Add(s[dex].c_str());
}
ifs_Awal.close();
delete []s;
s = NULL;
}
there's no errors during compile, but the result ListView just showing the number with this code ItemDefult->Caption = String(IntToStr(dex + 1));
can anyone show me how the best way for i do.
You are reading the file, leaving it open, and expecting to read it again. That won't work because the cursor in the file is at the end of the file (so your second while loop does nothing).
A much better approach would be:
std::vector<std::string> lines;
std::string line;
std::ifstream fin("Youfilename");
while (std::getline(fin, line))
{
lines.push_back(line);
}
fin.close();
// add data to your list view
its easier if you use std::vector for dynamic arrays and don't forget to first include the file header with #include<vector>
void __fastcall TFrmNewPeta::showDefaultRute() {
std::string lineDataAwal;
std::ifstream ifs_Awal;
std::vector<std::string> vec;
ifs_Awal.open("DefaultDataAwal");
/*get the string of lineDataAwal */
while(std::getline(ifs_Awal,lineDataAwal))
{ vec.push_back(lineDataAwal);}
for(int dex =0;dex<vec.size();++dex)
{
ItemDefult = ListView1->Items->Add();
ItemDefult->Caption = String(IntToStr(dex + 1));
ItemDefult->SubItems->Add(vec.at(dex).c_str());
}
ifs_Awal.close();
}
Hope this helps
I'm writing a program for an exercise that will read data from a file and format it to be readable. So far, I have a bit of code that will separate a header from the data that goes under it. Here it is:
int main() {
ifstream in("records.txt");
ofstream out("formatted_records.txt");
vector<string> temp;
vector<string> headers;
for (int i = 0; getline(in,temp[i]); ++i) {
static int k = -1;
if (str_isalpha(temp[i])) {
headers[++k] = temp[i];
temp.erase(temp.begin() + i);
}
else {
temp[i] += "," + headers[k];
}
}
}
(str_isalpha() is just a function that applies isalpha() to every character in a string.) Now, the for-loop in this program doesn't execute, and I can't figure out why. Does anybody know?
EDIT: As suggested, I changed it to
string line;
for (int i = 0; getline(in,line); ++i) {
temp.push_back(line);
Still skips the for-loop altogether.
vector<string> temp; makes an empty vector. When you then try to read into temp[0], that is undefined behavior. You should pass as getline's second argument a separate string variable, say string foo; before the loop, then temp.push_back(foo); as the first instruction in the loop's body.
If the loop still doesn't run after ensuring that you're reading into a valid string reference, then you should check that the stream you're reading from is valid. The stream will be invalid if the file doesn't exist or if you lack permission to read it, for instance. When the stream isn't valid, getline won't read anything. Its return value is the same stream, and when converted to bool, it evaluates as false. Check the stream's status before proceeding.
ifstream in("records.txt");
if (!in.is_open()) {
std::cerr << "Uh-oh.\n";
return EXIT_FAILURE;
}