C语言程序猿必会的内存四区及经典面试题解析
前言:
为啥叫C语言程序猿必会呢?因为特别重要,学习C语言不知道内存分区,对很多问题你很难解释,如经典的:传值传地址,前者不能改变实参,后者可以,知道为什么?还有经典面试题如下:
#include <stdio.h> #include <stdlib.h>
#include <stdlib.h> void getmemory(char *p) { p=(char *) malloc(100); } int main( ) { char *str=NULL; getmemory(str); strcpy(str,"hello world"); printf("%s/n",str); free(str); return 0; }
这段代码执行了会怎么样?接下里我会解释这道面试题。
一、内存布局
可能网上有很多把内存分的很多、很细,但觉得很难记,并对于理解问题作用并不大。现在主要将内存分为四区如下:
代码区:存放代码;运行期间不可修改
全局区:全局变量、静态变量、常量字符串;程序运行时存在,退出时消失。
栈区:自动变量、函数参数、函数返回值;作用域函数内(代码块内)
堆区:动态分配内存,需手动释放
用交换两个数的程序进行解释吧,如下:
#include<stdio.h> void swap(int a,int b) { int temp = a; //栈 a = b; b =temp; } int main() { int a=1,b=2; //栈 printf("a:%d,b:%d\n",a,b); swap(a,b); printf("a:%d,b:%d\n",a,b); return 0; }
画个图进行讲解,如下: PS:依旧是全博客园最丑图,不接受反驳!
说明:main函数把a,b的值给了temp函数,temp函数在内部交换了值,并没有影响main函数,并且temp结束,栈上的数据释放。传值不会改变实参。
二、程序示例及面试题讲解
1、传地址交换两个数
在拿传指针的例子来说明一下,如下:
#include<stdio.h> void swap(int *a,int *b) { int temp = *a; //栈 *a = *b; *b =temp; } int main() { int a=1,b=2; //栈 printf("a:%d,b:%d\n",a,b); swap(&a,&b); printf("a:%d,b:%d\n",a,b); return 0; }
结果:成功交换了实参的值
用图进行解释,如下: PS:依旧是全博客园最丑图,不接受反驳!
说明:实参把地址传给形参,形参*a、*b是取的实参在内存中的值,交换也就是交换实参的值了,所以成功交换了实参的值。
2、解释面试题
程序就是最开始的面试题那个,不再列出来了。
结果:段错误
然后画图进行说明,如下: PS:依旧是全博客园最丑图,不接受反驳!
说明:最重要一点实参是把值传给形参,而不是地址,要理解这一点!就是把实参的NULL给了形参,然后getmemory在堆上开辟空间,结束时p被释放了,但main函数中的str并没有指向堆上的内存,再给strcpy,当然会段错误。
三、解决被调函数开辟空间
可能有人就问了,我就想让被调函数开空间,怎么办呢?那就需要形参是二级指针了。
给大家演示一下,代码如下:
#include <stdio.h> #include <string.h> #include <stdlib.h> void getmemory(char **p) { *p=(char *) malloc(100); } int main( ) { char *str=NULL; getmemory(&str); strcpy(str,"hello world"); printf("%s/n",str); free(str); return 0; }
结果:没有段错误了
大家可以自己画下图,不懂欢迎随时留言。
三、十月份计划
十月份需求会很忙,但也要抽出时间把C++基础学完,然后深入学习数据结构和算法了
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端