C++ 函数返回指针,为什么这能够工作?

3

可能是重复问题:
局部变量的内存可以在其作用域外被访问吗?

这里有一个简单的 C++ 函数。它接受一个字符数组和一个整数 n 作为参数,然后创建一个新的只包含数组前 n 个元素的字符数组。

char * cutString(char * ch , int n){

  char * p = new char[n];
  int i ;
  for(i = 0 ; i < n ; i++)
         p[i] = ch[i];
  while(i <= n ){
    p[i++] = '\0';
  }
  return p ;

}

这段代码原本没问题,但如果我把char * p = new char[n];改成char p[n];后,会出现奇怪的字符。发生了什么?前者和后者有什么区别?另外,变量p是临时变量;函数如何成功返回它呢?


1
https://dev59.com/ZWw15IYBdhLWcg3wuuCn - chris
如果char* c是以空字符结尾的字符串,就没有理由添加第二个空字符。当i == n时,for循环终止,所以while循环总是会开始。while循环在将null字符添加到p[i](实际上是p[n])之前进行递增。p[n]超出了数组分配的大小。你要么在顶部说p = new char[n + 1],要么用if (p[n - 1] != '\0') p[n - 1] = '\0';替换while循环,或者在一开始就说if (ch[n] != '\0') return 0。我不知道对于你的使用模型什么是适当的。 - GlenPeterson
4个回答

9

char *p = new char[n] 动态地在堆上分配内存。这种内存的生命周期不受任何函数的限制,直到它被释放(使用delete[])。因此,返回其指针是完全有效的。

另一方面,char p[n] 在栈上分配内存,其生命周期绑定到定义它的函数。一旦该函数返回,对该内存的任何引用都会变得无效。


如果我在函数内使用 delete [] p,那么程序还能正常工作吗?我的意思是,我已经将其删除了,所以它没有返回值,因此它不应该工作。 - Nash Vail
@user1218380 如果您在函数内部使用 delete[] p 然后 return p,则返回的是指向无效(未分配)内存的指针。很有可能您的数据仍然存在,如果访问返回的指针不会导致访问冲突,那么它将获取数据,但这是纯属巧合。原则上访问已释放内存是非法的。 - Angew is no longer proud of SO

7
当您将代码更改为以下内容时:
char p[n];

当你返回p时,你正在返回指向局部变量的指针。在函数返回后,p不再存在。言简意赅的说,这样做会导致未定义的行为,并使你的程序不符合规范。


1

因为new char[n]将在堆上分配内存(不要忘记稍后delete[]它)

char p[n];是一个静态数组,驻留在堆栈上,在函数返回后会自动重用

如果你从函数中返回对它的引用,那么你就返回了一个指向未使用内存的指针,引用未使用内存是标准未定义行为


1
这是动态分配和自动分配内存的区别。 char * p = new char [n]; 是动态分配,这意味着内存在您删除它之前一直有效。另一方面,char p [n]; 严格来说不是合法的C ++,但使用您正在使用的编译器时,它是一种自动分配形式,这意味着当您退出函数时,内存不再有效。这就是为什么你会看到有趣的字符。

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