C++ reading binary data to struct - c++

I am currently reading a binary file that i know the structure of and i am trying to place into a struct but when i come to read off the binary file i am finding that when it prints out the struc individually it seems to come out right but then on the fourth read it seems to add it onto last member from the last read.
here the code which probably make's more sense than how i am explaining it:
Struc
#pragma pack(push, r1, 1)
struct header
{
char headers[13];
unsigned int number;
char date[19];
char fws[16];
char collectversion[12];
unsigned int seiral;
char gain[12];
char padding[16];
};
Main
header head;
int index = 0;
fstream data;
data.open(argv[1], ios::in | ios::binary);
if(data.fail())
{
cout << "Unable to open the data file!!!" << endl;
cout << "It looks Like Someone Has Deleted the file!"<<endl<<endl<<endl;
return 0;
}
//check the size of head
cout << "Size:" << endl;
cout << sizeof(head) << endl;
data.seekg(0,std::ios::beg);
data.read( (char*)(&head.headers), sizeof(head.headers));
data.read( (char*)(&head.number), sizeof(head.number));
data.read( (char*)(&head.date), sizeof(head.date));
data.read( (char*)head.fws, sizeof(head.fws));
//Here im just testing to see if the correct data went in.
cout<<head.headers<< endl;
cout<<head.number<< endl;
cout<<head.date<< endl;
cout<<head.fws<< endl;
data.close();
return 0;
Output
Size:
96
CF001 D 01.00
0
15/11/2013 12:16:56CF10001001002000
CF10001001002000
for some reason the fws seems to add to head.date? but when i take out the line to read head.fws i get a date that doesn't have anything added?
i also know thier more data to get for the header but i wanted to check the data up to what i have written is correct
cheers

1. Your date is declared as:
char date[19];
2. Your date format is exactly 19-characters long:
15/11/2013 12:16:56
3. And you print it this way:
cout<<head.date
Shortly speaking, you try to print fixed char[] using its address, which means, that it will be interpreted as null-terminated c-string. Is it null-terminated? No.
To solve this problem, declare date as:
char date[20];
And after you fill it, append null terminator:
date[19] = 0;
It applies to all members, that will be interpreted as string literals.

You have char date[19] filled with 15/11/2013 12:16:56 which is exactly 19 valid characters. This leaves no space for a terminating null and so doing cout << head.date outputs your 19 valid characters and then a load of garbage.

Related

Converting an integer to Char Pointer using C

I am trying to convert an integer to a char pointer as shown below. The data results are different. I am not sure what is going wrong. Please help me in correcting the code.
int main(){
char *key1 = "/introduction";
std::ostringstream str1;
str1<< 10;
std::string data=str1.str();
std::cout <<"The data value="<<data<<std::endl; // The data value= 10
char *intro= new char[data.length()+1];
strcpy(intro, data.c_str());
std::cout <<"The data value="<<*intro <<std::endl; // The data value=1
return 0;
}
I am not sure why two data value are printed different i.e, 10 and 1.
In C++, when trying to print all the contents of a char * with cout, you should pass the pointer, i.e. cout << intro << endl.
What you've done here is dereferenced the char *, so cout << *intro << endl is equivalent to cout << intro[0] << endl, which is equivalent to printing the first character, 1.

C++ cout corruption

