Sign in to follow this  
Bru

char + char = love!

Recommended Posts

hey there. i am programming in c++ and i've come to a point that i want to send a packet from my server to the client. but not just a packet, it has to have an idea aswell as some data since i want the client to know what data i sent(like coordinates or any other variables). so for this i guess i have to join two char arrays(strings?) to be able to connect an id and the information(like 01555 where 01 is the id of the packet,and 555 is the data). but well, c++ doesnt love char + char. and so i went on my long journy to google to find the lost html page with the tutorial on how to join two chars! but well that didnt go well. so i just thought about going here and ask, how can i join two char arrays :)?

Share this post


Link to post
Share on other sites
It doesn't look like you want to join two chars. Rather, you want to join two char arrays. To do this in C++ you need to know the lengths of both char arrays. Say that your char arrays are ca1 and ca2 respectively. Let the length of ca1 be la1 and the length of ca2 be la2. Then you can simply use a memcpy.



char* ca = new char[la1+la2];
memcpy( ca, ca1, la1 );
memcpy( &ca[la1], ca2, la2 );

// do whatever you need to send your packet here

delete [] ca;




Note that here you probably wouldn't want to dynamically allocate the array ca all the time. It would be better if, at compile time, you knew the size of the packet, or at least had an upper bound on the size of the packet. Then you could either allocate ca statically, or you could allocate it dynamically once at the beginning of the program and then just use it repeatedly every time you needed to send a packet. Anyway, those are all details. The real answer is that to join two char arrays, you'll likely want to use memcpy.

Cheers,
Rob

Share this post


Link to post
Share on other sites
You can use strcat to concat two strings. I'll let you look it up.

You might want to write a class that deals with all this sorta stuff for you, similar to Raknet's Bitstream, or, well, the iostream stuff [smile]

Share this post


Link to post
Share on other sites
@Richy2k : He might not want to use strcat. The two separate char*'s he wants to concatenate might not have null terminators. In fact, from the example he provided, that doesn't seem to be the case. Try the following code:


#include <cstdio>
#include <cstring>
#include <iostream>

using std::cout;
using std::endl;


int main(){

char* ca1 = new char[5];
char* ca2 = new char[8];

ca1[0] = 01;
ca2[1] = 5;
ca2[2] = 5;
ca2[3] = 5;

char* ca = new char[5+8];

strcat( ca, ca1 );
strcat( ca, ca2 );

puts( ca );

cout << strlen( ca ) << endl;
return 0;
}





That likely won't be what you want or what Bru expects.

@Bru The strcat function concatenates two null terminated strings. The memcpy function is more generic. Basically it looks like this:


memcpy( void* dest, void* src, size_t len );





It's really rather straight forward. It copies "len" bytes from "src" into "dest". The problem with strcat, as I mentioned to Richy2k, is that it expects the char arrays your concatenating to be null terminated. Since you'll be sending things over the network and you might want to use chars as bytes rather than parts of a string, this may not be true for you. Take a look at the example program I posted if you want to see what I mean. Let me know if you have any other questions about memcpy.

--Rob

Share this post


Link to post
Share on other sites
There are multiple ways listed above, but one you should seriously consider is using std::stringstream. The STL is really very powerful.

Here's a quick snippet to show you how easy it is to combine two char arrays into one stringstream.


#include <iostream>
#include <sstream>

using namespace std;

int main()
{
// Create a couple of buffers.
char* buffer1 = new char[11];
buffer1 = "firstBuffer";

char* buffer2 = new char[12];
buffer2 = "secondBuffer";


// Create a stringstream and feed in our char buffers using the input operator (<<)
stringstream stream;
stream << buffer1 << buffer2;


// Print out the results using the .str() function of stringstream.
cout << stream.str() << '\n';

return 0;
}



Hope you figure out a way that works!

Share this post


Link to post
Share on other sites
[quote]Original post by ArcPrime

// Create a couple of buffers.
char* buffer1 = new char[11];
buffer1 = "firstBuffer";

char* buffer2 = new char[12];
buffer2 = "secondBuffer";


[/quote]

What's that?

You know you are leaking memory and for no reason at all?

Why not just write:

std::string buffer1 = "firstBuffer";
std::string buffer2 = "secondBuffer";


Or for this particular case:

const char *buffer1 = "firstBuffer";
const char *buffer2 = "secondBuffer";

Share this post


Link to post
Share on other sites
Quote:

What's that?

You know you are leaking memory and for no reason at all?

Why not just write:


std::string buffer1 = "firstBuffer";
std::string buffer2 = "secondBuffer";



Or for this particular case:


const char *buffer1 = "firstBuffer";
const char *buffer2 = "secondBuffer";


