C语言基础(18)-内存
一.内存布局
1.1 代码区
代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段。代码区是可读不可写的。
代码区中的所有的内容在程序加载到内存的时候就确定了,运行期间不可以修改,只可以执行。
1.2 静态区
静态区是程序加载到内存的时候就确定了,程序退出的时候就从内存消失。所有的全局变量和静态变量在程序运行期间都占用内存。静态区是可读可写的。
1.3 栈区
栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参,函数的返回值都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。
栈区的容量一般很小,单位一般是k,所以栈中不能有太多变量。不同的系统栈的大小是不一样的,Windows系统在编译的时候就可以指定栈的大小,Linux栈的大小是可以通过环境变量设置的。
1.4 堆区
堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
堆内存有一个最小单位,叫内存页,一个内存页的大小也不是固定的。
在当前测试的这个机器里面是4k为一个单位变化的,当我们需要申请一个堆内存的时候,总是以4k为一个单位,要一个char,给的是4k,操作系统这样做可以避免频繁分配内存。
堆的分配和释放
二.标准C内存函数
☞ malloc
☞ free
☞ calloc
☞ realloc
例1:malloc和free的使用
#include <stdio.h> // 这个头文件在系统目录下 #include <stdlib.h> // 使用了system函数 #include <Windows.h> #include <string.h> // 使用了memset函数 int main() { //int a = 0; // 在栈区 //static int b = 1; // 在静态区 //int array[10]; // 在栈区 //int sss[100000];// 不能在栈里面放太大的元素 // 堆内存 char *p; p = malloc(100); // 在堆中分配了一个100个字节的内存,p指向堆内存的首地址。p在栈里面,但p的值是堆地址编号 // !!!!堆内存使用完毕后需要进行释放 free(p); // 把p指向的堆空间翻译 // 在堆中分配一个int int *p1 = malloc(sizeof(int)); // 在堆中分配一个int大小的内存 *p1 = 0;//把堆中int的值设置为0 printf("%d\n",*p1); // 在堆中分配一个int数组 int *p2 = malloc(sizeof(int)*10); memset(p2,0,sizeof(int)*10); // 将这段内存的值初始化为0 for (int i = 0; i < 10; i++) { printf("%d\n",p2[i]); } free(p1); free(p2); system("pause"); return 0; }
例2:malloc和calloc的区别:
#include <stdio.h> // 这个头文件在系统目录下 #include <stdlib.h> // 使用了system函数 #include <Windows.h> #include <string.h> // 使用了memset函数 int main() { char *p1 = malloc(10*sizeof(char)); // malloc只负责分配不负责清理,因此在内存分配完成后,调用memset(x,0,x)进行初始化 char *p2 = calloc(10,sizeof(char)); // calloc分配内存的同时会把内存清空,即会将所有内存置为0 for (int i = 0; i < 10; i++) { printf("%x\n",p1[i]); } printf("--------------------------------\n"); for (int i = 0; i < 10; i++) { printf("%x\n",p2[i]); } system("pause"); return 0; }
执行结果:
例3:realloc的使用
#include <stdio.h> // 这个头文件在系统目录下 #include <stdlib.h> // 使用了system函数 #include <Windows.h> #include <string.h> // 使用了memset函数 int main() { char *s1 = malloc(10 * sizeof(char)); memset(s1, 0, 10 * sizeof(char)); //使用malloc分配的内存最好初始化 strcpy(s1, "123456789"); printf("当前s1的值为:%s\n", s1); char *s2 = calloc(10, sizeof(char)); // 分配10个内存单元,每个内存单元1字节 strcpy(s2, "abcdef"); printf("当前s2的值为:%s\n", s2); // 需求:把s1和s2合并为一个字符串,结果放入s1 int len1 = strlen(s1); int len2 = strlen(s2); // realloc的返回值是指向新空间的指针,如果错误则返回NULL s1 = realloc(s1, len1 + len2 + 1); // 重新为s1分配内存,+1的目的是字符串末尾还有一个\0的结束符,strlen求得的实际上是字符的总数 strcat(s1, s2); printf("当前s1的值为:%s\n", s1); free(s1); free(s2); system("pause"); return 0; }
执行结果:
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
分类:
C语言基础知识
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库