24
char *recvmsg(){
    char buffer[1024];
    return buffer;
}

int main(){
    char *reply = recvmsg();
    .....
}

I get a warning:

warning C4172: returning address of local variable or temporary

Pang
  • 9,564
  • 146
  • 81
  • 122

12 Answers12

30

I would suggest std::vector<char>:

std::vector<char> recvmsg()
{
    std::vector<char> buffer(1024);
    //..
    return buffer;
}
int main()
{
    std::vector<char> reply = recvmsg();
}

And then if you ever need char* in your code, then you can use &reply[0] anytime you want. For example,

void f(const char* data, size_t size) {}

f(&reply[0], reply.size());

And you're done. That means, if you're using C API, then you can still use std::vector, as you can pass &reply[0] to the C API (as shown above), and reply to C++ API.

The bottomline is : avoid using new as much as possible. If you use new, then you've to manage it yourself, and you've to delete when you don't need it.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 3
    hehe, the OP _did_ vote for c++, so this is what it should be – sehe Oct 14 '11 at 15:43
  • 3
    The OP could also use `std::string`. – Thomas Matthews Oct 14 '11 at 16:13
  • @ThomasMatthews: If you're conceptualizing the data (of type `char*`) as *buffer* as opposed to *string*, then I believe `std::vector` conveys that better without any ambiguity, than `std::string`. – Nawaz Aug 27 '18 at 13:26
  • .. Or one could use `using buffer_t = std::vector;` (or maybe, `using buffer_t = std::string;`), then use `buffer_t`; maybe that is more appropriate. (Wish C++ had *strong* aliases!) – Nawaz Aug 27 '18 at 13:30
15

You need to dynamically allocate your char array:

char *recvmsg(){
   char* buffer = new char[1024];
   return buffer;
}

for C++ and

char *recvmsg(){
   char* buffer = malloc(1024);
   return buffer;
}

for C.

What happens is, without dynamic allocation, your variable will reside on the function's stack and will therefore be destroyed on exit. That's why you get the warning. Allocating it on the heap prevents this, but you will have to be careful and free the memory once done with it via delete[].

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
11

The warning message is correct. You're returning the address of a local array which disappears after the function returns.

You can do this using dynamic memory allocation:

char *recvmsg(){
    char *buffer = (char*)malloc(1024);
    return buffer;
}

The catch is that you need to make sure you free() the pointer later on to avoid a memory leak.

Alternatively, you can pass the buffer into the function.

void recvmsg(char *buffer,int buffer_size){
    //  write to buffer
}

void main(){
    char buffer[1024];
    recvmsg(buffer,1024);
}

This avoids the need for a memory allocation. This is actually the preferred way to do it.

Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • 2
    I would surely **not** suggest this. In C++, `std::vector` is better solution. This answer suggests C-style solution, but the question is tagged with C++. – Nawaz Oct 14 '11 at 15:46
  • Why was I under the impression that it was tagged C... But yes you're correct, vector is preferred. – Mysticial Oct 14 '11 at 15:49
7

The problem is that buffer lives on the stack and goes out of scope the moment you exit recvmsg.

You could allocate buffer on the heap:

char *recvmsg(){
  char *buffer = malloc(1024);
  return buffer;
}

Note that now the caller is responsibe for disposing of the allocated memory:

void main(){
  char *reply = recvmsg();
  free(reply);
}
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 1
    Most of the answers are valid, but only you mentioned free(). I would put a comment between two lines in main(): `/* do stuff here*/`, for readability purpose. +1 – Andrejs Cainikovs Oct 14 '11 at 15:37
2
char *recvmsg(){
    char *buffer = new char;
    cout<<"\nENTER NAME : ";
    cin>> buffer;
    return buffer;
}

int main(){
    char *reply = recvmsg();
    cout<<reply;
}
2

Just to complete the picture:

It is not necessary, to allocate memory with malloc. You can also create the buffer on the stack, but you must create it on a stack frame that lives as long as the consumer of the buffer lives. That was the error of the OP -- when the callee was finished, the buffer was deleted and the caller got a invalid pointer.

So what you can do is this:

void recvmsg(char *buffer, size_t size) {
   ... do what you want ...
}

void main(void) {
    char buffer[1024];
    recvmsg(buffer, sizeof(buffer));
}
Juergen
  • 12,378
  • 7
  • 39
  • 55
2

You have a few options...The way you're doing it now is going to cause undefined behavior as the array will go out of scope once hte function returns. So one option is to dynamically allocate the memory..

char * recmsg()
{ 
   char * array = new char[128];
   return array;
}

Just remember to clean it up with delete this way (or free if you used malloc). Second, you could use a parameter...

void recmsg(char * message, int size)
{
   if (message == 0)
      message = new char[size];
}

Again, the same thing goes for clean up here as with the previous. Also note the check for 0 to make sure you don't call new on a pointer that's been allocated already.

Last, you could use a vector..

std::vector<char> recmsg()
{
   std::vector<char> temp;

   //do stuff with vector here

   return temp;
}
MGZero
  • 5,812
  • 5
  • 29
  • 46
1

You could dynamically create the buffer, but then the caller needs to know to free it.

I think it's better to pass in a buffer (assuming recvmsg also fills it)

void recvmsg(char *buffer, size_t size){

}

void main(){
    char buffer[1024];
    recvmsg(buffer, sizeof(buffer));
}

Even if the caller decides dynamic is better, they will know that they need to free it, and the specific way to do that (free(), delete, delete[], or perhaps something special from a custom allocator)

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
0

how about passing by ref

char buf[1024];
PutStuffInBuff(&buf);
AbcAeffchen
  • 14,400
  • 15
  • 47
  • 66
karl
  • 31
  • 1
    I guess, karl means that the caller is providing a reference to buf and the callee is filling the buf. Because the caller lives longer as the callee (and so does the buf, everything is Ok, as long as the caller don't returns a ref to buf). – Juergen Feb 17 '15 at 00:40
0

The problem is that you are returning a pointer to a buffer allocated on the stack. Once the function returns, that buffer is no longer valid.

TJD
  • 11,800
  • 1
  • 26
  • 34
0

You are allocating the array on the stack inside of your recvmsg function. Returning a pointer to that memory will at some point lead to undefined behavior if it is dereferenced as the memory will be cleaned up when the function exits.

If you want to return a pointer to memory you will need to allocate it dynamically using malloc.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
0

when you are returning the buffer then as it acting as a pointer to the first location of the array so it will return its address.And the place where you are calling the function there you can make a character pointer which will store this returned address value .After which you can move your pointer and can access all the elements of your array.