Yes, you are correct. I wasn't so concerned about the tiny memory leak; the intention was simply to display the use of stringstream.

No offense intended, and thanks for giving everyone else the heads-up. :)

FYI, I personally prefer the first suggestion you made (using std::string).

Share this post


Link to post
Share on other sites
Quote:
Original post by ArcPrime
I wasn't so concerned about the tiny memory leak; the intention was simply to display the use of stringstream.


I think the point was that the following doesn't come close to what you seem to think it's doing:

char* pData = new char[10];
pData = "Hello, world.";


The problem here isn't really that you're not calling delete - although that would clearly fix the problem - but that you've misunderstood how the assignment in the second line works.

After the first line, pData (assuming new didn't fail and throw an exception) is a pointer to some newly-allocated memory on the free store. After the second line, pData is a pointer to the string literal "Hello, world." - you've completely lost any reference to the allocated memory and can no longer recover it.

pData = "Hello, world." doesn't copy the string "Hello, world." into the memory at pData, instead it creates a string literal (which may be stored in read-only segments, and multiple occurrences of that literal in the source may well actually correspond to a single instance in memory) and points pData at it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mononofu
Why not just use std::string?

Wouldn't that be the easiest approach with the least risk?
If you ever put a null byte in a std::string, you'll probably get some very strange behaviour.

Share this post


Link to post
Share on other sites
I really don't know why people keep telling other people (especially beginners) how to solve C++ problem with C. You don't use memcpy in C++, you use, std::copy. You don't use (const) char*, you use std::string, you don't add two arrays of chars, you add two std::vectors.

So to answer your particular problem you do:

typedef std::vector<char> Buffer;

Buffer buf1, buf2;

// do stuff with them

buf1.insert(buf1.end(), buf2.begin(), buf2.end()) // insert buf2 at the end of buf1

this is the C++ solution (int its simplest form) for adding 2 char buffers. In fact buf2 can also be a simple char array for example:

char buf2[LEN];

buf1.insert(buf1.end(), buf2, buf2 + LEN);

You can also try just using adding std::string as suggested by others above. Do not use C.

Also, for building a network message buffer you need to google up for serialization / marshaling.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Quote:
Original post by Mononofu
Why not just use std::string?

Wouldn't that be the easiest approach with the least risk?
If you ever put a null byte in a std::string, you'll probably get some very strange behaviour.


If an anonymous poster had written this, I'd WTFed, but since it's from you, Evil Steve, care to enlighten us?

I haven't noticed any strange behavior and didn't come across any warning putting '\0' bytes in a std::string. I guess printing the string might result in it being cut off depending on the crt and system used, or are there any std::string implementations out there doing strnlen() internally?


To the original poster, my recommendation would be to go with the stringstream demonstrated by ArcPrime (but skip the flaws :P). Less headaches, automatic binary - ascii conversion (depending on your level of knowledge, you might after all have the value you want to write in a char, not the ascii character representing that value).

Share this post


Link to post
Share on other sites
Quote:
Original post by Cygon
I haven't noticed any strange behavior and didn't come across any warning putting '\0' bytes in a std::string. I guess printing the string might result in it being cut off depending on the crt and system used, or are there any std::string implementations out there doing strnlen() internally?

Not if they want to confirm to the standard. You are explicitly allowed to have bytes containing zero in a std::string, and all implementations that I know of handle it correctly.

It's true that if you attempt to convert the contents of such a string int, say, a C-style string or a Unicode string, you may encounter some unexpected results, but it's entirely well defined.

It has also bee the source of quite a lot of acrimony amongst committee members.

Share this post


Link to post
Share on other sites
Quote:

I think the point was that the following doesn't come close to what you seem to think it's doing:

char* pData = new char[10];
pData = "Hello, world.";



The problem here isn't really that you're not calling delete - although that would clearly fix the problem - but that you've misunderstood how the assignment in the second line works.

After the first line, pData (assuming new didn't fail and throw an exception) is a pointer to some newly-allocated memory on the free store. After the second line, pData is a pointer to the string literal "Hello, world." - you've completely lost any reference to the allocated memory and can no longer recover it.

pData = "Hello, world." doesn't copy the string "Hello, world." into the memory at pData, instead it creates a string literal (which may be stored in read-only segments, and multiple occurrences of that literal in the source may well actually correspond to a single instance in memory) and points pData at it.


I realize what it was doing, I just wrote that post in a hurry yesterday. I originally had it using std::strings (the norm for me in C++), but after seeing the mention that the OP was using char*, I adjusted my code quickly without double-checking. Silly mistake; not a misunderstanding of how allocation of memory and assignment works with regard to char pointers. I really consider the important code to be the demonstration of std::stringstream.

Thanks again for pointing out, as it really was a dumb thing to do. I hope the OP has enough stuff to work with now. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by ArcPrime
Quote:
[my reply]


Thanks again for pointing out, as it really was a dumb thing to do. I hope the OP has enough stuff to work with now. :)


Fair dues, sorry. :-) Oh well, it always bears repeating for the odd lurking newbie, I suppose!