I am reading a file header using ifstream.
Edit: I was asked to put the full minimal program, so here it is.
#include <iostream>
#include <fstream>
using namespace std;
#pragma pack(push,2)
struct Header
{
char label[20];
char st[11];
char co[7];
char plusXExtends[9];
char minusXExtends[9];
char plusYExtends[9];
};
#pragma pack(pop)
int main(int argc,char* argv[])
{
string fileName;
fileName = "test";
string fileInName = fileName + ".dst";
ifstream fileIn(fileInName.c_str(), ios_base::binary|ios_base::in);
if (!fileIn)
{
cout << "File Not Found" << endl;
return 0;
}
Header h={};
if (fileIn.is_open()) {
cout << "\n" << endl;
fileIn.read(reinterpret_cast<char *>(&h.label), sizeof(h.label));
cout << "Label: " << h.label << endl;
fileIn.read(reinterpret_cast<char *>(&h.st), sizeof(h.st));
cout << "Stitches: " << h.st << endl;
fileIn.read(reinterpret_cast<char *>(&h.co), sizeof(h.co));
cout << "Colour Count: " << h.co << endl;
fileIn.read(reinterpret_cast<char *>(&h.plusXExtends),sizeof(h.plusXExtends));
cout << "Extends: " << h.plusXExtends << endl;
fileIn.read(reinterpret_cast<char *>(&h.minusXExtends),sizeof(h.minusXExtends));
cout << "Extends: " << h.minusXExtends << endl;
fileIn.read(reinterpret_cast<char *>(&h.plusYExtends),sizeof(h.plusYExtends));
cout << "Extends: " << h.plusYExtends << endl;
// This will output corrupted
cout << endl << endl;
cout << "Label: " << h.label << endl;
cout << "Stitches: " << h.st << endl;
cout << "Colour Count: " << h.co << endl;
cout << "Extends: " << h.plusXExtends << endl;
cout << "Extends: " << h.minusXExtends << endl;
cout << "Extends: " << h.plusYExtends << endl;
}
fileIn.close();
cout << "\n";
//cin.get();
return 0;
}
ifstream fileIn(fileInName.c_str(), ios_base::binary|ios_base::in);
Then I use a struct to store the header items
The actual struct is longer than this. I shortened it because I didn't need the whole struct for the question.
Anyway as I read the struct I do a cout to see what I am getting. This part is fine.
As expected my cout shows the Label, Stitches, Colour Count no problem.
The problem is that if I want to do another cout after it has read the header I am getting corruption in the output. For instance if I put the following lines right after the above code eg
Instead of seeing Label, Stitches and Colour Count I get strange symbols, and corrupt output. Sometimes you can see the output of the h.label, with some corruption, but the labels are Stitches are written over. Sometimes with strange symbols, but sometimes with text from the previous cout. I think either the data in the struct is getting corrupted, or the cout output is getting corrupted, and I don't know why. The longer the header the more the problem becomes apparent. I would really like to do all the couts at the end of the header, but if I do that I see a big mess instead of what should be outputting.
My question is why is my cout becoming corrupted?
Using arrays to store strings is dangerous because if you allocate 20 characters to store the label and the label happens to be 20 characters long, then there is no room to store a NUL (0) terminating character. Once the bytes are stored in the array there's nothing to tell functions that are expecting null-terminated strings (like cout) where the end of the string is.
Your label has 20 chars. That's enough to store the first 20 letters of the alphabet:
ABCDEFGHIJKLMNOPQRST
But this is not a null-terminated string. This is just an array of characters. In fact, in memory, the byte right after the T will be the first byte of the next field, which happens to be your 11-character st array. Let's say those 11 characters are: abcdefghijk.
Now the bytes in memory look like this:
ABCDEFGHIJKLMNOPQRSTabcdefghijk
There's no way to tell where label ends and st begins. When you pass a pointer to the first byte of the array that is intended to be interpreted as a null-terminated string by convention, the implementation will happily start scanning until it finds a null terminating character (0). Which, on subsequent reuses of the structure, it may not! There's a serious risk of overrunning the buffer (reading past the end of the buffer), and potentially even the end of your virtual memory block, ultimately causing an access violation / segmentation fault.
When your program first ran, the memory of the header structure was all zeros (because you initialized with {}) and so after reading the label field from disk, the bytes after the T were already zero, so your first cout worked correctly. There happened to be a terminating null character at st[0]. You then overwrite this when you read the st field from disk. When you come back to output label again, the terminator is gone, and some characters of st will get interpreted as belonging to the string.
To fix the problem you probably want to use a different, more practical data structure to store your strings that allows for convenient string functions. And use your raw header structure just to represent the file format.
You can still read the data from disk into memory using fixed sized buffers, this is just for staging purposes (to get it into memory) but then store the data into a different structure that uses std::string variables for convenience and later use by your program.
For this you'll want these two structures:
#pragma pack(push,2)
struct RawHeader // only for file IO
{
char label[20];
char st[11];
char co[7];
char plusXExtends[9];
char minusXExtends[9];
char plusYExtends[9];
};
#pragma pack(pop)
struct Header // A much more practical Header struct than the raw one
{
std::string label;
std::string st;
std::string co;
std::string plusXExtends;
std::string minusXExtends;
std::string plusYExtends;
};
After you read the first structure, you'll transfer the fields by assigning the variables. Here's a helper function to do it.
#include <string>
#include <string.h>
template <int n> std::string arrayToString(const char(&raw)[n]) {
return std::string(raw, strnlen_s(raw, n));
}
In your function:
Header h;
RawHeader raw;
fileIn.read((char*)&raw, sizeof(raw));
// Now marshal all the fields from the raw header over to the practical header.
h.label = arrayToString(raw.label);
h.st = arrayToString(raw.st);
h.st = arrayToString(raw.st);
h.co = arrayToString(raw.co);
h.plusXExtends = arrayToString(raw.plusXExtends);
h.minusXExtends = arrayToString(raw.minusXExtends);
h.plusYExtends = arrayToString(raw.plusYExtends);
It's worth mentioning that you also have the option of keeping the raw structure around and not copying your raw char arrays to std::strings when you read the file. But you must then be certain that when you want to use the data, you always to compute and pass lengths of the strings to functions that will deal with those buffers as string data. (Similar to what my arrayToString helper does anyway.)

