C语言之内存分区

1. 内存区域
  1. C编译的程序占用的内存分为以下几个区域
    • 代码区
    • 全局区/静态区
    • 栈区
    • 堆区
  2. 划分
    • 程序运行前: 代码区、全局区/静态区
    • 程序运行后:栈区、堆区
2. 内存四区
  1. 代码区

    作用:存放CPU执行的二进制机器指令

    特点:只读、共享

  2. 栈区

    栈是一种先进后出的内存结构,由编译器自动分配释放数据
    ​ 主要存放函数的形式参数值、局部变量等
    ​ 函数运行结束,相应栈变量会被自动释放
    ​ 栈空间较小,不适合将大量数据存放在栈中

    ​ 管理方式:编译器自动管理该区内存
    ​ 空间大小:提前规定、较小
    ​ 生命周期:函数使用完毕立即释放

    注意事项:不要返回局部变量的地址

    //栈区上开辟的数据由系统进行管理,不需要程序员管理开辟和释放
    int * func()
    {
    	int a = 10;
    	return &a;
    }
    //不管结果是否正确,这个值已经被释放了,不可以操作一块非法的内存空间
    void test01()
    {
    	int * p = func();
    
    	printf("a = %d\n", *p);
    	printf("a = %d\n", *p); 
    }
    
  3. 堆区

    堆区由开发人员手动申请和释放,在释放之前,该块堆空间可一直使用
    ​ 由程序员分配和释放,若程序员不释放,程序结束时由系统回收内存
    ​ 堆空间一般没有软限制,只受限于硬件。会比栈空间更大,适宜存放较大数据
    ​ 管理方式:开发人员手动申请和释放。
    ​ 空间大小:较大
    ​ 生命周期:手动释放之前一直存在,或程序结束由系统回收。
    注意事项:主调函数中没有给指针分配内存,被调函数需要利用高级指针进行分屏

    代码示例

    void allocateSpace(char * pp)
    {
    	char * temp = malloc(100);
    	memset(temp, 0, 100);
    	strcpy(temp, "hello world");
    	pp = temp;
    }
    
    void test02()
    {
    	char * p = NULL;
    	allocateSpace(p);
    	printf("%s\n", p);
    }
    

    解决方式1

    //利用返回值
    char* allocateSpace3()
    {
    	char *temp = malloc(100);
    	memset(temp, 0, 100);
    
    	strcpy(temp, "hello world");
    	return temp;
    }
    void test04()
    {
    	char *p = NULL;
    	p = allocateSpace3();
    	printf("%s\n", p);
    }
    

    解决方式2

    //利用高级指针
    void allocateSpac2(char ** pp)
    {
    	char * temp = malloc(100);
    	memset(temp, 0, 100);
    	strcpy(temp, "hello world");
    	*pp = temp;
    	printf("aaa%s\n", *pp);
    }
    
    void test03()
    {
    	char * p = NULL;
    	allocateSpac2(&p);
    	printf("%s\n", p);
    }
    

    内存申请我们可使用三个函数来完成,分别为:malloc、calloc、realloc,内存释放我们只需要使用 free 函数。

    1. malloc 函数:

      原型:void *malloc(unsigned int num_bytes)
      用法:分配长度为 num_bytes 字节的内存块。
      说明:如果分配成功则返回指向被分配内存的指针,否则返回 NULL
    2. calloc 函数:

      原型:void *calloc(int num_elems, int elem_size)
      用法:为具有 num_elems 个长度为 elem_size 元素的数组分配内存。
      说明:如果分配成功则返回指向被分配内存的指针,否则返回 NULL
    3. realloc 函数:

      原型:void *realloc(void *mem_address, unsigned int newsize)
      作用:改变 mem_address 所指内存区域的大小为 newsize 长度。
      说明:如果重新分配成功则返回指向被分配内存的指针,否则返回 NULL
    4. free 函数:

      原型:void free(void *p);
      作用:释放指针 p 所指向的的内存空间。
      说明:p所指向的内存空间必须是用 calloc,malloc,realloc 所分配的内存。如果 p 为 NULL则不做任何操作。
      

    calloc案例:

    void test01()
    {
    	int *p =  calloc(10,sizeof(int));  
    	for (int i = 0; i < 10; ++i)
    	{
    		p[i] = i + 1;
    	}
    	for (int i = 0; i < 10; ++i)
    	{
    		printf("%d\n", p[i]);
    	}
    	if (p != NULL)
    	{
    		free(p);
    		p = NULL;
    	}
    }
    

    realloc案例:

    void test02()
    {
    	int *p = malloc(sizeof(int)* 10);
    	for (int i = 0; i < 10; ++i)
    	{
    		p[i] = i + 1;
    	}
    	for (int i = 0; i < 10; ++i)
    	{
    		printf("%d ", p[i]);
    	}
    	printf("%d\n", p);
        
    	p = realloc(p, sizeof(int)* 200);   
    	printf("%d\n",p);
    
    	for (int i = 0; i < 15; ++i)
    	{
    		printf("%d ", p[i]);
    	}
    }
    
  4. 全局/静态区

    全局/静态区存储全局变量、静态变量、常量,该区变量在程序运行期间一直存在

    程序结束由系统回收

    ​ 已初始化的数据放在data段,未初始化的数据放到bss段

    ​ 该区变量当未初始化时,会有有默认值初始化

    ​ 管理方式:编译器自动管理该区内存
    ​ 生命周期:程序结束释放

    全局变量

    extern int g_a = 10; //c语言中 默认全局变量前 加了关键字 extern
    
    void test01()
    {
    	extern int g_a;
    	printf("g_a = %d\n", g_a);
    }
    

    静态变量

    void func()
    {
    	static int s_a = 10; //静态变量只初始化一次
    	s_a++;
    	printf("%d\n", s_a);
    }
    
    void test03()
    {
    	func();
    	func();
    	func();
    }
    void test04()
    {
    	static int s_a; //如果未初始化,默认为0
    	printf("%d\n", s_a);
    }
    

    常量

    const修饰的变量:

    //全局常量
    const int a = 10; //全局常量存放到常量区,收到常量区的保护
    
    void test01()
    {
        //a = 20; //直接修改失败
    	int * p = &a;
    	*p = 30;  //间接修改 语法通过,运行失败
    	printf("a = %d ", a); 
    
    
    	//局部常量
    	const int b = 10; //b分配到了栈上,可以通过间接方式对其进行修改
    	//b = 30; //直接修改失败
    	int * p2 = &b;
    	*p2 = 30;
    	printf("b = %d\n", b); //间接修改成功,C语言下const修饰的局部常量为伪常量
    }
    
    结论: 全局修改失败,局部修改成功
    

    字符串常量:

    //1、字符串常量 是可以共享的
    void test01()
    {
    	char * p1= "hello world";
    	char * p2 = "hello world";
    	char * p3 = "hello world";
    	printf("%d\n",&"hello world");
    	printf("%d\n", p1);
    	printf("%d\n", p2);
    	printf("%d\n", p3);
    }
    
    //2、vs下 不可以修改字符串常量中的内存
    void test02()
    {
    	char * p1 = "hello world";
    	printf("%d\n", p1);
    	printf("%c\n", p1[0]);
    	//p1[0] = 'W'; //不允许修改 常量区内容
    }
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值