C/C++ 中的函数返回局部变量以及局部变量的地址?

C/C++ 中的函数返回局部变量以及局部变量的地址?

C/C++中,函数内部的一切变量(函数内部局部变量,形参)都是在其被调用时才被分配内存单元。形参和函数内部的局部变量的生命期和作用域都是在函数内部(static变量的生命期除外)。子函数运行结束时,所有局部变量的内存单元会被系统释放。在C中,函数被调用时的传参方式有两种形式:传值和传址。 传址的好处: (1) 能在函数内部通过实参地址间接地改变实参的值。 (2) 当所传实参内容比较庞大时,传址只是复制了整个实参的地址过去,指针依据同一个地址访问实参变量。而传值就会将实参内容整个拷贝过去,形参会跟实参占一样大的内存,栈空间是有限的。当然了,在弱小的程序中,传址的这个优点不会被体现出来。

在函数中,可以随意的返回一个局部变量。 但如果返回一个局部变量的地址(指针),编译器就会给出警告。因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放,这样指针指向的内容就是不可预料的内容,程序就会出错。

准确的来说,函数不能返回指向栈内存的指针(返回指向堆内存的指针是可以的)。

返回局部变量

C++中,函数是可以返回局部变量的,原因:返回值是拷贝值,局部变量的作用域为函数内部,函数执行结束,栈上的局部变量会销毁,内存释放。

可返回的局部变量:

1、返回局部变量本身

#include

int display() {

int num = 9;

return num;

}

int main() {

int p = display();

std::cout << p << std::endl; // 9

return 0;

}

display 函数返回一个 int 类型的局部变量 num,函数会把局部的num的值复制一份拷贝给主函数里面的 p 变量。这样是可以的,而且这种方式在程序里面还是经常用到的。 上面程序输出:9

返回局部变量地址

引用一位博主的分析:https://blog.csdn.net/qq_34801642/article/details/88411252 C/C++语言函数是不能返回局部变量地址(特指存放于栈区的局部变量地址),除非是局部静态变量地址,字符串常量地址、动态分配地址。其原因是一般局部变量的作用域只在函数内,其存储位置在栈区中,当程序调用完函数后,局部变量会随此函数一起被释放。其地址指向的内容不明(原先的数值可能不变,也可能改变)。而局部静态变量地址和字符串常量地址存放在数据区,动态分配地址存放在堆区,函数运行结束后只会释放栈区的内容,而不会改变数据区和堆区。

举例如下:

#include

int* display() {

int num[3] = {8,6,5};

return num;

}

int main() {

int* p = display();

for(int i = 0; i < 3; i++) {

std::cout << *(p+i) << std::endl;

}

return 0;

}

这段代码存在一个问题,即在函数display()中返回了一个指向局部变量num的指针。这是不安全的操作,因为当函数display()结束时,局部变量num将被销毁,指向它的指针p将变成悬空指针,使用它可能导致未定义的行为。 上述程序输出结果为:

若要完整的打印num数组中的3个数,我们该怎么做呢?

函数返回局部变量的地址通常有以下几种方法

1、返回一个字符串常量的指针 const char* buffer = "helloword";

#include

const char* display() {

const char* buffer = "helloword";

return buffer;

}

int main() {

const char* str;

str = display();

std::cout << str << std::endl;

return 0;

}

这样程序运行是没有问题的;buffer存在只读内存区,在 display() 退出的时候,字符串常量不会被收回,因此把地址赋给str时可以正确访问。 上面这个方式只是最简单的解决方案,因为字符串存放在只读内存区,以后需要修改它的时候就会很麻烦。

上述程序输出:

(以下为错误方法 char buffer[] = "helloword"; )

#include

char* display()

{

char buffer[] = "helloword";

return buffer;

}

int main()

{

char* str;

str = display();

std::cout << str;

return 0;

}

在display()函数中,你定义了一个局部字符数组buffer,并将其作为指针返回给主函数。然而,当函数执行完毕后,局部数组buffer的生命周期结束,它所占用的内存将被释放。因此,在主函数中访问指针str指向的值将会导致未定义的行为。 运行上述程序,输出乱码。

2、使用全局声明的数组

