I have an object with a char Array; where the first 5 bytes(char in C++) are additional data and everything afterwards is a string message.
So my question is how can I get a string from starting index 5 way up to the last byte?
I know there is memccpy, but it requires an ending char, which I can't know beforehand.
I am aware there is a string object in C++, but the idea is to send back and forth a byte array which contains the data and message. So in a sense I serialize and deserialize back and forth.
Any suggestions?
Edit:
Packet * Packet::create(byte const data[])
{
//Concat all first 4 byte values to a uint32
unsigned int length = data[0] << 32 | data[1] << 16 | data[2] << 8 | data[3] << 0;
//4th element is packet type
PacketType type = (PacketType)data[4];
string packetData;
packetData.clear();
char * cdata;
//Check packet data is present
if(sizeof(data) > 5)
{
//string s((char)data);
//packetData = s.substr(4, s.length() - 4);
strncat(cdata,data+5,sizeof(data)-5);
packetData.append(cdata);
}
//Create new packet;
Packet * packet = new Packet(length,type,packetData);
return packet;
};
It won't accept data[] even when I cast it to char.
The argument isn't a pointer?
Edit::
Packet * Packet::create(char const * data)
{
//Concat all first 4 byte values to a uint32
unsigned int length = data[0] << 32 | data[1] << 16 | data[2] << 8 | data[3] << 0;
//4th element is packet type
PacketType type = (PacketType)data[4];
//Set packet data, if available
string packetData = (sizeof(data) > 5) ? string(data+5):"";
Packet * packet = new Packet(length,type,packetData);
return packet;
};
I still have to test this, but I had to use char, how do I use my own typedef in this situation?
Also what is the difference between
"char * data"
and
"char data[]"
I thought arrays and pointers are one and the same thing.
You mentioned "know there is memccpy, but it requires an ending char, which I can't know beforehand". Does that means that your serialized data doesn't have neither the size of the data nor a delimiter? Without that how do you expect
"string packetData = (sizeof(data) > 5) ? string(data+5):"";"
to work?
For the serialization you could send the size of your data as well in the header. Then use the simple memcpy.
use strcpy with charArray + 5 as source parameter.
You should also know of strlen which gives you the string's length [might be needed to allocate the char[], if there is not known upper bound for it].
EDIT: code snap:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char in[] = "XXXXXqwerty";
//dynamic allocation using strlen() if you don't have upper bound for in
char* out = new char[strlen(in) - 4];
strcpy(out,in+5);
cout << out;
delete[] out;
return 0;
}
Related
struct st {
char *p;
int len;
};
this is the structure which i need to write to a binary file, along with the string which is saved in
char *p
I am supposed to write a binary file with the char array data. After writing to binary file. Is should also be able to read it in the same structure from binary file.
I tried using FSEEK_END to get the binary size, and doing fread according to file size, but it is not saving string. Please suggest. Any help/suggestion/pointer would be appreciated.
thanks in advance.
sample code:
struct st {
char *p;
int len;
};
struct st varr;
varr.len = 100;
varr.p = new char[gen];
strcpy(varr.p, "Hello World");
FILE *p;
p=fopen("address","wb");
fwrite(&varr,sizeof(struct st),1,p);
fclose(p);
this will write me the pointer to the binary file. But i want to write here whole string, but the point is, it should done with one fwrite.
There is no use writing this to a binary file. A text file would suffice.
However, if this is your homework assignment (or so), I suggest you proceed as follows:
write the length as an integer;
write len bytes of the string. This does not include a terminating null.
When reading back:
read the integer length;
allocate memory of this length plus one byte
read the string into that memory and add the terminating null.
Fill your structure with this length and the pointer to allocated memory.
In your comments you keep iterating you want to read and write in one step. With your current data structure that is not possible because the character string wil always be somewhere else in memory and fwrite can only write a contiguous block of memory.
However, would you change your data structure to:
struct st{
char p[128];
int len;
};
then you can write and read in one go because now the struct is a contiguous memory block. But now the string is limited to this 128 bytes(or any size you make it).
I would suggest saving the strlen(p) first, followed by all the chars pointed by char *p. If you try to fwrite the struct as it is, you'll end up (in the file) with the value for the address with regrads to the first char. You do not want to save the address of the 1st char, do you?
If you are so much concerned about not having two fwrite you can have wrapper structure with zero length array.
struct st_wrap {
int len;
char p[0];
};
struct st_wrap *temp= malloc (sizeof (struct st_wrap ) + strlen(varr.p)+1);
temp->len = strlen(varr.p);
//Copy the data
strcpy(temp->p,varr.p);
//Then write it to file
fwrite(temp,sizeof(struct st_wrap)+strlen(varr.p),1,p);
Assuming you have written the length and string to binary file:
FILE* fp = fopen("file.bin", "wb");
/* writing */
st str = { .p = "foo", .len = 3 };
fwrite((char*)(&str.len), sizeof(str.len), sizeof(str.len), fp);
fwrite(str.p, str.len, str.len, fp);
You can now (in a different context) read the content from file into the struct object:
FILE* fp = fopen("file.bin", "rb");
st str;
/* read length */
fread((char*)&str.len, sizeof(str.len), sizeof(str.len), fp);
/* allocate enough space */
str.p = malloc((str.len + 1) * sizeof(char));
/* read string */
fread(str.p, str.len + 1, str.len + 1, fp);
Remember to free memory when you're done with p:
free(str.p);
I tried lot of ways, but #kiran Biradar's answer helped me a lot. hence displaying the working code here.
WriteBinaryFile.cpp
struct st_wrap {
int len;
int crc;
char p[0];
};
int main ()
{
char p[100] = "Hello World";
struct st_wrap *temp= (struct st_wrap*) malloc (sizeof (struct st_wrap ) + strlen(p)+1);
temp->len = strlen(p);
temp->crc = 400;
strcpy(temp->p,p);
cout << temp->p << endl;
cout << temp->len << endl;
cout << temp->crc << endl;
FILE *p1;
p1=fopen("binary.dat","wb");
fwrite(temp,sizeof(struct st_wrap)+strlen(p),1,p1);
fclose(p1);
}
ReadBinaryFile.cpp
struct st_wrap {
int len;
int crc;
char p[0];
};
int main ()
{
struct st_wrap *vw;
FILE *f=fopen("binary.dat","rb");
fseek(f, 0, SEEK_END);
long int filesize = ftell(f);
fseek(f, 0, SEEK_SET);
vw = (struct st_wrap*) malloc (filesize);
fread(vw,filesize,1,f);
cout << vw->len << endl;
cout << vw->p << endl;
cout << vw->crc << endl;
return 0;
}
QByteArray ba;
QDataStream ds(&ba,QIODevice::WriteOnly);
ds<<quint8(1)<<quint16(2)<<quint32(3); //1+2+4
qDebug()<<"size:"<<ba.size(); // 7
I use QDataStream to write 3 number, ba.size() is 7, but I'm confused about this:
QByteArray ba;
QDataStream ds(&ba,QIODevice::WriteOnly);
QString s="a";
ds<<quint8(1)<<quint16(2)<<quint32(3)<<s; //1+2+4+a
qDebug()<<"size:"<<ba.size(); // 13
If a QString's size is 1, ba's size plus 6, why is that? sizeof(QString) is 4.
Let's analyze the difference between both impressions:
"\x01\x00\x02\x00\x00\x00\x03"
"\x01\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\x00""a"
-----------------------------------------------------
x00\x00\x00\x02\x00""a
And for that, let's review the source code:
QDataStream &operator<<(QDataStream &out, const QString &str)
{
if (out.version() == 1) {
out << str.toLatin1();
} else {
if (!str.isNull() || out.version() < 3) {
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
out.writeBytes(reinterpret_cast<const char *>(str.unicode()), sizeof(QChar) * str.length());
} else {
QVarLengthArray<ushort> buffer(str.length());
const ushort *data = reinterpret_cast<const ushort *>(str.constData());
for (int i = 0; i < str.length(); i++) {
buffer[i] = qbswap(*data);
++data;
}
out.writeBytes(reinterpret_cast<const char *>(buffer.data()), sizeof(ushort) * buffer.size());
}
} else {
// write null marker
out << (quint32)0xffffffff;
}
}
return out;
}
That method uses the writeBytes() method,
and according to the docs:
QDataStream &QDataStream::writeBytes(const char *s, uint len)
Writes the length specifier len and the buffer s to the stream and
returns a reference to the stream.
The len is serialized as a quint32, followed by len bytes from s. Note
that the data is not encoded.
That is, apart from writing the data, write the length of the text in quint32 format (4 bytes) and the length of the buffer is equal to sizeOf(QChar) x length of the QString.
Taking into account in it we can understand the result better:
x00\x00\x00\x02 \x00""a
--------------- -------
numbers of bytes of buffer buffer
In general you can use the following formula to calculate the size of the stored data:
length stored data = 4 + 2 x length of string
By checking Qt Documentation for QDatastream, how strings are stored and retreived:
a char * string is written as a 32-bit integer equal to the length of
the string including the '\0' byte, followed by all the characters of
the string including the '\0' byte. When reading a char * string, 4
bytes are read to create the 32-bit length value, then that many
characters for the char * string including the '\0' terminator are
read.
So in your case 32 bit for length of the string + 1 Byte for "a" + 1 byte for \0, which sums to 6 bytes.
I'm using memcpy to copy a specific number of chars from a char array to a char *. But when I read the char * have always trash in the end.
I'm using libssh2 lib to send commands to my raspberry pi and receive the output.
libssh2_channel_read will return the number of chars of the output int x and the output text will be on the char buffer[32].
Code I'm using:
char buffer[32];
int x = libssh2_channel_read(channel, buffer, sizeof(buffer));
char * output = (char *)malloc(sizeof(char)*x);
memcpy(output, buffer, x-2); // x - 2 because of "\r\n"
libssh2_channel_free(channel);
channel = NULL;
cout << output << endl;
Example of output:
0══²²²²
I only want the 0
Welcome to C++.
You are copying the values you care about but not the terminating '\0' character. Assuming x is valid (that is: x > 3 and x <= sizeof(buffer)) you can say:
output[x - 2] = '\0';
after the call to memcpy() and you should get what you expect.
However: when you're dealing with communications and buffers like this you need to be careful and check everything.
I think you shouldn't be using raw arrays and memcpy and the like here.
You are probably better off with the containers from the C++ standard library:
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/string/basic_string
Directly write into char* buffer of std::string
Example:
std::vector<char> buffer(32);
int x = libssh2_channel_read(channel, &buffer[0], buffer.size());
// probably x will be smaller or equal the current size of the buffer
buffer.resize(x);
// if it's a string, why not have it as a std::string
std::string data(buffer.begin(), buffer.end());
std::cout << data << '\n';
Use std::string:
char buffer[32];
int x = libssh2_channel_read(channel, buffer, sizeof(buffer));
std::string output{ buffer, buffer + x - 2 };
libssh2_channel_free(channel);
channel = NULL;
cout << output << endl;
I'm facing some troubles with code for my school. The problem is that I have a char pointer named "contenido" like this:
class Archivo {
public:
Archivo(const char *filename, int banderas);
Archivo(const char *filename, int banderas, mode_t modo);
~Archivo();
size_t lee(size_t nbytes);
size_t escribe(const void *buffer, size_t nbytes);
char *get_contenido();
void cerrar();
protected:
string nombreArchivo;
int fd;
//Problematic char pointer
char *contenido;
};
The code is supposed to be a class implementation of the c functions read(), write() and open(), the specific method where i need to set a new size for my char pointer is size_t lee(size_t nbytes); that i implemented like this:
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, sizeof(contenido));
return nbytes;
}
In this method, I should receive a new size for "contenido" that in this case, it works as my buffer for the read() function but unfortunately, it doesn't matter which value I use it always returns "8" in the call of sizeof(contenido). I have tried using malloc() in the constructor, using malloc() and then realloc() and as you may see using new char[size_t] but in every single case I receive the same result of "8". I researched about this and in most cases the suggestion was to use std::vector but in this specific case it's necessary to use char * due to the request of my professor. I hope you can help me and thanks in advance.
sizeof(contenido) evaluates to the size of a pointer, which is 8 on your platform.
To restore the contents of a string, you need to use the length of the string as argument to read.
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, nbytes);
return nbytes;
}
If contenido is supposed to be a null terminated string, you probably need to allocate one more byte for it and make sure to add the terminating null character.
size_t Archivo::lee(size_t nbytes) {
contenido = new char[nbytes+1];
cout << "contenido: " << sizeof(contenido) << endl;
nbytes = read(fd, contenido, nbytpes);
contenido[nbytes] = '\0';
return nbytes;
}
You are calling the sizeof() operator on a pointer, therefore you get the size of the pointer and not the size of content it's pointing to. Pointer in memory is usually like another regular variable (int for example) except it contains an address instead of an actual value. You always get the number 8 probably because your machine is 64 bit, so a pointer should be able to hold any address in the 64 bit space. (8 bytes = 64 bit)
If you want to get the size in bytes of the content (the memory you allocated), you should take the size of char (the type the content is made of) using sizeof() and then multiply that by the number of chars allocated, like so:
sizeof(char)*nbytes
I am trying to read a binary file into memory, and then use it like so:
struct myStruct {
std::string mystring; // is 40 bytes long
uint myint1; // is 4 bytes long
};
typedef unsigned char byte;
byte *filedata = ReadFile(filename); // reads file into memory, closes the file
myStruct aStruct;
aStruct.mystring = filedata.????
I need a way of accessing the binary file with an offset, and getting a certain length at that offset.
This is easy if I store the binary file data in a std::string, but i figured that using that to store binary data is not as good way of doing things. (filedata.substr(offset, len))
Reasonably extensive (IMO) searching hasn't turned anything relevant up, any ideas? I am willing to change storage type (e.g. to std::vector) if you think it is necessary.
If you're not going to use a serialization library, then I suggesting adding serialization support to each class:
struct My_Struct
{
std::string my_string;
unsigned int my_int;
void Load_From_Buffer(unsigned char const *& p_buffer)
{
my_string = std::string(p_buffer);
p_buffer += my_string.length() + 1; // +1 to account for the terminating nul character.
my_int = *((unsigned int *) p_buffer);
p_buffer += sizeof(my_int);
}
};
unsigned char * const buffer = ReadFile(filename);
unsigned char * p_buffer = buffer;
My_Struct my_variable;
my_variable.Load_From_Buffer(p_buffer);
Some other useful interface methods:
unsigned int Size_On_Stream(void) const; // Returns the size the object would occupy in the stream.
void Store_To_Buffer(unsigned char *& p_buffer); // Stores object to buffer, increments pointer.
With templates you can extend the serialization functionality:
void Load_From_Buffer(std::string& s, unsigned char *& p_buffer)
{
s = std::string((char *)p_buffer);
p_buffer += s.length() + 1;
}
void template<classtype T> Load_From_Buffer(T& object, unsigned char *& p_buffer)
{
object.Load_From_Buffer(p_buffer);
}
Edit 1: Reason not to write structure directly
In C and C++, the size of a structure may not be equal to the sum of the size of its members.
Compilers are allowed to insert padding, or unused space, between members so that the members are aligned on an address.
For example, a 32-bit processor likes to fetch things on 4 byte boundaries. Having one char in a structure followed by an int would make the int on relative address 1, which is not a multiple of 4. The compiler would pad the structure so that the int lines up on relative address 4.
Structures may contain pointers or items that contain pointers.
For example, the std::string type may have a size of 40, although the string may contain 3 characters or 300. It has a pointer to the actual data.
Endianess.
With multibyte integers some processors like the Most Significant Byte (MSB), a.k.a. Big Endian, first (the way humans read numbers) or the Least Significant Byte first, a.k.a. Little Endian. The Little Endian format takes less circuitry to read than the Big Endian.
Edit 2: Variant records
When outputting things like arrays and containers, you must decide whether you want to output the full container (include unused slots) or output only the items in the container. Outputting only the items in the container would use a variant record technique.
Two techniques for outputting variant records: quantity followed by items or items followed by a sentinel. The latter is how C-style strings are written, with the sentinel being a nul character.
The other technique is to output the quantity of items, followed by the items. So if I had 6 numbers, 0, 1, 2, 3, 4, 5, the output would be:
6 // The number of items
0
1
2
3
4
5
In the above Load_From_Buffer method, I would create a temporary to hold the quantity, write that out, then follow with each item from the container.
You could overload the std::ostream output operator and std::istream input operator for your structure, something like this:
struct Record {
std::string name;
int value;
};
std::istream& operator>>(std::istream& in, Record& record) {
char name[40] = { 0 };
int32_t value(0);
in.read(name, 40);
in.read(reinterpret_cast<char*>(&value), 4);
record.name.assign(name, 40);
record.value = value;
return in;
}
std::ostream& operator<<(std::ostream& out, const Record& record) {
std::string name(record.name);
name.resize(40, '\0');
out.write(name.c_str(), 40);
out.write(reinterpret_cast<const char*>(&record.value), 4);
return out;
}
int main(int argc, char **argv) {
const char* filename("records");
Record r[] = {{"zero", 0 }, {"one", 1 }, {"two", 2}};
int n(sizeof(r)/sizeof(r[0]));
std::ofstream out(filename, std::ios::binary);
for (int i = 0; i < n; ++i) {
out << r[i];
}
out.close();
std::ifstream in(filename, std::ios::binary);
std::vector<Record> rIn;
Record record;
while (in >> record) {
rIn.push_back(record);
}
for (std::vector<Record>::iterator i = rIn.begin(); i != rIn.end(); ++i){
std::cout << "name: " << i->name << ", value: " << i->value
<< std::endl;
}
return 0;
}