C语言中的内存四区

C 语言中的内存四区

1 内存分区模型

C 程序运行时,操作系统将内存划分为4个区域:

1.栈区:由编译器自动分配和释放,存放函数的参数,局部变量等。

2.堆区:由程序员分配释放,若程序员未释放,则程序运行结束后,编译器自动释放。

3.全局区:存放全局变量,静态变量以及常量。

4.代码区:存放程序的二进制代码,由操作系统管理。

image-20220820150339383

2 栈区

栈区:存放函数的参数值、局部变量等,由编译器自动分配和释放,通常在函数执行完毕后释放。

2.1 案例代码

#include <stdio.h>
#include <stdlib.h>


char *pfunc1()
{
    //str是一个字符数组,开辟在栈区。
    char str[100] = "hehe123";
    return str;
}


int main()
{
    char *p = NULL;
    p = pfunc1();
    //打印p指向的内容,%s是打印地址所指向内存空间的数据
    printf("p = %s\n",p);

    return 0;
}

2.2 程序运行结果

image-20220820215258137

为什么会出现这样的运行结果那?

这个问题就是我们常说的由于返回局部变量的地址造成的。

2.3 程序运行分析

pfunc1函数在栈区,开辟一块内存,str数组在栈区开辟100个字节的大小。

字符串常量存储在全局区,因为str是一个字符数组,所以字符串的内容拷贝到数组里面,

pfunc1函数中将str的地址返回,main函数中的p1变量接收pfunc1函数的返回值。

pfunc1函数调用结束,开辟的栈区销毁,所以main函数中使用p1变量访问一个销毁的内存,结果出错。

image-20220820212513171

3 堆区

堆区由程序员使用malloc申请和free释放,若是程序员未释放,程序结束后由操作系统回收。

3.1 案例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


char *pfunc1()
{
    char *tmp = (char *)malloc(100);
    if(tmp == NULL)
    {
        return NULL;
    }

    strcpy(tmp,"hehe123");

    return tmp;
}


int main()
{
    int a = 0;
    char *p =pfunc1();
  	if(p != NULL)
    {
        printf("p = %s,p = %p\n",p,p);
        free(p);  
        p = NULL;  
    }
    return 0;
}

3.2 程序运行结果

image-20220820222038665

3.3 程序运行分析

pfunc1中使用malloc函数在堆区开辟一块内存,全局区上的字符串拷贝到堆区,tmp局部变量存在栈区上,

tmp指针指向的是堆区的地址,main函数中的p1变量接收pfunc1的返回值,p1指向堆区的地址,

所以pfunc1函数调用结束,tmp销毁后,使用p1依然能够正常访问。

image-20220820224705643

4 全局区

全局区:存放全局变量、静态变量、常量。

全局变量

静态变量,由static 修饰的全局变量,static 修饰的局部变量。

常量,包括字符串常量,const 修饰的全局常量,const修饰的局部常量不在全局区。

全局区可以细分为.bss段(未初始化)和.data段(已初始化)。

全局区在程序结束后由系统释放。

4.1 案例代码

#include <stdio.h>
#include <stdlib.h>


char *pfunc1()
{
    char *p1 = "hehe123";

    return p1;
}

char *pfunc2()
{
    char *p2 = "hehe123";

    return p2;
}


int main()
{

    char *p1 = NULL;
    char *p2 = NULL;

    p1 = pfunc1();
    p2 = pfunc2();

    //分别打印p1指向的内容和地址,%s是指打印指针所指向的内容
    printf("p1 = %s,p1 = %p\n",p1,p1);
    printf("p2 = %s,p2 = %p\n",p2,p2);

    return 0;
}

4.2 程序运行结果

image-20220820163615764

1.代码中char *p1 = “hehe123”;字符串是怎么存在指针里的?

字符串常量存放在全局区,指针变量存了字符串常量的地址。

2.分别在函数pfunc1和pfunc2里定义了一个相同的字符串,为什么在pfunc1和pfunc2里字符串地址是一样的。

字符串常量存在全局区,相同的字符串在全局区只开辟了一块空间存储字符串。不重复存这两个相同的字符串。

4.3 程序执行分析

main函数在栈区开辟一段内存,两个变量p1与p2开辟内存,pfunc1函数中变量p1、pfunc2函数中变量p2也在栈区开辟内存。

字符串存储在全局区,全局区的数据由操作系统管理,在程序运行结束后,自动回收。

pfunc1函数中的p1变量和pfunc2函数中的p2变量,存储的是字符串在全局变量的地址,然后通过函数返回给main函数中的变量p1、p2。在pfunc1、pfunc2函数调用结束后,这两个函数在栈区上的变量p1、p2也销毁。

main函数中的变量p1、p2变量存储着字符串的地址,由于字符串在全局区,所以通过p1、p2仍然可以正常访问。

image-20220820173120535

5 代码区

  1. ​ 代码区存放CPU执行的机器指令即程序汇编而成的二进制代码。
  2. ​ 代码区是共享的,对于频繁执行的程序,内存中只需要保存一份即可。
  3. ​ 代码区是只读的,只读的原因是防止程序意外修改了指令。
  • 30
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值