如何在C++中返回本地数组?

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

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

我收到一个警告:

警告 C4172:返回局部变量或临时对象的地址


5
你应该选择 C 或者 C++,因为好的答案取决于你选择哪个。 - PlasmaHH
2
你是想要C++的答案还是只需要C的? - JoeG
1
哦,顺便说一下,void main 是错误的。 - PlasmaHH
2
如果你正在学习C++的教程使用了void main,那么它很可能是垃圾。我会推荐一本好的C++入门书籍 - R. Martinho Fernandes
如果在调用例程中仅将*recvmsg的返回值作为strcpy等函数的输入而不进行赋值操作,则可以忽略警告。 - Laurie Stearn
12个回答

30
我建议使用std::vector<char>
std::vector<char> recvmsg()
{
    std::vector<char> buffer(1024);
    //..
    return buffer;
}
int main()
{
    std::vector<char> reply = recvmsg();
}

如果你的代码中需要使用 char*,那么随时可以使用 &reply[0]。例如:

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

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

完成了。这意味着,如果你正在使用C API,那么你仍然可以使用std::vector,因为你可以像上面所示一样传递&reply[0]到C API,同时将reply传递给C++ API。

底线是:尽量避免使用new。如果你使用new,那么你必须自己进行管理,并且在不需要它时要使用delete


3
好的,我会尽力进行翻译。以下是需要翻译的内容:hehe,OP确实投了C++的票,所以应该按照这个来。 - sehe
3
楼主也可以使用 std::string - Thomas Matthews
@ThomasMatthews:如果您将类型为char*的数据概念化为缓冲区而不是字符串,那么我认为std::vector<char>std::string更好地传达了这一点,没有任何歧义。 - Nawaz
或者可以使用 using buffer_t = std::vector<char>;(或者,也许是 using buffer_t = std::string;),然后使用 buffer_t;也许更合适一些。(但愿 C++ 有强大的别名!) - Nawaz

15

你需要动态分配你的字符数组:

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

适用于C++和

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

对于C语言。

如果没有动态分配内存,你的变量会在函数的堆栈上,因此在退出时被销毁,这就是为什么会出现警告。在堆上分配它可以防止这种情况,但你必须小心并通过delete[]释放内存。


5
在C++中使用new并不代表它是符合C++风格的解决方案。C++风格的解决方案是使用std::vector<char>而不是裸指针char* - Nawaz
1
据我所知,您无法真正使用std::vector与p/invoke一起使用,如果您需要与C#或VB进行任何互操作。 - Tom Fobear
3
“malloc(1024 * sizeof(char))”更好吗? - sazary
2
@sazary 这是个人偏好问题,char 的大小始终为1。 - Luchian Grigore
不一定需要使用malloc,可以参考karl或者我的答案。 - Juergen
这不是你在C++中应该这样做的方式,它非常糟糕。请参考这个答案 - François Andrieux

11

警告信息是正确的。您正在返回一个局部数组的地址,该数组在函数返回后消失。

您可以使用动态内存分配来解决这个问题:

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

要注意的是需要在后面使用 free() 函数释放指针以避免内存泄漏。

或者你可以将缓冲区传递给函数。

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

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

这样可以避免进行内存分配,事实上这是推荐的做法。


2
我肯定不会建议这样做。在C++中,std::vector<char>是更好的解决方案。这个答案提供了C风格的解决方案,但问题标记为C++。 - Nawaz
为什么我一直以为它被标记为C语言...但是没错,你是正确的,向量是首选。 - Mysticial

7
问题在于buffer存在于栈上,当你退出recvmsg函数时就会被释放。
你可以在堆上分配buffer
char *recvmsg(){
  char *buffer = malloc(1024);
  return buffer;
}

请注意,现在调用方负责释放已分配的内存:
void main(){
  char *reply = recvmsg();
  free(reply);
}

1
大多数答案都是正确的,但只有你提到了free()。我会在main()函数的两行之间放置一个注释:/* do stuff here*/,以提高可读性。+1 - Andrejs Cainikovs

2

你有几个选项...目前你的做法会导致未定义行为,因为数组将在函数返回后超出作用域。所以一个选择是动态分配内存...

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

记得使用delete(或者如果你使用了malloc,则使用free)来清理它。其次,你可以使用参数...

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

同样的,与之前一样,在这里进行清理也是必要的。同时请注意检查为0,以确保您不会在已经分配了指针的情况下调用new。

最后,您可以使用一个向量(vector)。

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

   //do stuff with vector here

   return temp;
}

2

补充一下:

使用malloc分配内存并不是必须的。你也可以在堆栈上创建缓冲区,但是你必须在一个与缓冲区使用者同生命周期的堆栈帧上创建它。这就是OP的错误——当调用者完成时,缓冲区被删除了,调用者得到了一个无效的指针。

所以你可以这样做:

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

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

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

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

1

你可以动态创建缓冲区,但是调用者需要知道如何释放它。

我认为最好传入一个缓冲区(假设recvmsg也填充它)

void recvmsg(char *buffer, size_t size){

}

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

即使调用者决定使用动态分配更好,他们也会知道需要释放它,并且知道如何释放(free()、delete、delete[]或者从自定义分配器中使用的特殊方法)。

0

如何通过引用传递

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

1
我猜,karl的意思是调用者提供了对buf的引用,而被调用者填充了buf。因为调用者的生命周期比被调用者长(buf也是如此),只要调用者不返回对buf的引用,一切都没问题。 - Juergen

0
问题在于您正在返回指向在堆栈上分配的缓冲区的指针。一旦函数返回,该缓冲区就不再有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接