How to deal with char array which '\0' is inserted into? - c++

When I try to copy a struct into a char array buffer using memcpy function, '\0' is inserted into the char array. I pass the buffer pointer to a function. the content before the first '\0' is past, but the rest is lost. How can I solve this problem? I would appreciate it if you help me.
here is the code, although the the struct Mystruct and the function display() is not designed reasonably。
#include <QCoreApplication>
#include <stdio.h>
struct MyStruct
{
char c;
int order;
char ch;
MyStruct(char c = 'b', int order = 0, char ch = 'a'):order(order), ch(ch), c(c)
{};
};
void display(char* str)
{
printf("%s", str);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyStruct *mystruct = new MyStruct;
// char* test = new char[50];
char test[50];
memset(test, 0, 50);
memcpy(test, mystruct, sizeof(MyStruct));
display(test);
return a.exec();
}
I want to send struct like 'Mystruct' through socket and the function send(char*) requires a char* pointer pointing to a buffer. The '\0' is inserted into the char array when the int order is copied into the test[50].
We use QTcpSocket::write(char* ) of QT instead of APIs offered by Linux or Windows. And my teammate offer me an interface function send(char ).I need pass the buffer pointed to by the char pointer.
I simplized my question with the code showed and apologize for my confusing expression.And any good way to send the struct through socket?

C-string function works with nul-terminating string.
if you want to handle char* with nul non terminal string, you need size (or other sentinel).
MyStruct mystruct;
std::string buffer {(char*) &mystruct, sizeof (MyStruct)};
Demo
Notice that that way of serializing has lot of pitfall:
padding (you might see random value between c and order and also after ch (those 0 ARE random)).
endianess issue.
...

Related

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.

How do you unindex a struct?

How do I unindex a struct? Example:
typedef struct String_s {
int current_location;
int size;
char data[0];
} String;
char* String_getCString(String *str){
return &str->data[0];
}
//this is supposed to take the result of 'String_getCString' and reverse the process to get the String*
//i.e. String_getCString(CString_getString(str)) == str
String* CString_getString(char *str){
//???
}
int foo(char *cstr){
printf("%s\n", cstr);
fflush(0);
free(CString_getString(cstr));
}
int main(int argc, char *argv[]){
const char *hello_world = "hello world";
String *str = (String*)malloc(sizeof(String)+1000*sizeof(char));
str->size = 1000;
str->count = strlen(hello_world);
char *cstr = String_getCString(str);
strcpy(cstr, hello_world);
foo(cstr);
return 0;
}
I'm not 100% sure I understand what you want CString_getString to do, but if you want it to return the address of the overall String object when passed the address of the embedded data field, then that's straightforward, but dangerous:
#include <stddef.h>
String *CString_getString(char *str)
{
return (String *)(str - offsetof(String, data));
}
If the type of the field you wished to "unindex" were anything other than [signed/unsigned/] char, you would need to cast the input pointer to char * before the subtraction, as well as casting to the desired return type afterward.
This is dangerous because CString_getString has no way of knowing whether you've passed in a str that really is the embedded data field of a String object. If you get it wrong, the C compiler sits back and watches it blow up on you at runtime. But, arguably, this is no worse than anything else one does in C all the time, and this can be a useful technique. It is, for instance, heavily used in the guts of Linux: http://lxr.free-electrons.com/ident?i=container_of

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 to delete char * in c++?

In my application, I create a char* like this:
class sample
{
public:
char *thread;
};
sample::sample()
{
thread = new char[10];
}
sample::~sample()
{
delete []thread;
}
Am I doing the right thing in the code?
If you have [] after your new, you need [] after your delete. Your code looks correct.
List of points to be noted:
1) You need to allocate room for n characters, where n is the number of characters in the string, plus the room for the trailing null byte.
2) You then changed the thread to point to a different string. So you have to use delete[] function for the variable you are created using new[].
But why are you fooling around with new and delete for character data? Why not just use std::string, instead of 'C' functions? It's amazing why so many don't do the easiest thing:
#include <cstdio>
#include <string>
int countWords(const char *p);
int main(int argc, char *argv[])
{
std::string pString = "The Quick Brown Fox!";
int numWords1 = countWords(pString.c_str());
printf("\n\n%d words are in the string %s", numWords1, pString.c_str());
int numWords2 = countWords(argv[1]);
printf("\n%d words are in the string %s", numWords2, argv[1]);
}
No need for new[], delete[], strcpy(), etc.
Use strlen(). Better yet, don't use char* and use std::string for string data.
It's "right"*, but it's very wrong.
You should not use new[], but instead use std::vector<char> or std::string. Even if you weren't doing that, you need to respect the rule of three, or your class is broken.
*Assuming you meant new char[10]. Also, more orthodox is delete[] thread.

Best way to create a C String

I'm currently using
char *thisvar = "stringcontenthere";
to declare a string in C.
Is this the best way to declare a string in C?
And how about generating a C-String from C++-Strings?
In C it depends on how you'll use the string:
named constant: your char* str = "string"; method is ok (but should be char const*)
data to be passed to subfunction, but will not not used after the calling function returns:
char str[] = "string";
data that will be used after the function it is declared in exits: char* str = strdup("string");, and make sure it gets freed eventually.
if this doesnt cover it, try adding more detail to your answer.
As other suggested, and I you want to "do it" the C++ way, use a std::string.
If you somehow need a C-string, std::string has a method that gives a const char*.
Here is an example:
#include <iostream>
#include <string>
void dummyFunction(const char* str)
{
// Do something
}
int main(int, char**)
{
std::string str = "hello world!";
dummyFunction(str.c_str());
return EXIT_SUCCESS;
}
const char *thisvar="stringcontenthere";
It depends. For ASCII encoded strings see paragraphs C and C++. For unicode encoded strings see last paragraph.
C:
As David pointed out it depends on how to use the string in C:
as a constant then: const char s[] = "Hello World";
as a string containing variable data then: char s[] = "Hello World";
as a data array char *data; Initialization then should be customized.
Please note in C there are all Strings Null-terminated, that means the definition of e.g. char s[] = "foo"; implicitly includes a NULL character at the end s[3]='\0'.
Also please note the subtile difference between char *s and char s[] which might often behave the same but sometimes not! (see Is an array name a pointer?) for example:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[])
{
char s[] = "123456789123456789123456789";
char *t = (char*) malloc( sizeof(char) * 28 );
for( size_t i = 0; i < 28; ++i )
t[ i ] = 'j';
printf( "%lu\n", sizeof(s) );
printf( "%lu\n", sizeof(t) );
printf( "%s\n", s );
printf( "%s\n", t );
return EXIT_SUCCESS;
}
So I recommend to use char arrays whenever you use them as strings and char pointers whenever you use them as data array.
C++:
In C++ there is an own string data type: std::string. If you just need to have a C-String version of a std::string (e.g. using some C-API) just use the c_str() member:
std::string s = "Hello World";
your_c_call( s.c_str(), ... );
Unicode:
I you want to have unicode strings then you should really go with something like
char utf8String[] = u8"Hello World";
and try not to use wchar_t whenever possible. See this excellent article on that issue: http://www.nubaria.com/en/blog/?p=289. Please not that there is also unicode support for C++. But generally I am tempted to say that you should go with normal characters as far as you can. Interesting resource on that: http://www.cprogramming.com/tutorial/unicode.html
Is this C or C++? In C++ you should use std::string:
std::string aString("stringcontenthere");