C++函数返回指针和引用的坑

常用C++进行项目开发的童鞋们应该都知道,在C++中指针和引用是常用的语法了,而指针又是C++区别于其他高级语言的一大精髓。 针对C++中的指针和引用,博主之前也写过几篇技术博文进行了介绍了,忘记了的童鞋们可以温故知新:

C++之指针扫盲
C++之智能指针
C++之指针与引用
C++之右值引用

而今天我们再来看看在C++新手们针对指针和引用的使用经常犯的错误。

函数返回指针

在C++中针对一个函数返回指针的实现方式一般有三种:

  • 返回一个变量的地址

例如以下代码

c 复制代码
// 返回int指针地址
int * funTest(){
    int a = 101;
    return &a;
}

int main(int argc, const char *argv[]) {
    int *a = funTest();
    std::cout << "a的值:" << *a << std::endl;
    return 0;
}

以上代码在笔者的电脑上运行就直接报错崩溃了,崩溃信息:

vbnet 复制代码
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

上面的代码返回一个局部变量a的地址,这个变量a紧在函数funTest内有效,当函数funTest结束了,变量a的生命周期也就结束了, 此时变量a所占用的内存空间将被释放,因此返回的指针地址将会被指向一个未知数,后续再使用这个指针是未定义的行为,可能会导致程序崩溃或者出现其他异常。

针对这样的危险代码行为,其实编辑器也已经给出了警告,所以说在开发过程中也不要以为的忽略警告哦。

为了杜绝此类行为的发生,还可以使用笔者之前的介绍的代码质量检测工具cppcheck进行检测,在开发过程中直接划线提醒。

介绍一款CPP代码bug检测神器

  • 返回一个使用static修饰的变量地址

我们修改一下funTest函数的变量a,使用static关键字修饰一下:

c 复制代码
// 返回int指针地址
int * funTest(){
    static int a = 101;
    return &a;
}

int main(int argc, const char *argv[]) {
    int *a = funTest();
    std::cout << "a的值:" << *a << std::endl;
    return 0;
}

运行发现程序并没有崩溃,而且是正确打印出了变量a的值。这是因为 使用static 表示将这个变量存储到全局区(static静态区), 此时就不受栈区管控,当函数funTest执行完毕后,变量a依然存在,不会存在前面所说的变量地址被释放的问题。

  • 使用动态分配内存new关键字
c 复制代码
int * funTest(){
    //动态分配的内存空间,手动delete后才会释放
    int* a = new int(101) ;
    return a;
}

int main(int argc, const char *argv[]) {
    int *a = funTest();
    std::cout << "a的值:" << *a << std::endl;
    return 0;
}

上述代码不会崩溃,也能正常运行,但是存在一个隐患就是返回的指针变量a如果忘记调用delete则会造成内存泄露, 这就引发了一个指针变量谁维护销毁的问题。一般默认规则是谁开发维护。

因此,针对这样的场景,笔者的建议是智能指针你值得拥有...

函数返回一个引用

我们看看以下返回一个引用的例子代码:

c 复制代码
int & funTest(){
    //动态分配的内存空间,手动delete后才会释放
    int a = 101 ;
    return a;
}

int main(int argc, const char *argv[]) {
    int a = funTest();
    std::cout << "a的值:" << a << std::endl;
    return 0;
}

笔者在CLion上测试也是直接崩溃了,原因也是和上面所说的返回一个局部变量的地址一样, 都是因为函数funTest结束后,变量a的生命周期结束了, 变量a也就是被释放了,再返回它的引用的话就是未定义的。至于为什么它们的原因是一样的呢?因为所谓引用,可以简单地理解为引用其实就是带const修饰的指针。

那么针对这个问题该如何修正呢?首先使用static关键字肯定是可以的。那么使用动态内存new的方式行不行呢?答案也是可行的,但是需要注意的一点就是如果一个引用 的值来源于一个指针,后来这个指针被delete掉了,那么再使用这个引用也是会造成崩溃的...

如何返回一个数组

那么问题来了,举一反三,如果想通过一个函数返回一个数组那该如何实现呢?

众所周知,C++是不允许直接返回一个数组的,如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数。

例如下面的写法是编译不通过的:

csharp 复制代码
// 无法编译通过,不能返回一个数组
int[] funTest(){
    int myArray[3] = {1, 2, 3};
    return myArray;
}

正确的写法应该是:

arduino 复制代码
int* funTest(){
    static int myArray[3] = {1, 2, 3};
    return myArray;
}

因而可以看出,其实返回一个数组的函数所遇到的坑其实就转换成了返回一个指针的函数所遇到的坑,这些坑的举例就如前面所说...

推荐阅读

C++进阶系列

关注我,一起进步。

相关推荐
uyeonashi16 分钟前
【Boost搜索引擎】构建Boost站内搜索引擎实践
开发语言·c++·搜索引擎
Smile丶凉轩3 小时前
Qt 界面优化(绘图)
开发语言·数据库·c++·qt
small_wh1te_coder5 小时前
从经典力扣题发掘DFS与记忆化搜索的本质 -从矩阵最长递增路径入手 一步步探究dfs思维优化与编程深度思考
c语言·数据结构·c++·stm32·算法·leetcode·深度优先
hjjdebug7 小时前
constexpr 关键字的意义(入门)
c++·constexpr
虾球xz8 小时前
游戏引擎学习第282天:Z轴移动与摄像机运动
c++·学习·游戏引擎
.小墨迹8 小时前
Apollo学习——planning模块(3)之planning_base
linux·开发语言·c++·学习·自动驾驶
龙湾开发9 小时前
计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 10.增强表面细节(一)过程式凹凸贴图
c++·笔记·学习·3d·图形渲染
德亦周9 小时前
如何在Mac电脑上的VScode去配置C/C++环境
c++·vscode·macos
XiaoyaoCarter9 小时前
每日一道leetcode(新学数据结构版)
数据结构·c++·算法·leetcode·职场和发展·哈希算法·前缀树
八月的雨季 最後的冰吻9 小时前
SIP协议栈--osip源码梳理
linux·服务器·网络·c++·网络协议