Need to convert char* to string or other type in order to run hash on it

I need to read in an mp3 file so that I can run the hash(). I do not need to parse the mp3 tag data out of this so I can just read the whole thing all together.
Currently I am using ifstream() to open the file in binary mode. I then get the size of the file, allocate enough space with a char* and read it all at once.
I know that when I run cout on this data I can only see "ID3 and some gibberish." I opened the mp3 file up in a hex editor and ID3 and the gibberish was what was at the beginning of the file. The next binary data I believe is being interpreted as end of line/string and does not print.
This is okay because I don't need to print it. I need to get the data in a format that I can run the Hash function on. Any ideas on a type I can convert it to that will not interpret the end of the file being a couple bytes in?
Here is code of what I have so far.
bool Sender::openSoundFile(){
streampos size;
soundSampleStream.open(soundFilePath.c_str(), ios::in|ios::binary|ios::ate);
if(!soundSampleStream.is_open()){
return false;
}
size = soundSampleStream.tellg();
cout << "Size of MP3: " << size << endl;
soundFileInMemory = new char [size];
soundSampleStream.seekg (0, ios::beg);
soundSampleStream.read(soundFileInMemory, size);
cout << "Error is: " << strerror(errno) << endl;
cout << "gcount: " << soundSampleStream.gcount() << endl;
soundSampleStream.close();
cout << soundFileInMemory << endl;
return true;
}
I get no error on reading the file and gcount() comes back with the correct numbers of bytes for the file.
Edit 1:
To add some more on this. The hash() seems to hash the char* and not the data being pointed at because the hash value changes on different program runs. This is why I need to convert to some other thing. I also don't think that a vector is supported by the c++11 hash().
std::string has a constructor that takes a char * and a size_t. See the fourth item in http://en.cppreference.com/w/cpp/string/basic_string/basic_string.
std::string file_contents(soundFileInMemory, size);
That will convert your char array to a string.

Why does this work? Using cin to read to a char array smaller than given input

