预备知识:内存的分类 C/C++程序占用的内存分为两大类: 静态存储区 与动态存储区 。其示意图如下所示: 数据保存在静态存储区与动态存储区的区别就是:静态存储区在 编译-链接 阶段已经确定了,程序运行过程中不会变化,只有当程序退出的时候,静态存储区的内存才会被系统回收。动态存储区是在程序运行过程中动态分配的。 在其它地方我们还可以看到内存分配还有其他分类,那些都是细分的分类,比如文字常量区、全局数据区等,都归为静态存储区这一个大类。 关于内存的分类这里只是大致说明一下,关于内存更详细的内容可查看往期笔记: 【C语言笔记】内存笔记 例子:return返回指向栈内存指针 先看一个return返回指向栈内存指针的例子: #includechar *GetStr(void) { char p[] = "Hello"; /* 保存在栈中 */ return p; } int main(void) { char *str = NULL; str = GetStr(); printf("%s ", 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 #include #include 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 ", str); free(str); /* 释放str指向的堆内存 */ return 0; } 3、可以将变量p声明为static静态变量。但这也会导致函数是不可重入的。示例代码如下: // 微信公众号:嵌入式大杂烩 char *GetStr(void) { static char p[] = "Hello"; return p; }猜你喜欢: 分享一些C语言的经典demo 分享一个有趣的库,让你学习C语言不会觉得那么枯燥 长文 | 花了两天时间整理了STM32中的一些C语言知识点 1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。私信回复1024,即可免费获取!