[Edited by - TheUnbeliever on January 19, 2009 2:27:09 PM]

Share this post


Link to post
Share on other sites
Okay, everyone, back up a second. Let's make sure we understand the problem correctly.

Quote:
Original post by Bru
so for this i guess i have to join two char arrays(strings?) to be able to connect an id and the information


Tell me, OP, in your own words:

What is a char?

What is a char array?

What is a string?

What is a byte?

Have you ever heard of "ASCII"? What is it?

Quote:
(like 01555 where 01 is the id of the packet,and 555 is the data).


How many bytes are there in the packet ID that you propose? What are their values? How many bytes are in the data that you propose? What are their values?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Okay, everyone, back up a second. Let's make sure we understand the problem correctly.

Quote:
Original post by Bru
so for this i guess i have to join two char arrays(strings?) to be able to connect an id and the information


Tell me, OP, in your own words:

What is a char?

What is a char array?

What is a string?

What is a byte?

Have you ever heard of "ASCII"? What is it?

Quote:
(like 01555 where 01 is the id of the packet,and 555 is the data).


How many bytes are there in the packet ID that you propose? What are their values? How many bytes are in the data that you propose? What are their values?


char is one letter in ascii i belive.
char array is an array of chars(!?)
string is like a char array just that its not an array?
byte is a cell in the memory that is made of 8 bits, can hold any number between -127 to 127 or 0-255
ascii stands for american code something, i know all letters in the computer are saved in their ascii code.
in 01555 i belive there are 5 bytes(or now that i think about it, if its in ascii then its probably 10?).
value of each digit in 01555 in ascii? dont know.
your point is?

P.S sorry for bump.

Share this post


Link to post
Share on other sites
I think his point was for you to think about your protocol. Is is text based or does it use some other encoding for the data?

When I first replied I assumed it was not text based, so I suggested std::vector<char> as a buffer type.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
I think his point was for you to think about your protocol. Is is text based or does it use some other encoding for the data?

When I first replied I assumed it was not text based, so I suggested std::vector<char> as a buffer type.


well at the moment i dont use any enconding. i simply send raw data between the client and server. the reason for that is that i am still learning about winsock and everything and i plan to keep it to the end.

Share this post


Link to post
Share on other sites
Even if you aren't doing any fancy encoding, you still need a format for your "packets". If the server receives "01555" - does that mean packet id = 01 and packet data = 555 or does it mean packet id = 0 and packet data = 1555?

If you are using TCP then remember there are no packets at your level - only a stream. How does the server know where one "packet" ends and the next begins if it receives 01555034243507895? You will also have to handle the case where you receive an incomplete packet by storing the partial data until the rest arrives.

If you are using UDP you will need to be able to handle missing, duplicate or out-of-order packets.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Even if you aren't doing any fancy encoding, you still need a format for your "packets". If the server receives 01555 as text, does that mean packet id = 01 and packet data = 555 or does it mean packet id = 0 and packet data = 1555.

If you are using TCP, remember there are no packets at your level, only a stream. How does it know where one "packet" ends and the next begins if it receives 015550155501555? You will also have to handle the case where you receive an incomplete packet by storing the partial data until the rest arrives.


i guess i seperate them by by adding a packet size?

Share this post


Link to post
Share on other sites
Good idea. But you still need a format for the packet size [smile]

Don't worry, it can be as easy as "the first X digits are the packet size". Alternatively in your text based protocol you could use a certain character as a delimiter. However this does mean that you would need to ensure that no legitimate message could contain this delimiter (or implement escape characters).

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Good idea. But you still need a format for the packet size [smile]

Don't worry, it can be as easy as "the first X digits are the packet size". Alternatively in your text based protocol you could use a certain character as a delimiter. However this does mean that you would need to ensure that no legitimate message could contain this delimiter (or implement escape characters).


the stop character sounds lighter than using a size in the packet. if i use ';' as the stop character, i can always implant a little function to make sure ; will only be used as a stop character.

so lets say my packet formad is 2 or three digits for the id, rest for data and in the end a(an?) ;. i still have to somehow make a string out of it, to first enter the id, then add the data from a variable without overwriting the id, and then add ; without overwriting the id+data and i am still not sure how to do it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this