C 语言内存管理
一、内存管理
- malloc:申请动态内存空间
- free:释放动态内存空间
- calloc:申请并初始化一系列内存空间
- realloc:重新分配内存空间
注意这些函数都是在头文件中
1.malloc:申请动态内存空间 存放在堆中
函数原型:void *malloc(size_t size);
malloc 函数向系统申请分配size个字节的空间,并返回一个指向这块空间的指针。
如果函数调用成功,返回一个指向申请的内存空间的指针,由于返回类型是void指针(void *),所有它可以被转换成任何类型的数据;如果函数调用失败,返回值是NULL。另外,如果size参数设置为0,返回值也可能是NULL,但这并不意味着函数调用失败。
2.free:释放动态内存空间
动态内存是存放在堆中的,如果你不主动去释放堆上的内存资源,那么他将永远的存在,直到程序关闭。
函数原型:void free(void *ptr);
free函数将释放ptr参数指向的内存空间。该内存空间必须是由 malloc、calloc、realloc 函数申请的。否则该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。注意:该函数并不会修改ptr参数的值,所以调用后任然指向原来的地方(变为非法空间)。
#include<stdio.h>
#include<stdlib.h>
int main(){
int *ptr;
ptr = (int *)malloc(sizeof(int));
if(ptr == NULL){//一般内存不够用的时候会失败
printf("分配内存失败!\n");
exit(1);
}
printf("请输入一个整数:");
scanf("%d",ptr);
printf("你输入的整数是:%d\n",*ptr);//520
free(ptr);//释放
printf("你输入的整数是:%d\n",*ptr);//0
return 0;
}
3.内存泄露
导致内存泄露主要有两种情况:
- 一、隐式内存泄露(即用完内存块没有及时free函数释放)
- 二、丢失内存块地址
为防止内存泄露,我们要在使用完这块内存空间之后,立刻调用free函数释放(高级语言有垃圾回收机制,而C语言则没有)
int main(void){
while(1){
malloc(1024);//循环申请内存空间,并且没有及时释放,会导致内存爆掉
}
return 0;
}
4.calloc:申请并初始化一系列内存空间
函数原型:void *calloc(size_t nmemb,size_t size);
calloc函数在内存中动态申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为nmemb*size),这些内存空间全部被初始化为0
calloc函数在申请完内存后,自动初始化该内存空间为零
5.realloc:重新分配内存空间
函数原型:realloc(void ptr,size_t size);
6.初始化内存空间
/**
以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中。
--memset-- 使用一个常量字节填充内存空间
--memcpy-- 拷贝内存空间
--memmove--
--memcpm-- 比较内存空间
--memchr-- 在内存空间汇总搜索一个字符
*/
二、内存布局
#include<stdio.h>
#include<stdlib.h>
int global_uninit_var;
int global_init_var1 = 520;
int global_init_var2 = 880;
void func(void);
void func(void){
;
}
int mian(void){
int local_var1;
int local_var2;
static int static_uninit_var;
static int static_init_var = 456;
char *str1 = "I love FishC.com!";
char *str2 = "You are right!";
int *malloc_var = (int *)malloc(sizeof(int));
printf("addr of func -> %p\n",func);
printf("addr of str1 -> %p\n",str1);
printf("addr of str2 -> %p\n",str2);
printf("addr of global_uninit_var -> %p\n",global_uninit_var);
printf("addr of global_init_var1 -> %p\n",global_init_var1);
printf("addr of global_init_var2 -> %p\n",global_init_var2);
printf("addr of static_init_var -> %p\n",static_init_var);
printf("addr of static_uninit_var -> %p\n",static_uninit_var);
printf("addr of local_var1 -> %p\n",&local_var1);
printf("addr of local_var2 -> %p\n",&local_var2);
}
代码段(Text segment) 通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常量。
数据段(Initialized data segment) 通常用来存放已经初始化的全局变量和局部静态变量。
BSS段(Bss segment/Uninitialized data segment) 通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称,这个区段中的数据在程序运行前将被自动初始化为数字0。
堆:是用来存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩展或缩小。当进程调用malloc等函数分配内存是,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。
栈:大家平时可能经常听到堆栈这个词,一般指得就是这个栈。栈是函数执行的内存区域,通常和堆共享一片区域。
堆和栈的区别
一、申请方式:
--堆是由程序员手动申请
--栈是由系统自动分配
二、释放方式:
--堆是由程序员手动释放
--栈由系统自动释放
三、生存周期:
--堆的生存周期由动态申请到程序员主动释放为止,不同函数之间均可自由访问
--栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能相互访问
四、发展方向:
--堆和其他区段一样,都是从低地址向高地址发展
--栈则相反,是由高地址向低地址发展
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 图(Graph)的定义,什么叫图?
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论