c语言内存存储区,[转载]C语言中的内存存储区

一般认为在C中分为这几个存储区:

1.栈:由编译器自动分配并释放内存空间,如局部变量,函数参数等;

2.堆:一般由程序员分配释放内存空间(如C语言中的malloc和C++中的new)。若程序员不释放,程序结束时可能由OS回收。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问,比如以下语句:

#include

struct node

{

int a;

int b;

};

int main(void)

{

struct node *p;//如果改为“struct node p;”,下一条语句改为“p=(struct node )malloc(sizeof(struct node));”,程序运行会出错

p=(struct node *)malloc(sizeof(struct node));

return 0;

}

3.全局区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和初始化的静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。如程序外声明的全局变量,static声明的静态变量就存放在该区。在C++中是不区分初始化区和未初始化区的。程序结束释放。

4.还有一块常量区。它是静态区的一部分,主要存放常量(如const声明的常量数据),形如“abcdef”的字符串字面值也存放在此处。

5.register声明的变量存放在寄存器中,寄存器不在内存中,而是比内存更接近CPU,因此执行效率更高。但每一台电脑的寄存器个数是有限的,其存储的变量也是有限的。

比如:

int a = 0; //全局初始化区

char *p1; //全局未初始化区

main()

{

int b; //栈区

char s[] = "abc";

//abc在内存中共有两个,一个是字符串字面值“abc ”,存放在常量区;另一个是字符

数组s[],其数组内也存放着“abc ”,但它们被存放在栈中。

char *p2; //栈区

char *p3 = "123456";

//“123456 ”作为字符串字面值在常量区,p3在栈区

static int c = 0;

//全局(静态)初始化区

p1 = (char *)malloc(10); p2 =

(char *)malloc(20); //分配得来的10和20字节的区域就在堆区。

}

除此之外,还应注意以下几点:

1. 栈是先入后出的,由高地址向低地址生长,堆是由低地址向高地址生长,详细介绍请参照数据结构。运行以下程序就一目了然了:

#include

#include

struct node

{

int

a;

int

b;

int

c;

int

d;

};

int main(void)

{

struct node

*m;

int

e;

int

f;

int

g;

int

h;

m=(struct node

*)malloc(sizeof(struct node));

puts("堆的存储:由低地址到高地址");

printf("m->a的地址:%dn",&m->a);

printf("m->b的地址:%dn",&m->b);

printf("m->c的地址:%dn",&m->c);

printf("m->d的地址:%dn",&m->d);

puts("栈的存储:由高地址向低地址");

printf("e的地址:%dn",&e);

printf("f的地址:%dn",&f);

printf("g的地址:%dn",&g);

printf("h的地址:%dn",&h);

return

0;

}

2.栈的空间大小是有限的,VC默认是2M。栈不够用的情况一般是程序中分配了大量数组和递归函数的层次太深。有一点必须知道,当一个函数调用完返回后它会释放该函数中所有的栈空间。还应注意,当函数执行完毕后并不是立刻释放它开辟的栈空间,而是将栈数据继续留在内存中以保留现场,直到调用另一个函数时栈空间才被清空。请看以下程序:

#include

int *fun()

{

int *p,a=3;

p=&a;

return p;

}

int main(void)

{

int *p;

p=fun();

printf("%dn",*p);

return 0;

}

当执行完fun()函数之后,存放在栈中的局部变量a理应被释放,但输出结果仍然是3,也就是说p所指向的地址中仍然保存着a的数据,即保存现场(但当函数一旦执行返回值操作,存放在栈中的自动变量(即a)就失效了(见以下注意5),因此在程序外引用a仍是无效的)。但如果对程序做以下修改,结果就不同了:

#include

int *fun()

{

int *p,a=3;

p=&a;

return p;

}

int main(void)

{

int *p;

p=fun();

printf("%dn",*p);

printf("%dn",*p);

return 0;

}

你会看到,程序输出的第一个*p的结果为3,但第二个*p的结果却为1245056,是个无效值。说明当调用新函数printf()之后,原函数中的栈数据被释放了。

3.在栈上存取数据比通过指针在堆上存取数据效率高。

4.堆是动态分配内存的,并且你可以分配使用很大的内存。但是用不好会产生内存泄露。并且频繁地调用malloc()和free()会产生内存碎片,而栈不会产生碎片。

5.堆(heap)和栈是C/C++编程不可避免会碰到的两个基本概念,他们都是基本的数据结构。具体地说,现代计算机(串行执行机制)都直接在代码底层支持栈的数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成数据入栈出栈的操作。这种机制的特点是效率高,支持的数据有限,一般是整数、指针、浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。因为栈的这种特点,对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈,然后跳转至子程序地址的操作,而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转的操作。C/C++中的自动变量是直接利用栈的例子,这也就是为什么当函数返回时,该函数的自动变量失效的原因。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一些思路。 首先,虚拟存储内存工作是两个不同的概念。虚拟存储是指计算机系统为了满足进程地址空间需要而提供的一种抽象的存储器模型,其大小可能远大于实际可用的物理内存。而内存工作是指实际可用的物理内存域。 在C语言,可以使用结构体来表示虚拟存储内存工作。例如: ```c // 虚拟存储结构体 typedef struct { int size; // 存储大小 int *data; // 存储数据 } VirtualMemory; // 内存工作结构体 typedef struct { int size; // 工作大小 int *data; // 工作数据 } MemoryWorkspace; ``` 然后,可以使用动态内存分配函数`malloc`来为虚拟存储内存工作分配内存空间。例如: ```c // 创建一个大小为100的虚拟存储 VirtualMemory *vm = (VirtualMemory *)malloc(sizeof(VirtualMemory)); vm->size = 100; vm->data = (int *)malloc(vm->size * sizeof(int)); // 创建一个大小为50的内存工作 MemoryWorkspace *mw = (MemoryWorkspace *)malloc(sizeof(MemoryWorkspace)); mw->size = 50; mw->data = (int *)malloc(mw->size * sizeof(int)); ``` 接下来,您可以实现一些操作虚拟存储内存工作的函数,例如读取和写入数据: ```c // 从虚拟存储读取数据 int readFromVirtualMemory(VirtualMemory *vm, int address) { if (address >= vm->size) { // 超出虚拟存储范围 return -1; } return vm->data[address]; } // 向虚拟存储写入数据 void writeToVirtualMemory(VirtualMemory *vm, int address, int value) { if (address >= vm->size) { // 超出虚拟存储范围 return; } vm->data[address] = value; } // 从内存工作读取数据 int readFromMemoryWorkspace(MemoryWorkspace *mw, int address) { if (address >= mw->size) { // 超出内存工作范围 return -1; } return mw->data[address]; } // 向内存工作写入数据 void writeToMemoryWorkspace(MemoryWorkspace *mw, int address, int value) { if (address >= mw->size) { // 超出内存工作范围 return; } mw->data[address] = value; } ``` 当然,以上只是一个简单的示例。实际上,虚拟存储内存工作的实现会更加复杂,可能需要考虑分页、置换等问题。但是,以上代码可以为您提供一个基本的思路。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值