Reputation: 446
In my program, I may need to load a large file, but not always. So I have defined:
char** largefilecontents;
string fileName="large.txt";
When I need to load the file, the program calles this function:
bool isitok=LoadLargeFile(fileName,largefilecontents);
And the function is:
bool LoadLargeFile(string &filename, char ** &lines)
{
if (lines) delete [] lines;
ifstream largeFile;
#ifdef LINUX
largeFile.open(filename.c_str());
#endif
#ifdef WINDOWS
largeFile.open(filename.c_str(),ios::binary);
#endif
if (!largeFile.is_open()) return false;
lines=new char *[10000];
if (!lines) return false;
largeFile.clear();
largeFile.seekg(ios::beg);
for (int i=0; i>-1; i++)
{
string line="";
getline(largeFile,line);
if (largeFile.tellg()==-1) break; //when end of file is reached, tellg returns -1
lines[i]=new char[line.length()];
lines[i]=const_cast<char*>(line.c_str());
cout << lines[i] << endl; //debug output
}
return true;
}
When I view the debug output of this function, "cout << lines[i] << endl;", it is fine. But when I then check this in the main program like this, it is all messed up:
for (i=0; i<10000; i++)
cout << largefilecontents[i] << endl;
So within the function LoadLargeFile()
, the results are fine, but without LoadLargeFile()
, the results are all messed up. My guess is that the char ** &lines
part of the function isn't right, but I do not know what this should be.
Could someone help me? Thank you in advance!
Upvotes: 1
Views: 129
Reputation: 4034
The problem is where you are using line.c_str
. You are first allocating the memory for your new string using lines[i]=new char[line.length()];
but then you overwrite the pointer in line[i]
with a pointer referring to the c_str within the local variable line
. This c_str
will get destroyed when line
goes out of scope. What you need to do is use strcpy
instead of doing simple pointer assignment.
Try the following
lines[i]=new char[line.length()+1]; //Thanks @Claptrap for the catch
strncpy(lines[i], line.c_str(), line.length()+1); //Note, strcpy is not considered safe.
//Use strncpy
If you want to stick to strictly c++ ways then I'd recommend using @christian-hackl 's suggestion of making
std::vector<std::string> largefilecontents; //Since in your case 10000 is fixed
...
bool LoadLargeFile(string &filename, std::vector<std::string> &lines)
{
...
//lines=new char *[10000];
//if (!lines) return false;
lines.resize(10000); //Since in your case 10000 is fixed
...
for...
if(i >= lines.size()) break; //safety net in case more than 10000 lines
lines[i]="";
getline(largeFile,lines[i]);
if (largeFile.tellg()==-1) break; //when end of file is reached, tellg returns -1
//lines[i]=new char[line.length()];
//lines[i]=const_cast<char*>(line.c_str());
Arrays are raw C++ datatypes while Vectors are classes, part of standard template library. This means that in theory vectors are slower than arrays. But in practice that drop in speed is negligible. Vectors provide two huge benefits for negligible cost
There are two costs associated with vectors
References:
Upvotes: 1
Reputation: 36082
The lines
lines[i]=new char[line.length()];
lines[i]=const_cast<char*>(line.c_str());
do not do what you expect them to
lines[i] = new char [line.length()]
allocate a number of bytes for the string but does not include the ending \0 for the string.
the lines[i]=const_cast<char*>(line.c_str());
is setting it to point a local string variable which last as long as one iteration. What you need to do is to allocate a buffer on the heap like you did for your pointers and then copy to it
lines[i] = new char[line.length() + 1];
strcpy(lines[i], line.c_str() );
if this is an exercise from school then i will not say more but if it is a real program then you should instead use a vector<string>
to keep things simple instead of fiddling with raw arrays.
one other thing is that it is better if you initialize all your pointers to NULL before reading in lines so that the caller of the function knows when to stop processing the pointers.
that way you can write
for (int j = 0; lines[j] != NULL; ++j)
cout << lines[j] << endl;
Upvotes: 1
Reputation: 27528
This piece of code has many deficiencies, so it is very hard to reason about it. For example:
if (!lines) return false;
is useless, because new
will (in any normal environment) not return null but throw an exception if memory runs out.
The next thing is, why the magic number 10000? What happens if your file contains more than 10000 lines? Look at your loop:
for (int i=0; i>-1; i++)
It just increments i
until it has the maximum allowed value for an int
, at which point the incrementation yields undefined behaviour (e.g. seemingly random crashes).
Next, this line:
getline(largeFile,line);
You do not check the stream for errors after the operation but just assume that the reading worked. That's not good practice.
Finally, this line:
lines[i]=const_cast<char*>(line.c_str());
Casting away the costness of a char const *
yields undefined behaviour as well.
Have you even tried just storing the contents of the "large file" in a std::vector<std::string>
? Chances are that your assumption that it's too big for a normal string vector and that you thus have to use pointers is simply wrong.
Upvotes: 0
Reputation: 73366
Check what passing by value and what passing by reference is. The problem is that the changes are not preserved after the termination of the function.
However, I feel that the problem starts from how you declare your 2D char array. I think you do that statically, were you could do it easily dynamically, like this:
// We return the pointer
char **get(int N, int M) /* Allocate the array */
{
/* Normally, you should check if allocation was ok. */
char** ary = new char*[N];
for(int i = 0; i < N; ++i)
ary[i] = new char[M];
return ary;
}
void delete2Darray(char** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
delete [] p[i];
delete p;
}
void foo(char** p)
{
printf("%s\n", p[0]);
strcpy(p[0], "sam");
printf("%s\n", p[0]);
}
int main()
{
char** A = get(1, 5);
strcpy(A[0], "dad");
foo(A);
printf("%s\n", A[0]);
delete2Darray(A, 1);
return 0;
}
which gives the output:
dad
sam
sam
Here is a simple example in C, about this. (this is my pseudo-site).
Upvotes: 1