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

5
  • 5
    You should settle for either C or C++ as a good answer will depend on that. Commented Oct 14, 2011 at 15:38
  • 2
    Did you want answers for C++ as well or just C? Commented Oct 14, 2011 at 15:39
  • 1
    Oh and btw. void main is wrong. Commented Oct 14, 2011 at 15:41
  • 2
    If the thing you're learning C++ from uses void main it's highly likely crap. I'll recommend a good introductory C++ book. Commented Oct 14, 2011 at 15:50
  • It might be okay to disregard the warning in the case of using the return of *recvmsg only as input to a function like strcpy in the calling routine, as the function return is not used in an assignment. Commented Mar 29, 2020 at 4:09

12 Answers 12

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.

Sign up to request clarification or add additional context in comments.

4 Comments

hehe, the OP did vote for c++, so this is what it should be
The OP could also use std::string.
@ThomasMatthews: If you're conceptualizing the data (of type char*) as buffer as opposed to string, then I believe std::vector<char> conveys that better without any ambiguity, than std::string.
.. Or one could use using buffer_t = std::vector<char>; (or maybe, using buffer_t = std::string;), then use buffer_t; maybe that is more appropriate. (Wish C++ had strong aliases!)
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[].

6 Comments

Using new in C++ doesn't make it C++-style solution. The C++-style solution is std::vector<char> instead of raw pointer char*.
you cant really use std::vector with p/invoke, as far as i know, if you have any interop needs with c# or VB
isn't malloc( 1024 * sizeof( char ) ) better?
@sazary matter of preference, sizeof char is always 1.
It is not necessary, that malloc is used, see the answer of karl or mine.
|
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.

2 Comments

I would surely not suggest this. In C++, std::vector<char> is better solution. This answer suggests C-style solution, but the question is tagged with C++.
Why was I under the impression that it was tagged C... But yes you're correct, vector is preferred.
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);
}

1 Comment

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
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;
}

Comments

2
char *recvmsg(){
    char *buffer = new char;
    cout<<"\nENTER NAME : ";
    cin>> buffer;
    return buffer;
}

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

Comments

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));
}

Comments

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)

Comments

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.

Comments

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.

Comments

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.

Comments

0

how about passing by ref

char buf[1024];
PutStuffInBuff(&buf);

1 Comment

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.