Function to copy data in a reference char array - c++

How can I write in C++ a function who put the data in a char array, I don't how to explain well but I'll write an example
void functionCopyData(char& buf){
// get data from a char variable
char data1 = "textdata1";
char data2 = "textdata2"
// copy data
copy(&buf,data1);
copy(&buf,data2);
}
char variable[20];
functionCopyData(&variable);
printf(variable);
// return: textdata1textdata2
So summarizing, I need to copy the data from two variables and put in a char array. Sorry if I was not clear enough.
Why this way?
because I need to get the data from and a variable and send it in a function request a reference data sendFunction(&data,sizeVar);
how can I do that?

How can I write in C++ a function who put the data in a char array
Change the argument type.
void functionCopyData(char& buf){
will be good if you want to update just one character, not an array of characters. To update an array of characters, use:
void functionCopyData(char buf[]){
or
void functionCopyData(char* buf){
That could easily lead to problems if buf does not have enough memory to store the data. To make function more robust, pass a number that indicates the capacity of buf.
void functionCopyData(char buf[], size_t capacity){
Fix the definitions of data1 and data2.
char data1 = "textdata1";
char data2 = "textdata2"
are not syntactically valid. Change them to:
char data1[] = "textdata1";
char data2[] = "textdata2";
or
char const* data1 = "textdata1";
char const* data2 = "textdata2";
Make sure that buf can hold data1 and data2.
// You need the additional 1 for the terminating null
// character.
size_t capacityNeeded = strlen(data1) + strlen(data2) + 1;
if ( capacityNeeded > capacity )
{
// Deal with the problem.
}
else
{
// Now copy the contents of data1 and data2 to buf
}
Copy the contents data1 and data2 to buf using standard library functions.
strcpy(buf, data1);
strcat(buf, data2);
Fix the call to the function.
functionCopyData(&variable);
is not the right syntax to use to call the function, given the function declaration. Use:
functionCopyData(variable, 20);

An easy solution is to write a function to copy one array, and then call it twice with different pointers pointing to different positions in the result array.
For example, if you have char data[20] to hold the result, and want to copy two arrays char a[10] and char b[10], then write a function
void copy(char* destination, char* source, int length)
That copies length bytes from source to destination, then call it with
copy(data, a, 10);
copy(data+10, b, 10);

The functions strcpy and strlen can help you:
#include <string.h>
void functionCopyData(char buf[]){
char data1[] = "textdata1";
char data2[] = "textdata2";
strcpy(buf, data1);
strcpy(buf+strlen(buf), data2);
}
...
functionCopyData(variable);
...

void functionCopyData(char* buf){
// get data from a char variable
char* data1 = "textdata1";
char* data2 = "textdata2"
// copy data
copy(buf,data1);
copy(buf,data2);
}
char variable[20];
functionCopyData(variable);
printf(variable);
I think it's more clear use pointer but not reference.

Related

Concatenation of chars

I need to concatenate to chars and send it as argument to function, but strcat move concatenated chars to first char. I need a method that return concatenated char. Or if I can do it in different way how can I do it?
void abca(char *a)
{
Serial.println(a);
}
void setup()
{
Serial.begin(9600);
char *bb = "1";
char *aa = "2";
abca(strcat(aa, bb));
}
Edit: I'm creating program for Arduino, and I can't use strings. Strings use a lot of memory. Unfortunately Arduino have only 2kB
There are a few problems with your code. First of all, you are using non-const pointers to const arrays:
char *bb = "1"; // "1" is a char constant array
char *aa = "2"; // so it needs a pointer to constant memory
When you fix that your function calls will fail because they need non-const arrays.
One fix is to create a non-const array to receive your concatenated string:
// should be const because it is not modified
void abca(char const* a)
{
Serial.println(a);
}
void setup()
{
Serial.begin(9600);
// char const array decays to pointer to const char
char const* bb = "1";
char const* aa = "2";
// can't concatenate into constant memory
// abca(strcat(aa, bb));
// So make some writable memory and concat to that
char buffer[32]; // long eough for the combined text
strcpy(buffer, bb);
strcat(buffer, aa);
abca(buffer);
}
If you don't know how big the resulting string is you may need to allocate buffer dynamically to make sure it is big enough.
If you are able to change the function to
void abca(const char *a)
Then you could use a std::string at the calling site and the c_str() method:
int main()
{
std::string a = "aa";
std::string b = "bb";
abca((a + b).c_str());
}
Note that the overloaded + operator is used for concatenation. Better still, if you can change the function to
void abca(const std::string& a)
(note that the body of the function is unchanged), you can write
abca(a + b);
at the calling site. All standard C++, and no memory leaks or undefined behaviour either! std::string might get some bad press but it does epitomise the power of C++.

How can I declare a structure of an unknow size?

I have this structure :
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
unsigned dataLength;
unsigned char data[0];
};
And to declare it I do :
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
packet->data = "kappa";
packet->dataLength = 5;
But when I compile I have this error :
error: incompatible types in assignment of ‘const char [6]’ to ‘unsigned char [0]’
packet->data = "kappa";
^
Have you an idea how I can do that ?
And I need to send this structure through a socket, to get the object back in my server, so I can use only C types.
If this was a C program, the error you get is because you try to assign to an array, which is not possible. You can only copy to an array:
memcpy(packet->data, "kappa", 5);
Also note that if you want the data to be a C string, you need to allocate an extra character for the string terminator '\0'. Then you can use strcpy instead of memcpy above. Or strncpy to copy at most a specific amount of characters, but then you might need to manually terminate the string.
However, this should not work in C++ at all, unless your compiler have it as an extension.
You can't assign a literal string that way. You'll need to allocate additional memory for the string, then copy to the data pointer.
struct A {
size_t datasize;
char data[0]; // flexible member must appear last.
};
A* create_A(const char* str)
{
size_t datasize = strlen(str) + 1; // null terminated (?)
A* p = reinterpret_cast<A*>(new char[sizeof(A) + datasize]);
memcpy(p->data, str, datasize);
p->datasize = datasize;
return p;
}
A* p = create_A("data string");
This solution is only applicable in environments supporting zero-length or flexible arrays. In fact, a better solution may be to write the sockets code in C and export that interface for use in C++.
If you are willing/allowed to change the unsigned char to a regular char, you can use strcpy:
#include <iostream>
#include <stdio.h>
#include <string.h>
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
unsigned dataLength;
char data[0]; // I changed this to char in order to use strcpy
};
int main(){
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
// Copy the string. Add NULL character at the end of
// the string to indicate its end
strcpy(packet->data, "kappa\0");
packet->dataLength = 5;
// Verify that the string is copied properly
for (int i=0;i<packet->dataLength;++i){
std::cout<<packet->data[i];
}
std::cout<<std::endl;
return 0;
}
Note that this will only work if data is at the end of the struct, otherwise there is no contiguous memory to allocate data. If I swap the order of the elements to:
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
char data[0]; // I changed this to char in order to use strcpy
unsigned dataLength;
};
the output of the code above (instead of "kappa"), would be "a".
A more reliable way if you are determined to use C-arrays would be to assume a maximum number of elements and preallocate the array, i.e.:
#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAX_NUMBER_OF_CHARACTERS 5 // Many ways to do this, I defined the macro for the purposes of this example
struct __attribute__((packed)) BabelPacket
{
unsigned senderId;
// I changed this to char in order to use strcpy. Allocate the
// max number + 1 element for the termination string
char data[MAX_NUMBER_OF_CHARACTERS+1];
unsigned dataLength;
};
int main(){
BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
packet->senderId = 1;
packet->dataLength = 5;
if (dataLength>MAX_NUMBER_OF_CHARACTERS){
std::cout<<"String greater than the maximum number of characters"<<std::endl;
}
// Copy the string. Add NULL character at the end of
// the string to indicate its end
strcpy(packet->data, "kappa\0");
// Verify that the string is copied properly
for (int i=0;i<packet->dataLength;++i){
std::cout<<packet->data[i];
}
std::cout<<std::endl;
return 0;
}
This code produces the correct output, and protects you against violations. As you can see, it can get messy pretty quickly, which is why I would recommend to use std::vector for this. The dataLength may then be retrieved automatically as the size of the vector, and you are always protected against overflows.

Simple serialization example in c++

I have the following struct:
typedef struct{
int test;
std::string name;
} test_struct;
Then, I have the following code in the main function:
int main(int argc, char *argv[]){
test_struct tstruct;
tstruct.test = 1;
tstruct.name = "asdfasdf";
char *testout;
int len;
testout = new char[sizeof(test_struct)];
memcpy(testout, &tstruct, sizeof(test_struct) );
std::cout<< testout;
}
However, nothing gets printed. What's wrong?
sizeof(std::string) yeilds same value always. It will not give you the runtime length of the string. To serialize using memcpy, either change the struct to contain char arrray such as char buffer[20] or compute the size of the required serialized buffer by defining a method on the struct which gives the runtime length of the bytes.
If you want to use members like std::string, you need to go through each member of the struct and serialize.
memcpy(testout, (void *)&tstruct.test, sizeof(int) );
memcpy(testout+sizeof(int), tstruct.name.c_str(),tstruct.name.length() );
memcpy against the entire struct will not work in such scenarios.
Try NULL-terminating the string and also emitting a newline:
testout = new char[sizeof(test_struct) + 1];
memcpy(testout, &tstruct, sizeof(test_struct));
testout[sizeof(test_struct)] = '\0';
std::cout<< testout << std::endl;
However, as user3543576 points out, the serialization you get from this process won't be too useful, as it will contain a memory address of a character buffer, and not the actual string itself.

c++: write a char at a given char* causes segfault

I want to copy a char to an address where a given char* points to.
it's in a function which is called by main:
char data = " ";
myfunction(data, somethingelse);
...
inside the function i have something like
void myfunction(char* data, short somethingelse) {
...
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++;
...
}
the segfault also comes when i to the copy using strncpy:
strncpy(data, byte, 1);
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array. i've tested that multiple times.
thanks in advance.
String literals are readonly. If you want a modifyable string, you must use an array, e.g.:
char data[10];
Or:
char *data = new char[10];
To elaborate a bit more: the type of a string literal is actually const char*. Assigning a string literal to a non-const char* is therefore technically invalid, but most compilers allow it anyway for legacy reasons. Many modern compilers will at least issue a warning when you try to do that.
data is assigned a string literal. String literals are ready only, and writing to them will cause segfaults.
Try this:
char data[10]; // or whatever size you want.
instead.
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array.
You didn't allocate anything. char *data = " "; shouldn't even compile in C++. You are assigning a constant string to a non-constant.
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++; // << How many times?
No problem
#include <stdio.h>
int main(int argc, char **argv)
{
char *data = "Yello"; // or char data[] = "Yello";
*data = 'H';
puts(data); // Hello
}

How do i push different datatypes into a void buffer?

I have the following data i need to add in the void buffer:
MyStruct somedata; // some struct containing ints or floats etc.
string somestring;
How do i do this?
This is my buffer allocation:
void *buffer = (void *)malloc(datasize);
How do i add first the somedata into the buffer (, which takes lets say 20 bytes), and then after 20 bytes comes the string which is variable size. I was thinking to read the structs byte by byte and add to buffer, but that feels stupid, there must be some easier way...?
Edit: i want this to equal to: fwrite( struct1 ); fwrite( struct2 ); which are called sequentially, but instead of writing to file, i want to write to a void buffer.
Edit 2: Made it working, heres the code:
char *data = (char *)malloc(datasize);
unsigned int bufferoffset = 0;
for(...){
MyStruct somedata; // some POD struct containing ints or floats etc.
string somestring;
... stuff ...
// add to buffer:
memcpy(data+bufferoffset, &somedata, sizeof(MyStruct));
bufferoffset += sizeof(MyStruct);
memcpy(data+bufferoffset, somestring.c_str(), str_len);
bufferoffset += str_len;
}
Anything to fix?
memcpy(buffer, &somedata, sizeof(MyStruct));
strcpy(buffer + sizeof(MyStruct), somestring.c_str());
Which will copy the string as a c string.
In general you should avoid doing this for classes which have custom copy-constructors etc.
But if you have to and you know what you're doing, use memcpy
In C, I'd do a bit like this:
MyStruct somedata;
string somestring;
void *buffer = (void *)malloc(datasize);
memmove(buffer, &somedata, 20);
strcpy(buffer + 20, somestring);
But there's LOTS of bad smell in the first 3 lines of this C code:
MyStruct is either a typedef (why? I hate typedefs) or it should be struct MyStruct
string is either a typedef (why? I hate typedefs) or it should be struct string; and identifiers starting with "str" are reserved and should not be used by programmers
Casting the return value of malloc is redundant and may hide errors
Edit after noticing (thanks Newbie) operations on void *
char *buffer = malloc(datasize);
In C, void* and any other pointer type are assignment compatible in both directions, so there is no need to cast char * to void * when passing it to memmove() and friends.
memmove(buffer, &somedata, 20);