没有使用全局声明的数组的情况

#include

int* display() {

int num[5] = { 3,4,5,6,8 };

return num;

}

int main() {

int* p;

p = display();

for (int i = 0; i < 5; i++) {

std::cout << "*(p+" << i << "):" << *(p + i) << std::endl;

}

return 0;

}

输出结果:

使用了全局声明的数组的情况

#include

int num[5] = { 3,4,5,6,8 };

int* display() {

return num;

}

int main() {

int* p;

p = display();

for (int i = 0; i < 5; i++) {

std::cout << "*(p+" << i << "):" << *(p + i) << std::endl;

}

return 0;

}

输出结果:

这种情况简单容易。缺点就是任何人都有可能在任何时候修改这个全局数组,而且该函数的下一次调用会覆盖数组的内容。

3、使用静态数组 static

#include

int* display() {

static int num[5] = { 3,4,5,6,8 };

return num;

}

int main() {

int* p;

p = display();

for (int i = 0; i < 5; i++) {

std::cout << "*(p+" << i << "):" << *(p + i) << std::endl;

}

return 0;

}

输出结果:

使用静态数组可以保证内存不被回收,而且可以防止任何人修改这个数组。只有拥有指向该数组的指针的函数才能修改这个静态数组,不过同时该函数的下一次调用会覆盖数组的内容。同时和全局数组一样,大型缓冲区闲置是非常浪费空间的。

补充:

static int num[5]和int num[5]的区别在于变量的作用域和生命周期。

1. static int num[5]:在函数内部或者代码块内部使用static关键字声明的数组,称为静态数组。静态数组的特点是: - 作用域:静态数组的作用域限定在声明它的函数内部或者代码块内部。 - 生命周期:静态数组在程序运行期间一直存在,即使函数执行完毕或者代码块结束,数组仍然存在于内存中。 - 存储位置:静态数组存储在静态存储区,不会随着函数的调用而创建和销毁。

2. int num[5]:只使用int关键字声明的数组,称为自动数组(也称为局部数组)。自动数组的特点是: - 作用域:自动数组的作用域限定在声明它的函数内部或者代码块内部。 - 生命周期:自动数组的生命周期与所在的函数执行周期相关,函数执行完毕或者代码块结束时,数组会被销毁。 - 存储位置:自动数组存储在栈上,随着函数的调用和返回而动态创建和销毁。

总结: 静态数组的作用于是全局的,生命周期是整个程序运行期间,存储在静态存储区; 自动数组的作用域是局部的,生命周期与所在函数相关,存储在栈上。

4、显式的分配内存,在堆上动态分配内存 new / malloc

使用new动态分配内存

#include

char* display()

{

char* buffer = new char[11];

strcpy_s(buffer,11, "helloworld");

return buffer;

}

int main()

{

char* str;

str = display();

std::cout << str;

delete[] str; // 释放内存

return 0;

}

输出结果为:

在上述代码中,我们使用strcpy_s函数来进行字符串复制操作。注意,我们还将缓冲区大小作为第二个参数传递给strcpy_s,确保不会发生缓冲区溢出。 注意,在使用动态内存分配时,需要确保在不再使用时手动释放内存,以避免内存泄漏。

使用malloc动态分配内存

#include

char* fun()

{

int i;

char* buffer = (char*)malloc(sizeof(char) * 20);

if (buffer != NULL) {

strcpy_s(buffer,20, "abcdefgwwwwwwweeeww");

}

return buffer;

}

int main()

{

char* str;

str = fun();

if (str != NULL) {

std::cout << str << std::endl;

free(str); // 释放内存

}

return 0;

}

输出结果:

部分引用自:

C/C++ 返回函数内局部变量和局部变量的地址_c++返回地址的函数-CSDN博客

相关数据

手机应用商店软件排行榜
365beat版app

手机应用商店软件排行榜

⌛ 08-08 👁️ 5730
我注册了中文域名不知道怎么解析
约彩365苹果在线安装

我注册了中文域名不知道怎么解析

⌛ 10-01 👁️ 6040
什么是SD-WAN?
365beat版app

什么是SD-WAN?

⌛ 08-04 👁️ 4199