C 函数返回指针和引用的坑
创始人
2025-07-07 03:41:06
0

常用C++进行项目开发的童鞋们应该都知道,在C++中指针和引用是常用的语法了,而指针又是C++区别于其他高级语言的一大精髓。

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

函数返回指针

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

1.返回一个变量的地址

例如以下代码:

// 返回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;
}

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

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

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

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

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

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

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

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

// 返回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依然存在,不会存在前面所说的变量地址被释放的问题。

3.使用动态分配内存new关键字

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则会造成内存泄露, 这就引发了一个指针变量谁维护销毁的问题。一般默认规则是谁开发维护。

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

函数返回一个引用

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

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++是不允许直接返回一个数组的,如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数。

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

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

正确的写法应该是:

int* funTest(){
    static int myArray[3] = {1, 2, 3};
    return myArray;
}

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

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Intel将Moblin社区控... 本周二,非营利机构Linux基金会宣布,他们将担负起Moblin社区的管理工作,而这之前,Mobli...