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;
Related
I am trying to read a string from a binary file but cant seem to get it to work. I am a pretty new to c++. Can anybody help please? Thanks.
string Name = "Shaun";
unsigned short int StringLength = 0;
int main()
{
StringLength = Name.size();
ofstream oFile("File.txt", ios::binary|ios::out);
oFile.write((char*)&StringLength, sizeof(unsigned short int));
oFile.write(Name.c_str(), StringLength);
oFile.close();
StringLength = 0;
Name = "NoName";
ifstream iFile("File.txt", ios::binary|ios::in);
if(!iFile.is_open())
cout << "Failed" << endl;
else
{
iFile.read((char *)&StringLength, sizeof(unsigned short int));
iFile.read((char *)&Name, StringLength);
}
cout << StringLength << " " << Name << endl;
system("Pause>NUL");
return 0;
}
This is the problematic line.
iFile.read((char *)&Name, StringLength);
You are reading the char* part of a std::string directly into the memory of Name.
You need to save both the size of the string as well as the string so that when you read the data, you would know how much memory you need to read the data.
Instead of
oFile.write(Name.c_str(), StringLength);
You would need:
size_t len = Name.size();
oFile.write(&len, sizeof(size_t));
oFile.write(Name.c_str(), len);
On the way back, you would need:
iFile.read(&len, sizeof(size_t));
char* temp = new char[len+1];
iFile.read(temp, len);
temp[len] = '\0';
Name = temp;
delete [] temp;
you need to create a buffer of char type.
char *buffer = new char[size];
Then use your buffer as the parameter to read function
iFile.read(buffer, size);
Instead of this
iFile.read((char *)&Name, StringLength);
Try this:
Name.resize(StringLength);
iFile.read((char *)&Name[0], StringLength);
Your original line overwrites the string object data from the beginning, which may contain the string length and capacity, for instance, instead of the character data. Also you don't resize the string appropriately to be able to contain the data.
Conceptually, you need to understand the data stream which you are reading. Not everything use ASCII which uses a byte size of 8 bits. I also notice you did not set bit size read which can be as little as one bit to as large as {R, B, G, A} color set. Using your basic 2 dimensional reiteration structured code.
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;
}
I am trying to take the sensor data from Arduino & Raspberry Pi using RS232 serial communication. I have searched for this small thing and found something related on this below link but was unable get the full idea.
The os (kernel) has an internal buffer of 4096 bytes. If this buffer is full and a new character arrives on the serial port, the oldest character in the buffer will be overwritten and thus will be lost. After a successful call to RS232_OpenComport(), the os will start to buffer incoming characters.
The values are properly coming from Arduino to Raspberry Pi (output attached below) and it is storing in a pointer to unsigned char[] which is defined as unsigned char *buf[4096].
int main()
{
int i, n,
cport_nr=0, /* /dev/ttyS0 (COM1 on windows) */
bdrate=9600; /* 9600 baud */
unsigned char buf[4096];
char mode[]={'8','N','1',0};
while(1)
{
n = RS232_PollComport(cport_nr, buf, 4095);
if(n > 0)
{
buf[n] = 0;
for(i=0; i < n; i++)
{
if(buf[i] < 32) /* replace unreadable control-codes by dots */
{
buf[i] = '.';
}
}
printf("received %i bytes: %s\n", n, (char *)buf);
}
}
Now I want to store these values in another float/double variable so that I can perform further operations on it. How to store a value suppose 0.01 to a float/double which is later used to create stuff.
From the output in the screenshot it looks like you are sending the string representation of the numbers rather than the actual numbers. You just need to detect those "unreadable control-codes" that you are just replacing with a . as they will probably tell you when a number ends and another begins. Just make QSerialPort * serial; a proper class member.
Also, check for errors on opening the port: serial->open(QIODevice::ReadWrite); Then, insert some qDebug() in serialreceived() to see if the slot is called at all and if the canReadLine() works. you should use QByteArray to read your data. If there's any char in the response, that is not String conform, the resulting QString will be prematurely terminated, use readLine() instead readAll() like this:
QByteArray data = serial -> readLine();
qDebug() < data.toHex(' '); // prints the hex representation of your char array
QString str(data);
qDebug() << str;
First, it will be better if you use some other ASCII character (e.g. space) to separate the numbers, because . dot is a part of floating point number. Then, you can construct std::string object from your raw unsigned char array, split it in a multiple strings and convert each string to float.
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
int main() {
// imagine that this buff is already after read and preprocessing
unsigned char buff[1024] = "13.60 13.60 -11.12 -0.3 and let's say that the rest is garbage";
int n = 28; // let's say that you received 28 bytes
std::string strBuff(reinterpret_cast<char*>(buff), n); // construct a string from buff using just first 28 bytes
std::vector<std::string> numbers;
boost::split(numbers, strBuff, boost::is_any_of(" "), boost::token_compress_on);
for (const auto& n : numbers) {
try {
std::cout << std::stof(n) << std::endl;
} catch (const std::exception& e) {
std::cout << n << " is not convertible to float: " << e.what() << std::endl;
}
}
return 0;
}
I took the string splitting method from this answer but you can use anything that works for you.
I used reinterpret_cast because std::string accepts char instead of unsigned char as a CTor arg.
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 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;
}