[C.C++] C语言程序内存结构,内存结构 - C 语言程序设计

300 0
Honkers 2025-5-23 18:47:52 来自手机 | 显示全部楼层 |阅读模式

内存结构

一个C 程序本质上都是由BSS(Block Started by Symbol) 段、Data 段、Text 段三个组成的。

BSS 段:在采用段式内存管理的架构中,BSS 段(Block Started by Symbol)通常是指用来存放程序中

未初始化的全局变量的一块内存区域。BSS 是英文Block Started by Symbol 的简称。BSS 段属于静态内存

分配,即程序一开始就将其清零了。比如,在C 语言之类的程序编译完成之后,已初始化的全局变量保存

在.data 段中,未初始化的全局变量保存在.bss 段中。

数据段:在采用段式内存管理的架构中,数据段(data segment)通常是指用来存放程序中已初始化的

全局变量的一块内存区域。数据段属于静态内存分配。

代码段:在采用段式内存管理的架构中,代码段(text segment)通常是指用来存放程序执行代码的一

块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域属于只读。在代码段中,也有可

能包含一些只读的常数变量,例如字符串常量等。

text 和data 段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;而BSS 段不在可执行文件中,由系统初始化。

程序编译后生成的目标文件至少含有这三个段,这三个段的大致结构图如下所示:

其中data 段包含三个部分:heap(堆)、stack(栈)和静态数据区。

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc 等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free 等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static 声明的变量,static 意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

stack 段存放函数内部的变量、参数和返回地址,其在函数被调用时自动分配,访问方式就是标准栈中的LIFO 方式。(因为函数的局部变量存放在此,因此其访问方式应该是栈指针加偏移的方式)

malloc():申请一个内存空间

realloc():在已有空间基础上在增加部分内存空间

free():释放空间

动态内存的申请与回收

静态内存是由系统分配的,是栈内存中的连续内存空间,其运行效率非常高,且可以被系统自动回收。但是在某些情况下我们需要动态的申请一些内存空间,比如,在创建数组的时候我们不知道数组的长度是多少,那么我们就需要创建动态数组

动态内存是程序员手动申请的在堆内存中开辟的空间不一定是连续,,运行效率略慢,容易产生碎片需要手动回收

内存模型

void main()

{

int i = 0;

//指针数组

char * p1[] = {"123", "456", "789"};

//二维数组

char p2[3][4] = {"123", "456", "789"};

//手工二维内存

char **p3 = (char **)malloc(3 * sizeof(char *)); //int array[3];

for (i=0; i<3; i++)

{

p3 = (char *)malloc(10*sizeof(char)); //char buf[10]

sprintf(p3, "%d%d%d", i, i, i);

}

}

C语言与内存

程序 = 数据 + 算法

计算机运行程序的目的:得到一个结果;关注运行的过程

静态内存SRAM,动态内存DRAM

内存地址,内存单元(1个字节byte),内存编址是以字节位单位的

32位系统:32位数据线,32位地址线

三总线:地址总线,数据总线,控制总线

32位地址线:232 = 4G,地址线的数量决定了它可以寻址内存空间的大小

寄存器

register 寄存器,在CPU里面

void main()

{

//register int a = 3;

//&a;//地址是内存的地址,CPU没有地址

int a = 10;

int b; // b=a+5;

_asm // 内嵌汇编语言

{

mov eax, a

add eax, 5

mov b,eax

}

printf("%d", b);

getchar();

}

#include

#include

void test()

{

int a = 10;//自动分配,自动回收 ,栈的运行与更新非常快

printf("%p", &a);

printf("\n");

}

void main1()

{

test();

printf("\n\n");

test();

printf("\n\n");

//auto int a = 10;自动变量

getchar();

}

动态分配,链接的,内存碎片化,因此速度比栈(连续的内存,自动分配自动释放)慢

malloc() 只管分配,不管初始化

calloc() 会对内存进行清零

realloc()

free()

代码区

函数名存放的是函数的入口地址,回调函数,劫持

#include

#include

void gogogo()

{

printf("AAAAA\n\n\n\n");

}

void main1()

{

printf("%p", gogogo);//0x013A11A4,函数名存放函数的地址

//gogogo = gogogo;代码区只能读不可写

//void gogogo();

//void ()();

gogogo();//直接调用

void(*p)()=gogogo;

p();//间接调用

getchar();

}

void main()

{

char *p = "ABCDEFG";//p存储常量字符串的地址

printf("%d,%d\n", sizeof(p), sizeof("ABCDEFG"));

printf("\n%p", &p);//查看指针变量的地址

printf("\n%p", p);//查看字符串的地址

*p = 'a';//代码区只能读,常量字符串在代码区

getchar();

}

#include

#include

//导出函数,可以加载的时候调用

_declspec(dllexport) void go()

{

//函数指针类型必须一致,否则无法调用成功

//int ** 变量名挖掉就是类型

//间接调用的方式调用函数,根据地址来调用

void(*p1)(int a) = (void(*)(int a)) 0x2c10eb; // 函数类型:void(*)(int a)

p1(10);

void(*p2)() = (void(*)())0x2c111d;

p2();

}

静态区

全局变量存在静态区,可以跨文件使用,声明可以有多个,定义只能有一个

static修饰全局变量,限定全局变量只在c文件内使用

extern int num;

内存检索

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4013
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行