I'm reading C++ Primer Plus (6th Edition) and I've come across some sample code in chapter 4 which I have a question about:
Listing 4.2 strings.cpp
// strings.cpp -- storing strings in an array
#include <iostream>
#include <cstring> // for the strlen() function
int main()
{
using namespace std;
const int Size = 15;
char name1[Size]; // empty array
char name2[Size] = "C++owboy"; // initialized array
// NOTE: some implementations may require the static keyword
// to initialize the array name2
cout << "Howdy! I'm " << name2;
cout << "! What's your name?\n";
cin >> name1;
cout << "Well, " << name1 << ", your name has ";
cout << strlen(name1) << " letters and is stored\n";
cout << "in an array of " << sizeof(name1) << " bytes.\n";
cout << "Your initial is " << name1[0] << ".\n";
name2[3] = '\0'; // set to null character
cout << "Here are the first 3 characters of my name: ";
cout << name2 << endl;
return 0;
}
The code itself doesn't cause any confusion, but I've been running it through and I'm confused by a certain scenario.
name1 is initialised as an array of chars 15 elements in length - am I right in thinking this should hold a string 14 characters in length? The end char should be reserved for the string terminator, right?
If I enter my name as HowCanIPossiblyFitThisEntireStringIn?, I get the following output:
Howdy! I'm C++owboy! What's your name?
HowCanIPossiblyFitThisEntireStringIn?
Well, HowCanIPossiblyFitThisEntireStringIn?, your name has 37 letters and is stored
in an array of 15 bytes.
Your initial is H.
Here are the first 3 characters of my name: C++
How is the entire name I enter being stored? If I step through the code, after cin reads into name1, Visual Studio tells me it contains elements 0 - 14, with the last one being the char 'y' ("HowCanIPossibly...). I would assume from this that any extra data entered had been truncated and lost, but this is obviously not the case as the following cout successfully writes the entire name out to the console.
For curiosity's sake, could anyone enlighten me as to what's happening here? For the record, I'm using Visual Studio 2012 Express.
You are writing past the bounds of the array. The C++ standard doesn't say this should be an error; it says it is undefined behaviour. This means anything can happen, including seemingly working correctly. Simply put, your code does not have well-defined behaviour and so you shouldn't trust it to work.
We can imagine why it's probably working though. The first 15 characters will fit nicely into the array:
|H|o|w|C|a|n|I|P|o|s|s|i|b|l|y|F|i|t|T|h|i|s|E|n|t|i|r|e|S|t|r|i|n|g|I|n|?|...
^ ^
| These characters fit |
in the array
The rest of the characters are being written to the following memory locations. Now, remember that the null character, which is used to terminate C-style strings, is defined to have a representation that is all 0 bits. Now if the location following the location that contains the ? has all 0 bits in it, the string will appear to be null-terminated.
But the fact is, this is undefined. It just happens to work. Unfortunately, this is the scariest type of bug because it can seemingly work for a long time until one day you start getting calls from your very, very angry client.
You could use istream::get with the buffer and the size of the buffer:
cin.get(name1, Size);
As others have noted, it's far easier to use std::string:
std::string name1;
cin >> name;

how to print char array in c++

how can i print a char array such i initialize and then concatenate to another char array? Please see code below
int main () {
char dest[1020];
char source[7]="baby";
cout <<"source: " <<source <<endl;
cout <<"return value: "<<strcat(dest, source) <<endl;
cout << "pointer pass: "<<dest <<endl;
return 0;
}
this is the output
source: baby
return value: v����baby
pointer pass: v����baby
basically i would like to see the output print
source: baby
return value: baby
pointer pass: baby
You haven't initialized dest
char dest[1020] = ""; //should fix it
You were just lucky that it so happened that the 6th (random) value in dest was 0. If it was the 1000th character, your return value would be much longer. If it were greater than 1024 then you'd get undefined behavior.
Strings as char arrays must be delimited with 0. Otherwise there's no telling where they end. You could alternatively say that the string ends at its zeroth character by explicitly setting it to 0;
char dest[1020];
dest[0] = 0;
Or you could initialize your whole array with 0's
char dest[1024] = {};
And since your question is tagged C++ I cannot but note that in C++ we use std::strings which save you from a lot of headache. Operator + can be used to concatenate two std::strings
Don't use char[]. If you write:
std::string dest;
std::string source( "baby" )
// ...
dest += source;
, you'll have no problems. (In fact, your problem is due to the fact
that strcat requires a '\0' terminated string as its first argument,
and you're giving it random data. Which is undefined behavior.)
your dest array isn't initialized. so strcat tries to append source to the end of dest wich is determined by a trailing '\0' character, but it's undefined where an uninitialized array might end... (if it does at all...)
so you end up printing more or less random characters until accidentially a '\0' character occurs...
Try this
#include <iostream>
using namespace std;
int main()
{
char dest[1020];
memset (dest, 0, sizeof(dest));
char source[7] = "baby";
cout << "Source: " << source << endl;
cout << "return value: " << strcat_s(dest, source) << endl;
cout << "pointer pass: " << dest << endl;
getchar();
return 0;
}
Did using VS 2010 Express.
clear memory using memset as soon as you declare dest, it's more secure. Also if you are using VC++, use strcat_s() instead of strcat().