静态变量求x n c语言,c语言在内存中的分布

参考文章https://www.cnblogs.com/yif1991/p/5049638.html

存储时结构

首先写一个c语言版的Hello World

#include

void main()

{

printf("hello,world\n");

}

将该段程序写在一个hello.c的文件中。打开终端,编译hello.c生成一个a.out的文件。

b9fb850f223132ee68172982e0481d66.png

终端上展示的是一个c语言的可执行文件在不同的内存所占的空间,text、data、bss分别代表内存中不同的区域,dec代表十进制总和,hex代表着16进制总和,filename代表着文件名。

text 代码区。

程序被操作系统加载到内存的时候,所有的可执行代码(程序代码指令、常量字符串等)都加载到代码区,这块内存在程序运行期间是不变的。代码区是平行的,里面装的就是一堆指令,在程序运行期间是不能改变的。函数也是代码的一部分,故函数都被放在代码区,包括main函数。

注意:“int a = 0;”语句可拆分成”int a;”和”a = 0”,定义变量a的”int a;”语句并不是代码,它在程序编译时就执行了,并没有放到代码区,放到代码区的只有”a = 0”这句。

静态区

该区包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)

int x = 99;

static x = 100;

未初始化数据区

BSS区(uninitialized data segment)

BSS区的数据在程序开始执行之前被内核初始化为0或者空指针(NULL)

int x;

以上为可执行代码存储时结构。

运行时结构

运行时结构多个栈区和堆区。

09bdd0eda08b86b938ab44b357b381a8.png

栈(stack)

一种先进后出的内存结构,局部变量(自动变量)和函数形式参数都存储在此,存储的这个动作由编译器自动完成,写程序时不需要考虑。

栈区在程序运行期间是可以随时修改的。当一个自动变量超出其作用域时,自动从栈中弹出。

每个线程都有自己专属的栈。

栈的最大尺寸固定,超出则引起栈溢出。

变量离开作用域后栈上的内存会自动释放。

下面这个例子可以看出地址分配规律。

#include

int n = 0;

void test(int a, int b);

int main() {

static int m = 0;

int a = 0;

int b = 0;

printf("自动变量a的地址是:%d\n自动变量b的地址是:%d\n", &a, &b);

printf("全局变量n的地址是:%d\n静态变量m的地址是:%d\n", &n, &m);

test(a, b);

printf("main函数的地址是:%d", &main);

}

void test(int x, int y)

{

printf("形式参数x的地址是:%d\n形式参数y的地址是:%d\n",&x, &y);

}

运行结果如下:

bb9efda1cbdb9d494ff8c23c71c71c53.png

由运行结果可以知道局部变量和形参地址相似,存储在一个内存区;全局变量和静态变量地址相似,存储在一个区。根据运行结果中a,b,x,y的地址值大小可以还原占内存的内存分配原理。局部变量按照执行顺序入栈,函数参数的入栈顺序是从右到左。

f98f29852c51637766fdafdb485effe5.png

内存与指针

#include

int *getx()

{

int x = 10;

return &x;

}

int main()

{

int *p = getx();

printf("%d\n", *getx());

printf("%d\n", *p);

*p = 20;

printf("%d\n", *p);

}

这段代码没有任何语法错误,编译也可以正常通过。因为int *p = getx()中变量x的作用域为getx()函数体内部,这里得到一个临时栈变量x的地址,getx()函数调用结束后这个地址就无效了。所以有关于这个地址的任何操作都不一定成立了。

栈不会很大,一般都是以K为单位。如果在程序中直接将较大的数组保存在函数内的栈变量中,很可能会内存溢出,导致程序崩溃。比较大的内存就要用到堆(heap)内存了。

堆(heap)

堆是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。更重要的是堆是一个大容器,它的容量要远远大于栈,这可以解决上面实验三造成的内存溢出困难。一般比较复杂的数据类型都是放在堆中。

在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。对于一个32位操作系统,最大管理管理4G内存,其中1G是给操作系统自己用的,剩下的3G都是给用户程序,一个用户程序理论上可以使用3G的内存空间。堆上的内存必须手动释放(C/C++)

malloc与free

malloc函数用来在堆中分配指定大小的内存,单位为字节(Byte),函数返回void *指针。

free负责在堆中释放malloc分配的内存。malloc与free一定成对使用。

#include

#include "stdlib.h"

#include "string.h"

void print_array(char *p, char n)

{

int i = 0;

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

{

printf("p[%d] = %d\n", i, p[i]);

}

}

int main()

{

char *p = (char *)malloc(1024*1024*1024);//在堆中申请了内存

memset(p, 'a', 10);//初始化内存

int i = 0;

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

{

p[i] = i + 65;

}

print_array(p, 10);

free(p);//释放申请的堆内存

}

运行结果如下:

1f6a6f48161efa1f826404f0b67476bb.png

改造占内存中那个以指针作为返回值的getx()的例子,改为申请堆内存,即可完成需求,但一定用通过free函数释放申请的堆内存空间。改造以后的函数如下:

#include

#include "stdlib.h"

#include "string.h"

int *getx()

{

int *p = (int *)malloc(sizeof(int));//申请了一个堆空间

return p;

}

int main()

{

int *pp = getx();

*pp = 10;

printf("%d\n", *pp);

free(pp);

}

用来在堆中申请内存空间的函数还有calloc和realloc,用法与malloc类似。文章地址:https://www.cnblogs.com/lidabo/p/4611411.html

动态创建数组,则用堆。

#include

#include "stdlib.h"

int main() {

int len;

int * arr;

printf("请输入数组长度:");

scanf("%d", &len);

arr = (int *)malloc(sizeof(int)*len);

printf("请输入数组的值:");

for ( int i = 0; i < len; i ++) {

scanf("%d", &arr[i]);

}

for (int j = 0; j < len; j ++) {

printf("%d:%d ", j , arr[j]);

}

free(arr);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值