易错、经典问题:return不可返回指向栈内存的指针
预备知识:内存的分类
C/C++程序占用的内存分为两大类:静态存储区与动态存储区。其示意图如下所示:

数据保存在静态存储区与动态存储区的区别就是:静态存储区在编译-链接阶段已经确定了,程序运行过程中不会变化,只有当程序退出的时候,静态存储区的内存才会被系统回收。动态存储区是在程序运行过程中动态分配的。
在其它地方我们还可以看到内存分配还有其他分类,那些都是细分的分类,比如文字常量区、全局数据区等,都归为静态存储区这一个大类。
关于内存的分类这里只是大致说明一下,关于内存更详细的内容可查看往期笔记:
例子:return返回指向栈内存指针
先看一个return返回指向栈内存指针的例子:
#include <stdio.h>
char *GetStr(void)
{
char p[] = "Hello"; /* 保存在栈中 */
return p;
}
int main(void)
{
char *str = NULL;
str = GetStr();
printf("%s\n", str);
return 0;
}
程序编译、运行的结果如下:

可以看到,编译出现警告:
warning: function returns address of local variable
运行结果并不是我们期望的输出字符串Hello。
那是因为GetStr函数返回指向栈内存的指针,这里的变量p是局部变量,而局部变量是分配在栈上的。即Hello保存在栈内存上,栈内存在函数调用结束时会自动销毁,因此此时的p里的内容是未知的,所以结果无输出。
下面我们把GetStr函数修改为:
char *GetStr(void)
{
char *p = "Hello"; /* p在栈上,Hello在静态区(常量区) */
return p;
}
此时编译运行的结果是怎样的呢?结果为:

可以看到能正常输出。为什么这里又可以正常输出呢?因为这里的p虽然分配在栈上,但是此时的Hello是一个字符串常量,其存储在静态存储区。在调用GetStr函数结束时其也不会被销毁。
这里可能有些人会有疑惑,同样是Hello,为什么一个在栈上,一个在静态区。
char *p = "Hello";
此处首先定义了一个指针变量p,编译器就会为指针变量开辟了栈空间。而此时并没有空间来存放Hello,所以Hello只能存储在静态区。
char p[] = "Hello";
此处首先定义一个数组p,因为未给出数组大小,所以此时数组大小未确定。然后把Hello保存在这个数组里,编译器就会为数组p开闭适当的栈空间来存储Hello。
相关笔记:【C语言笔记】char *str与char str[]的区别
其它替代方法
从上面的例子我们知道,若函数返回指向栈内存的指针,所得到的结果并不是我们想要的。除了上面的方法之外,这里还有如下几种解决方法:
1、把p定义为全局变量,因为全局变量存储在静态存储区,程序结束才会释放。但是这样会导致函数是不可重入的。关于函数的重入与不可重入可查看往期笔记。
2、在GetStr函数中使用malloc申请动态内存,但使用完一定要记得使用free进行释放,否则会导致内存泄漏。示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *GetStr(void)
{
char *p = (char*)malloc(64*sizeof(char));
strcpy(p, "Hello");
return p;
}
int main(void)
{
char *str = NULL;
str = GetStr();
printf("%s\n", str);
free(str); /* 释放str指向的堆内存 */
return 0;
}
3、可以将变量p声明为static静态变量。但这也会导致函数是不可重入的。示例代码如下:
char *GetStr(void)
{
static char p[] = "Hello";
return p;
}
以上就是本次笔记分享的内容,如有错误,欢迎指出!
我的个人博客:https://zhengnianli.github.io/
我的微信公众号:嵌入式大杂烩
易错、经典问题:return不可返回指向栈内存的指针的更多相关文章
- C++ —— 返回数组指针的函数 和 返回指向函数的指针的函数
返回数组指针的函数 基础知识:数组不能被拷贝,函数不能返回数组,只能返回数组的指针或者引用. 定义一个 返回数组指针的函数 的方法,以 一个接收参数为 含有10个整型元素的数组的引用 和 返回一个含 ...
- C语言指针的易错点
1.内存泄漏:申请的堆内存没有释放. 2.内存污染:前面非法操作使用内存(没有报错),后面写着写着就出错.如下代码: 当结构体中只有划线部分代码时,在编译器中编写不会报错,但此时已经造成非法操作内存, ...
- 你必须知道的----C语言笔试面试中经典易错的一些知识点(持续更新)
1. 关于二级指针的解析和引用 1.1 二级指针意义 二级指针存放的是一级指针的地址 Ex: Int a = ; Int *p = &a; Int **q = &p; 1.2 ...
- JavaScript易错知识点整理
前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...
- JavaScript 易错知识点整理
本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES ...
- 细节!重点!易错点!--面试java基础篇(二)
今天来给大家分享一下java的重点易错点第二部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.字符串创建与存储机制:当创建一个字符串时,首先会在常量池中查找是否已经有相同的字符串被定义,其判断 ...
- JavaScript易错点转载
前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...
- JavaScript易错知识点整理[转]
前言 本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一 ...
- forEach、map、filter、find、sort、some等易错点整理
一.常用方法解析 说起数组操作,我们肯定第一反应就是想到forEach().map().filter()等方法,下面分别阐述一下各方法的优劣. 1.forEach 1.1 基础点 forEac ...
随机推荐
- Centos7 C++ 安装使用googletest单元测试
废话不多说,直接开始吧. 环境说明 系统环境:centos7.0 g++ 版本: g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36) 查看方法: g++ -vers ...
- 使用vitamio长时间播放崩溃的另类处理
最近公司一个项目在公交站旁边弄一个 广告牌,上面是广告视频,下面是广告图片,都是无限轮播的.要求从早上6点到晚上11点不间断播放.剩余时间为关机状态. 图片部分还好说,就是viewpager弄一个无限 ...
- null==a和a==null的区别
在项目代码中在if判断中会经常看到一些老司机这样写:if(null == a),而我由于习惯会写成if(a == null),这两种有什么区别呢? 其实两种并没有什么区别,只是前者在细节处理上.我们在 ...
- DevExpress的TextEdit限制输入内容的格式,比如只能输入数字
场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...
- STL 补档
STL 补档 1.vector 作用:它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据. vector在C++标准模板库中的部分内容,它是 ...
- b146: NOIP2004 1.不高兴的津津
题目: 津津上初中了.妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班.另外每周妈妈还会送她去学习朗诵.舞蹈和钢琴.但是津津如果一天上课超过八个小时就会不高兴,而且 ...
- 大数据平台搭建 - Mysql在linux上的安装
一.简介 MySQL是一个关系型数据库系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 ...
- springboot---redis缓存的使用
1.下载redis安装包,解压到电脑 2.启动redis 3.springboot application.properties中配置redis缓存 spring.redis.host=127.0. ...
- 疑难杂症----windows7
这两天换了台win7的机器,每次开机发现时间日期没法更新,第一次手动更新后过了一天以后又恢复成20xx/01/01,头疼ing,网上找了好多办法,在这里记录一下,避免以后再碰到同样的问题. 出现这个问 ...
- liunx帮助whatis使用方法
liunx帮助 获取帮助的能力决定了技术的能力! 1.whatis ♢只显示命令的简短描述,相对功能比较单一. [09:42:22 root@centos ~]# ...