get corruption at end of string

A

Angus

Hello

I am using ifstream to load the contents of a text file into a char*
variable. I am allocating using new with the file size as amount to
allocate. My problem is that the variable contains a load of misc
extraneous data at the end of the variable.

Here is the code.

int main(int argc, char* argv[])
{
std::ifstream myfile;
std::string line;
long begin,end;
char szFile[256];
char* memblock;
std::ifstream::pos_type size;
std::cout << "Enter filename to open: ";
std::cin.getline(szFile, 256);
std::cout << "You selected file: " << szFile << std::endl;


myfile.open( szFile );
if (myfile.is_open())
{
begin = myfile.tellg();
myfile.seekg (0, std::ios::end);
end = myfile.tellg();
size = end-begin;
memblock = new char [size];
myfile.seekg (0, std::ios::beg);
myfile.read (memblock, size);
myfile.close();

std::cout << memblock << std::endl;

delete [] memblock;
}

return 0;
}

if I myfile.read just size then why do I get all the unallocated characters
at the end of the memblock variable?

Angus
 
A

Andre Kostur

Hello

I am using ifstream to load the contents of a text file into a char*
variable. I am allocating using new with the file size as amount to
allocate. My problem is that the variable contains a load of misc
extraneous data at the end of the variable.

Here is the code.

int main(int argc, char* argv[])
{
std::ifstream myfile;
std::string line;
long begin,end;
char szFile[256];
char* memblock;
std::ifstream::pos_type size;
std::cout << "Enter filename to open: ";
std::cin.getline(szFile, 256);
std::cout << "You selected file: " << szFile << std::endl;


myfile.open( szFile );
if (myfile.is_open())
{
begin = myfile.tellg();
myfile.seekg (0, std::ios::end);
end = myfile.tellg();
size = end-begin;
memblock = new char [size];
myfile.seekg (0, std::ios::beg);
myfile.read (memblock, size);
myfile.close();

std::cout << memblock << std::endl;

delete [] memblock;
}

return 0;
}

if I myfile.read just size then why do I get all the unallocated
characters at the end of the memblock variable?

Because you're reading into a C-style string. You have no terminating
nul ('\0') character at the end of your C-style string. Thus the cout
<< memblock stuff has no idea when to stop reading your string.

If you really want to stick with C-style strings, replace your "new" line
with:

memblock = new char[size + 1];
memblock[size] = '\0';
 
J

James Kanze

I am using ifstream to load the contents of a text file into a char*
variable. I am allocating using new with the file size as amount to
allocate. My problem is that the variable contains a load of misc
extraneous data at the end of the variable.
Here is the code.

A meta-comment: this would be a lot easier and clearer if you'd
use std::string.
int main(int argc, char* argv[])
{
std::ifstream myfile;
std::string line;
long begin,end;
char szFile[256];
char* memblock;

I'd initialize this to something, at least NULL. Or just
define it later, when you can initialize it correctly.

In general, it is bad policy to define variables before you can
correctly initialize them. In the case of pointers, it's
particularly serious.
std::ifstream::pos_type size;
std::cout << "Enter filename to open: ";
std::cin.getline(szFile, 256);
std::cout << "You selected file: " << szFile << std::endl;
myfile.open( szFile );
if (myfile.is_open())
{
begin = myfile.tellg();
myfile.seekg (0, std::ios::end);

Note that this seek may set eofbit, which will in turn cause all
further operations to fail. (I don't think it's supposed to,
but I believe that it does, or at least did, in some
implementations. I'd throw in a call to clear(), here, just to
be sure.)
end = myfile.tellg();
size = end-begin;

Note that this is not guaranteed to give you anything
significant. In the case of Unix, it probably will result in
the file size. In the case of Windows, it will almost surely be
more than is necessary. And on other systems, it might have no
relationship what so ever to the real file size.
memblock = new char [size];
myfile.seekg (0, std::ios::beg);
myfile.read (memblock, size);

Did the read succeed? How many characters did you really read?

istream::read() is a funny function, since it can "fail" even
when it partially succeeds. Basically, it will "fail" unless it
can read size characters (which will almost certainly be the
case if you're not on Unix). Basically, you need to call
gcount(), to know how many characters it actually read---only if
gcount() returns 0 did the read completely fail.
myfile.close();
std::cout << memblock << std::endl;

Since memblock isn't '\0' terminated, it's not a legal argument
to << here.

Personally, I'd write this entire block:

std::istringstream s ;
s << myfile.rdbuf() ;
std::cout << s.str() << std::endl ;

If for some reason I really needed a C style array, and didn't
have to worry about portability beyond Unix and Windows, I'd do
something along the lines of:

// Calculate size as above. It will be exact
// under Unix, and >= the real size under Windows,
// typically a little greater, but not too much.
std::vector< char > buffer( size + 1 ) ;
myfile.read( &buffer[ 0 ], size ) ;
size = myfile.gcount() ;
if ( ! myfile && size == 0 ) {
// Error...
} else {
buffer[ size ] = '\0' ;
// use &buffer[ 0 ] as C style string...
}
delete [] memblock;
}

return 0;
}
if I myfile.read just size then why do I get all the unallocated characters
at the end of the memblock variable?

Because you don't terminate the C style string. And because you
don't check how many characters you've actually read, to know
where to terminate it.
 
A

Angus

Personally, I'd write this entire block:

std::istringstream s ;
s << myfile.rdbuf() ;

If I try that I get this compile error:
ifstreamtest.cpp(99) : error C2676: binary '<<' : 'class
std::basic_istringstream<char,struct std::char_traits<char>,class
std::allocator<char> >' does not define this operator or a conversion to a
type acceptable to the predefined operator
 
J

John Harrison

Angus said:
Personally, I'd write this entire block:

std::istringstream s ;
s << myfile.rdbuf() ;

If I try that I get this compile error:
ifstreamtest.cpp(99) : error C2676: binary '<<' : 'class
std::basic_istringstream<char,struct std::char_traits<char>,class
std::allocator<char> >' does not define this operator or a conversion to a
type acceptable to the predefined operator

I think James meant

std::eek:stringstream s ;
s << myfile.rdbuf() ;

john
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,001
Messages
2,570,250
Members
46,848
Latest member
Graciela Mitchell

Latest Threads

Top