C++ istream::read causes undefined behaviour - c++

I using the following code to copy n character from binary file to char* variable :
std::ifstream is ("write.abc", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
std::cout << "length of buffer: "<<strlen(buffer) <<endl;
std::cout << "Content of buffer: "<<buffer <<endl;
.......
The content of my file:
This is the result of compilation:
My question is the following: I'm waiting to have:
length of buffer: 13
Content of buffer: abcdefghjklmn
Can some one, please, help me to interpret the result?

Your buffer is not terminated - you need to allocate an extra char and set it to '\0', otherwise it's just an unterminated C string, so strlen will most likely return an invalid value, and attempting to print the string will typically produce garbage.
char * buffer = new char [length + 1]; // <<< allocate space for `length`
// characters + terminator
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
buffer[length] = '\0'; // <<< terminate C-style string
Note that using proper C++-style std::strings instead of old school C-style char * strings avoids this and other common problems, and is generally simpler and a lot more robust. If you're reading binary data rather than text, then consider using std::vector<unsigned char>.

Please note that this is not answering the question. It is a followup to a comment
One solution is to "store" the buffer as a [begin, end) range instead of null terminated C string. This has a big advantage over null terminate string - it can be used with STL algorithms without calling strlen(...) to find end element.
Following some examples:
std::stringstream is("some text\n");
if (is)
{
// get length of file:
is.seekg (0, is.end);
auto length = is.tellg();
is.seekg (0, is.beg);
char* begin = new char [length];
char* end = begin + length;
std::cout<<"Reading "<<length<<" characters...\n";
// read data as a block:
is.read (begin,length);
//print the data:
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
//print the data backwards:
std::copy(std::reverse_iterator<char*>(end), std::reverse_iterator<char*>(begin), std::ostream_iterator<char>(std::cout));
std::cout<<std::endl;
//create string from data:
std::string str(begin, end);
std::cout<<str;
//sum the characters
auto sum = std::accumulate(begin, end, 0);
std::cout<<sum<<std::endl;
//make them uppercase
std::transform(begin, end, begin, toupper);
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
}

Related

c++ fstream::read only returning 1st char

Preface: I am a inexperienced coder so its probably an obvious error. Also like all of this code is stolen and slapped together so I claim no ownership of this code.
System: I am using windows 10 64 bit. I write my code in Notepad++ and compile with MinGW G++.
What I'm trying to do: I am trying to read an entire file (BMP format) into a variable and return a pointer to that variable as the return of a function.
What's happening: The variable is only storing the first char of the file.
char* raw_data(std::string filename){
//100% non-stolen
std::ifstream is (filename, std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
std::cout << is.tellg() << "\n";
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... \n";
// read data as a block:
is.read (buffer,length);
std::cout << "\n\n" << *buffer << "\n\n";
if (is)
{std::cout << "all characters read successfully.";}
else
{std::cout << "error: only " << is.gcount() << " could be read";}
is.close();
// ...buffer contains the entire file...
//101% non-stolen
return {buffer};
}
return {};
}
The code calling the function is
char * image_data = new char [image_size];
image_data = raw_data("Bitmap.bmp");
This compiles fine and the EXE outputs
0
Reading 2665949 characters...
B
all characters read successfully.
The file Bitmap.bmp starts:
BM¶ƒ 6 ( € ‰ €ƒ Δ Δ ¨δό¨δό¨δό¨
As you can see, the variable buffer only stores the first char of Bitmap.bmp (if I change the 1st char it also changes)
Any help would be appreciated.
Thank you for your time.
std::cout << "\n\n" << *buffer << "\n\n";
Buffer is a char*, so by dereferencing it you get a single char, which in your case is B. If you want to output the whole data that you read just don't dereference the pointer, in C/C++ char* has special treatment when outputing with std::cout,printf and such.
std::cout << "\n\n" << buffer << "\n\n";
Keep in mind that by convention, C-strings in char* should be null-terminated, yours is not and the caller of your function has no effective way to check how long it is, that information is lost as functions like strlen expect the Cstring to be null-terminated too. You should look at std::vector<char> or std::string for holding such data, as they will hold the information about the size, and clean after themselves.

Reading a single character from a file returns special characters?

Using fstreams I'm attempting to read single characters from a specified location in a file and append them onto a string. For some reason, reading in these characters returns special characters. I've tried numerous things, but the more curious thing that I found while debugging was that changing the initial value of the char temp; will cause the whole string to change to that value.
int Class::numbers(int number, string& buffer) {
char temp;
if (number < 0 || buffer.length() > size) {
exit(0);
}
string fname = name + ".txt";
int start = number * size;
ifstream readin(fname.c_str());
readin.open(fname.c_str(), ios::in)
readin.seekg(start);
for (int i = 0; i < size; ++i) {
readin.get(temp);
buffer += temp;
}
cout << buffer << endl;
readin.close();
return 0;
}
Here is an example screenshot of the special characters being outputted: http://i.imgur.com/6HCI7TT.png
Could the issue be where I'm starting using seekg? It seems to start in the appropriate position. Another thing I've considered is that maybe I'm reading some invalid place into the stream and it's just giving me junk characters from memory.
Any thoughts?
WORKING SOLUTION:
int Class::numbers(int number, string& buffer) {
char temp;
if (number < 0 || buffer.length() > size) {
exit(0);
}
string fname = name + ".txt";
int start = number * size;
ifstream readin(fname.c_str());
readin.open(fname.c_str(), ios::in)
readin.seekg(start);
for (int i = 0; i < size; ++i) {
readin.get(temp);
buffer += temp;
}
cout << buffer << endl;
readin.close();
return 0;
}
Here is the working solution. In my program I had already had this file name open, so opening it twice was likely to cause issues I suppose. I will do some further testing on this in my own time.
For ASCII characters with a numeric value greater than 127, the actual character rendered on screen depends on the code page of the system you are currently using.
What is likely happening is that you are not getting a single "character" as you think you are.
First, to debug this, use your existing code to just open and print out an entire text file. Is your program capable of doing this? If not, it's likely that the "text" file you are opening isn't using ASCII, but possibly UTF or some other form of encoding. That means when you read a "character" (8-bits most likely), you're just reading half of a 16-bit "wide character", and the result is meaningless to you.
For example, the gedit application will automatically render "Hello World" on screen as I'd expect, regardless of character encoding. However, in a hex editor, a UTF8 encoded file looks like:
UTF8 Raw text:
0000000: 4865 6c6c 6f20 776f 726c 642e 0a Hello world..
While UTF16 looks like:
0000000: fffe 4800 6500 6c00 6c00 6f00 2000 7700 ..H.e.l.l.o. .w.
0000010: 6f00 7200 6c00 6400 2e00 0a00 o.r.l.d.....
This is what your program sees. C/C++ expect ASCII encoding by default. If you want to handle other encodings, it's up to your program to accomodate it manually or by using a third-party library.
Also, you aren't testing to see if you've exceeded the length of the file. You could just be grabbing random garbage.
Using a simple text file just containing the string "Hello World", can your program do this:
Code Listing
// read a file into memory
#include <iostream> // std::cout
#include <fstream> // std::ifstream
#include <string.h>
int main () {
std::ifstream is ("test.txt", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
// allocate memory:
char * buffer = new char [length];
// read data as a block:
is.read (buffer,length);
// print content:
std::cout.write (buffer,length);
std::cout << std::endl;
// repeat at arbitrary locations:
for (int i = 0; i < length; i++ )
{
memset(buffer, 0x00, length);
is.seekg (i, is.beg);
is.read(buffer, length-i);
// print content:
std::cout.write (buffer,length);
std::cout << std::endl;
}
is.close();
delete[] buffer;
}
return 0;
}
Sample Output
Hello World
Hello World
ello World
llo World
lo World
o World
World
World
orld
rld
ld
d

How can I assign a std::string from a char * [duplicate]

This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 8 years ago.
This may be trivial, but I'm new to C++ and an getting confused here.
I have the method:
bool load_database_file( const std::string& filename, std::string& contents ) {
std::ifstream is (filename, std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = (int)is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer, length);
if (is)
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << is.gcount() << " could be read";
is.close();
// ...buffer contains the entire file...
std::string str(buffer);
contents = str;
delete[] buffer;
}
return true ;
}
where I would like to read a file and assign it's contents to contents so that it can be read by the calling function.
My issue is that after this function is run, I see that only the first character of buffer was copied to contents.
How can I copy/convert the entire contents of buffer (a char *) to contents (a std::string).
std::string str(buffer);
Should be:
std::string str(buffer, buffer+length);
Otherwise, how can the constructor know how many bytes to allocate/copy?
By the way, your code is needlessly clumsy. Why not read directly into the string's buffer rather than using a separate buffer that you have to allocate and free just to hold the data before you allocate another buffer?

Read unknown symbols when read a content of file

As in the title, when read a content of file i find it reads unknown symbols with the content.
The code:
char *buff = NULL;
size_t size = 0;
ifstream file("c:\\file.txt", ios::out);
if(!file){
cout << "File does not open." << endl;
}
file.seekg(0, file.end);
size = file.tellg();
file.seekg(0, file.beg);
buff = new char[size];
while(!file.eof()){
file.read(buff, size);
}
cout << buff << endl;
delete[] buff;
The file content:
Hello world!.
Thank you for help.
The result:
As you seen in the previous image, there are many unknowns symbols.
Why these symbols appear, what's wrong in my code ?
Your char array is not null terminated, either create the array with space for one extra null character (and set it to '\0')
buff = new char[size + 1];
buff[size] = '\0';
// Or simply
buff = new char[size + 1]{};
or even better avoid using raw pointers wherever possible, especially for character arrays used as strings.
while(!file.eof()) is an antipattern, don't use it except in very specific cases.
std::ifstream file("file.txt");
std::string buff{ // Use regular brackets if not C++11
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>()
};
You can only use operator<<(const char *) for C-style strings. You can't use it for arbitrary chunks of bytes. How would it know where to stop?

C++ Ifstream reads too much?

I'm trying to read a file and output the contents. Everything works fine, I can see the contents but it seems to add about 14 empty bytes at the end. Does anyone know whats wrong with this code?
int length;
char * html;
ifstream is;
is.open ("index.html");
is.seekg (0, ios::end);
length = is.tellg();
is.seekg (0, ios::beg);
html = new char [length];
is.read(html, length);
is.close();
cout << html;
delete[] html;
You didn't put a null terminator on your char array. It's not ifstream reading too much, cout just doesn't know when to stop printing without the null terminator.
If you want to read an entire file, this is much easier:
std::ostringstream oss;
ifstream fin("index.html");
oss << fin.rdbuf();
std::string html = oss.str();
std::cout << html;
That is because html is not null-terminated string, and std::cout keeps printing character until it finds \0, or it may crash your program
Do this:
html = new char [length +1 ];
is.read(html, length);
html[length] = '\0'; // put null at the end
is.close();
cout << html;
Or, you can do this:
cout.write(html, length);
cout.write will stop printing exactly after length number of chars.