Just for fun——C/C++函数返回局部变量的问题

常见栈内变量

一般来说,在函数内对于存在栈上的局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放。因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错;但是如果返回的是局部变量的地址(指针)的话,就造成了野指针,程序运行会出错,因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错。

#include <iostream>
using namespace std;
int fun1() {
    int i = 1;
    return i; // OK.
}
int* fun2() {
    int i = 2;
    int* ip = &i;
    return ip; // Wrong!
}
int main() {
    int r1 = fun1();
    cout << r1 << endl; // 1
    int* r2 = fun2();
    cout << *r2 << endl; // 这里有可能可以打印出结果:2,看似正确的,但其实是有问题的。这是因为相应的内存还未被覆盖,但这块内存已经是自由的、不被保护的了。
    return 0;
}

字符串

代码:

#include <iostream>
using namespace std;
char* fun3() {
    char* s = "Hello";
    return s; // OK.
}
char* fun4() {
    char s[] = "Hello";
    return s; // Wrong!
}
int main() {
    char* r3 = fun3();
    cout << r3 << endl; // Hello
    char* r4 = fun4();
    cout << r4 << endl; // 内存已经无效的了。打印出乱码。
    return 0;
}

静态变量

如果函数的返回值非要是一个局部变量地址,可以把局部变量声明为static静态变量。这样变量存储在静态存储区,程序运行过程中一直存在。

#include <iostream>
using namespace std;
int* fun5() {
    static int i = 5;
    return &i; // OK.
}
char* fun6() {
    static char s[] = "Hello";
    return s; // OK.
}
int main() {
    int* r5 = fun5();
    cout << *r5 << endl; // 5
    char* r6 = fun6();
    cout << r6 << endl; // Hello
    return 0;
}

数组

数组是不能作为函数的返回值的。因为编译器会把数组名认为是局部变量(数组)的地址。返回一个数组,实际上是返回指向这个数组首地址的指针。函数结束后,数组作为局部变量被释放,这个指针则变成了野指针。同1的fun2()及2的fun4()(字符数组)。但是声明数组是静态的,然后返回是可以的

#include <iostream>
using namespace std;
int* fun7() {
    int a[3] = {1, 2, 3};
    return a; // Wrong!
}
int* fun8() {
    static int a[3] = {1, 2, 3};
    return a; // OK.
}
int main() {
    int* r7 = fun7();
    cout << *r7 << endl; // 内存已经是无效的了。
    int* r8 = fun8();
    cout << *r8 <<endl; // 1
    return 0;
}

堆内变量

函数返回指向存储在堆上的变量的指针是可以的。但是,程序员要自己负责在函数外释放(free/delete)分配(malloc/new)在堆上的内存。

#include <iostream>
using namespace std;
char* fun9() {
    char* s = (char*) malloc(sizeof(char) * 100);
    return s; // OK. 但需要程序员自己释放内存。
}
int main() {
    char* r9 = NULL;
    r9 = fun9();
    strcpy(r9, "Hello");
    cout << r9 << endl; // Hello
    free(r9); // 要记得自己释放内存。
    return 0;
}

Salamander
上帝在我很小的时候送给我了两个苹果,一个红苹果,一个蓝苹果。红苹果代表疯狂,蓝苹果代表思考
6.7k 声望
407 粉丝
0 条评论
推荐阅读
Java AtomicInteger类使用
这个问题发生的原因是++counter不是一个原子性操作。当要对一个变量进行计算的时候,CPU需要先从内存中将该变量的值读取到高速缓存中,再去计算,计算完毕后再将变量同步到主内存中。这在多线程环境中就会遇到问...

pigLoveRabbit2阅读 2.3k

C 程序眼中的 Unicode
去年写了一篇文章「在 C 程序中处理 UTF-8 字符串」,介绍了如何使用 GLib 提供的 UTF-8 字符串处理函数来实现基本的 UTF-8 文本处理。不过,GLib 是一个功能比较全面的 C 程序库,C 字符串处理仅仅是它的一个很...

garfileo3阅读 5.6k评论 5

万字避坑指南!C++的缺陷与思考(上)
导语 | 本文主要总结了本人在C++开发过程中对一些奇怪、复杂的语法的理解和思考,同时作为C++开发的避坑指南。前言C++是一门古老的语言,但仍然在不间断更新中,不断引用新特性。但与此同时C++又甩不掉巨大的历史...

腾讯云开发者5阅读 506

计算机如何表示整数
在计算机中,任何的数据都是用二进制: 0 和 1 来表示。整数也不例外。生活中的 10,在 8 个字节的整数中表示为 00001010。但是这样子只能表示正数和零。怎么表示负数呢?于是有了符号位的概念。在 8 个字节的整...

kang2阅读 3k评论 7

麒麟操作系统 (kylinos) 从入门到精通 - 研发环境 - 第二十一篇 C++/C语言开发环境搭建
类别:笔记本型号:中国长城 NF14C硬件平台:飞腾处理器(ArmV8 指令集)系统:银河麒麟操作系统 V10 SP1(2203) 关键词:信创,麒麟系统,linux,c++,c,内核飞腾,arm

码上世界1阅读 2.3k评论 1

封面图
浙大版《C语言程序设计》第四版(何钦铭颜晖) 第5章 函数 课后习题答案
你也可以上程序咖([链接]),打开大学幕题板块,不但有答案,讲解,还可以在线答题。一、选择题1.在 C 语言程序中,若对函数类型未加显式说明,则函数的隐含类型为( )。A. voidB. double C. charD. int答:D解析...

茹茹1阅读 1k

万字避坑指南!C++的缺陷与思考(下)
导读 | 在万字避坑指南!C++的缺陷与思考(上)一文中,微信后台开发工程师胡博豪,分享了C++的发展历史、右值引用与移动语义、类型说明符等内容,深受广大开发者喜爱!此篇,我们邀请作者继续总结其在C++开发过...

腾讯云开发者4阅读 474评论 1

6.7k 声望
407 粉丝
宣传栏