一、内存映像
计算机运行一个程序前,操作系统先将硬盘里的可执行程序代码装载到计算机的内存中,然后运行内存中的程序。
装载后程序在运行的过程中会占据内存中的一块区域,等到程序(代码)执行完毕,操作系统会将该区域自动释放作为任意调遣的空闲空间。
此片由硬盘调出,装载到内存的区域即为内存映像。
内存映像分区:
内存映像按照功能可以分为三个区域:(三个区域可能并非如图所示的连续分布)
(1)代码(程序)区:存放可执行的程序指令。
(2)静态存储区:存放永久(静态全局)数据区域。分为常量区和静态变量区。
常量区:顾名思义,存放常量。
静态变量区:存放全局变量和静态变量(目前还未遇到)
(3)动态存储区:存放临时(动态局部)数据的区域。分为栈区和堆区。
栈区:空间大小有限,存放自动变量,即未作说明(或auto)的局部变量,包括函数形式参数。
堆区:空间非常大,存放动态变量(也是局部变量),适合存放大数组。
二、动态内存分配函数
需要头文件:#include<stdlib.h>
void* malloc (unsigned int size); | 向系统申请大小为size的内存块把首地址返回, 若申请不成功则返回NULL | p=(float *)malloc(m*sizeof(float))) |
void* calloc(unsigned int num,unsigned int size); | 向系统申请num个size大小的内存块 把首地址返回,若申请不成功则返回NULL | p=(float *)calloc(m,sizeof(float))) |
三、使用演示
输入:数字n
输出:从1到n的动态存储序列
代码:
#include<stdio.h>
#include<stdlib.h>
//动态分配10个int单位内存,分别演示自增方式和偏移方式(下标省略,原因和偏移类似,不必重复)
int main() {
printf("让我们嗨起来好吗\n");
system("pause");
int n = 10; //动态变量
int i=0; //计数器
int*p,*q;
p=q= (int*)calloc(n,sizeof(int)); //动态内存分配
if (p == NULL) {
printf("动态内存分配失败\n");
}
else {
printf("p的初始内存是%d\n",p); //指针自增方式
for (i = 0; i < n; i++,p++) {
*p = i + 1;
printf("%d\n%d\n",*p,p);
printf("下标序号是%d\n",(p-q));
}
free(q);
p = NULL;
}
int* h;
h= (int*)calloc(n, sizeof(int)); //指针偏移方式
if (h == NULL) {
printf("动态内存分配失败\n");
}
else {
for (i = 0; i < n; i++) {
*h = i + 1;
printf("%d\n%d\n", *h, h);
}
free(h);
p = NULL;
}
system("pause");
return 0;
}
1.指针自增方式需要布置两个指针:一个用与移动,一个用于释放,因为内存释放的时候必须指向首(p[0])地址
2.内存要确保分配成功后才能使用
3.内存分配成功后要及时初始化
4.内存分配成功并且初始化后要避免越界使用
5.要及时释放内存:动态分配内存和释放成对出现,并且往往出现在程序的首尾,否则会用完,虽然总量很大
6.动态内存释放后避免再次访问空间,防止方法为内存释放后赋予指针NULL,相应动态内存将会永远迷失