tags:

views:

294

answers:

8

I want to simply pass a char as an argument to a function which should then be modified by the function. Unfortuantely, when doing it like below the printouts of the buffers are NOT equal. I do not understand as I pass a pointer to the char array. Anyone sees the obvious thing that is missing?

unsigned char* buffer;
doSomething(buffer)
printout(buffer);

where doSomething() is defined as:

doSomething(unsigned char *buffer)
{
    char* receiveddata;
    Socket.recv(receiveddata);
    buffer = ( unsigned char* ) receiveddata;
    printout(buffer);
}
A: 

I guess you need to allocate some memory on receiveddata, not just the pointer.

Looks like Socket.recv(receiveddata) should copy to that pointer the receiveddata, but the pointer points to invalid memory. try:

receiveddata = malloc(10000);

Before Socket.recv(receiveddata)

Arkaitz Jimenez
+1  A: 

I don't know what libraries you used for sockets. But I presume that first you have to allocate the buffer, to receive data. Just declaring receiveddata, without allocation (not even initialization) will lead to undefined behavior.

Just guessing.

Cătălin Pitiș
+1  A: 

try this:

doSomething(unsigned char *buffer)
{       
   Socket.recv((char *)buffer);
   printout(buffer);
}

Edit: Yes, first allocate some memory for buffer before calling doSomething.

Edit 2: If you want to allocate memory inside doSomething, then:

doSomething(unsigned char **buffer)
{
   *buffer = malloc( MAX_LENGTH_SOCKET_RECV_MAY_RETURN );
   Socket.recv((char *)(*buffer));
   printout(*buffer);
}

and call like this:

doSomething( &buffer );
palindrom
+1  A: 

In C/C++ you can not assign a char* to another one to copy memory. You will have to do a strncpy on the receiveddata into the buffer.

Daniel A. White
+1  A: 

The argument is passed by value -- 'buffer' in the caller still has the same value after the call that it had before. The changes to the parameter of the same name in the function do not affect it.

Steve Gilham
A: 

You need to supply a valid buffer into which recv() will store data.

Try this:

unsigned char buffer[512]

doSomething(buffer);

...

void doSomething(unsigned char* buffer)
{
    Socket.recv(buffer);
    printout(buffer)
}
Alan
Smelly code. Where is `recv` specified? How do you know it won't write more than 512 bytes? Or, since it doesn't even take the buffer size, even allocate the buffer itself?
sbi
+4  A: 

You have two problems here:

  1. The pointer receiveddata is uninitialized and is thus pointing to some random location in memory. This will cause you to trash data somewhere.

  2. The change that you make to the buffer pointer is not passed on to the outside. If you want to do this, you have to use a double pointer.

Here's a solution to both of these problems:

void doSomething(unsigned char **buffer)
{       
    unsigned char* receiveddata;

    // Allocate memory
    // Note: You need to know the maximum length of data that you will
    // ever receive here.
    receiveddata=new unsigned char[MAXIMUM_NUMBER_OF_CHARS_YOU_WILL_RECEIVE];

    Socket.recv(receiveddata);
    *buffer = receiveddata;
    printout(buffer);
}

Note that this code is vulnerable to a buffer overflow attack in case someone can send it more data than you expect. What sockets library are you using? Does it have a mechanism that can protect you from writing more data to the buffer than it can take (for example, an additional argument to recv specifying the length of the buffer)?

You would call this as follows:

unsigned char* buffer;    
doSomething(&buffer);
// Process the data in buffer, then free it when you're done:
delete [] buffer;

However, as others have pointed out, it's cumbersome to have to manage memory allocation and deletion yourself. Take a look at the standard library and the string and collection classes contained in it -- those can make life easier and safer by doing the memory management for you.

Edited as noted in the comments.

Martin B
Urgh. Now that function passes out memory it allocates for others to delete. And what's the point in using `malloc` instead of `new`? The problaem was tagged "C++", after all. What do you think will happen if others try to `delete` that memory? And how do you know 256 bytes is enough? (What's that `Socket.recv()` thingie anyway?)
sbi
All of those are good points... Guess I was in a C mindeset because of all the pointers, but you're right of course, this should use new/delete instead of malloc/free (fixed). Passing out memory is not a pretty idiom, but it seemed to be what Floh wanted to do, which is why I stayed with it. 256 bytes is of course not guaranteed to be enough -- code changed to emphasize this.
Martin B
A: 

Alternatively:

#define MAX_RECV_OUTPUT_LENGTH 1024 // See comment below at recv() call.
char *buffer = new char[MAX_RECV_OUTPUT_LENGTH];
doSomething(buffer);
printout(buffer);
delete[] buffer;

void doSomething(char *buffer)
{       
   Socket.recv(buffer); // Ideally you would know how much memory you need (exactly or MAX, as specified by API).
}

So:

  • You need to allocate yourself, be it using new/delete or malloc()/free() (or as became obvious, through a container).
  • Assigning one pointer to another just changes the address pointed to, it does not copy data.
  • If it's a string you'r dealing with, do you need the unsigned? Just checking..
  • And very much like someone else just put: we're all assuming recv() eats a pointer to write to, but that might be different? We need to know.
nj
How do you know that `recv` function doesn't allocate a buffer. And if it doesn't, how do you know it only ever write 256 bytes? And what if `printout` might throw? I'm sorry to say, but I consider this badly smelling code.
sbi
The comment suggests that this is just an example of how to simplify what's being done. It wasnt meant to be correct in that respect. Furthermore, check the last bullet point.
nj
@sbi: if recv() is to alllocate buffer itself then its argument must be a double pointer.
palindrom
@palindrom: Unless it takes the pointer per reference. Yes, I know it's unlikely, but given the original code...
sbi
@Palindrom The function could take a reference to a pointer, which would then work with an ordinary char *.
anon
And how likely is that? Exactly..
nj