前言
C语言的数据和代码本身都需要存放在内存中,供处理器CPU执行,内存是按照字节编址的,程序通过显式或隐式方式访问内存。
程序执行的过程,从内存角度来看,有两种操作:
1)从内存读入数据;
2)修改数据保存到内存中。
C语言提供两种内存管理方式:
1)自动内存管理
2)动态内存管理。
自动内存管理
C程序中的各种类型变量、常量、函数、代码段、数组等,只要声明和定义,编译器会自动分配内存空间存放数据和代码,当程序执行完毕以后,自动回收这些内存空间,以免内存泄露。
内存泄露:指程序运行过程中,分配的内存未及时释放和回收,导致一直占用计算机内存空间,最终有可能完全消耗所有内存资源,导致计算机死机。
当然,强制退出程序,操作系统会自动释放该程序所有内存。
自动内存管理的优缺点:
优势:方便、简单,无需担心内存泄露问题,
缺点:不够灵活,无法动态分配内存空间,只能预分配固定大小的空间。
动态内存管理
动态内存管理,指通过<stdlib.h>
标准库函数手工申请内存和释放内存,内存分配可以在程序运行的过程中动态分配。
动态内存管理的优缺点
优势:灵活、可以根据用户输入和需要动态分配内存空间,
缺点:复杂、需要手工释放,否则会导致内存泄露,另外对释放后的内存指针访问,容易出现空指针错误。
动态内存管理相关函数
标准库<stdlib.h>中提供4个内存管理函数,实现动态内存管理功能。
#include <stdlib.h>
使用动态内存管理,需要添加该头文件。
1 申请分配内存函数:
void *calloc(size_t nmemb, size_t size);
//功能:申请一块 nmemb*size 大小(以字节为单位)的内存,内存空间的值自动初始化为二进制位0。
//参数nmemb:元素的个数,例如100个int型元素,此时nmemb=100。
//参数size:表示每个元素的大小,例如int型元素的大小,一般是4个字节。
//返回值:内存申请成功返回内存首地址的指针,失败返回NULL空指针。
2 释放内存函数:
void free(void *ptr);
//功能:释放一块ptr指向的内存空间。
//当ptr是NULL空指针时,则不执行任何操作。
//ptr取值应为calloc、malloc或realloc三个内存分配函数返回的指针。
3 内存分配函数(不会初始化为0):
void *malloc(size_t size);
//功能:直接分配一个元素的size大小的内存空间,内存空间的值不会自动初始化。
//返回值和calloc函数相同。
//calloc是同时申请多个元素的内存空间,malloc是申请一个元素的内存空间。
4 内存重新分配函数:
void *realloc(void *ptr, size_t size);
//功能:重新申请一块内存空间,调整之前申请内存空间的大小。
//参数和返回值与calloc函数一致。
//申请失败,原来内存空间ptr保持不变。
几种特殊情况:
•ptr为NULL时,realloc行为和malloc函数一致;
•ptr非空,size=0时,释放ptr指向的对象存储空间;
•size和之前的大小相等,则直接返回ptr;
•当增加内存空间时,无法在之前ptr直接扩展,则释放ptr,然后重新分配新的空间。
例如:展示以上内存分配函数使用,并且输出申请的内存区域首地址。
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *ptr1, *ptr2, *ptr3, *ptr4;
ptr1 = (int *)malloc(100 * sizeof(int));
printf("%p\n", ptr1);
ptr2 = (int *)malloc(100 * sizeof(int));
printf("%p\n", ptr2);
ptr3 = (int *)realloc(ptr1, 100 * sizeof(int));
printf("%p\n", ptr3);
ptr3 = (int *)realloc(ptr1, 1000 * sizeof(int));
printf("%p\n", ptr3);
ptr4 = (int *)realloc(NULL, 100 * sizeof(int));
printf("%p\n", ptr4);
free(ptr1);
free(ptr2);
free(ptr3);
free(ptr4);
return 0;
}
输出:
006A20D8
006A3278
006A20D8
006A3410
006A20D8
注意:
•如果新申请的内存空间大于原来的内存空间ptr,则原来内存空间的内存拷贝到新内存空间,增加的内存空间的值是不确定的;
•如果新申请的内存空间小于原理的内存空间ptr,则将拷贝原来内存空间的前半部分内容,其它内容丢失。
动态内存管理示例代码1
问题:用户输入的整数个数是不确定的,可能很大也可能很小,使用数组时,一般只能定义很大的数组。例如int a[10000]; 当输入的数字只有100个时,浪费99%空间;当输出整数个数超过10000时,数组溢出,无法保存,使用动态内存管理可以解决问题。
例如:以下程序实现动态输入不同个数的整数,此外还可以调整增加输入整数个数。
# include <stdio.h>
#include <stdlib.h>
int main(void){
int *ptr = NULL;
int i, num;
printf("请先输入你要输入整数的个数:");
scanf("%d", &num);
ptr = (int *)calloc(num, sizeof(int));
if (ptr != NULL){
for (i = 0; i < num; i++)
scanf("%d", ptr + i);
}
for (i = 0; i < num; i++)
printf("%d ", *(ptr + i));
printf("\n");
int num2;
printf("请输入你要新增的整数的个数:");
scanf("%d", &num2);
ptr = (int *)realloc(ptr, (num + num2) * sizeof(int));
if (ptr != NULL){
for (i = 0; i < num2; i++)
scanf("%d", ptr + num + i);
}
for (i = 0; i < num + num2; i++)
printf("%d ", *(ptr + i));
printf("\n");
free(ptr);
return 0;
}
运行结果如下:
输入:
请先输入你要输入整数的个数:5
10 9 8 7 6
输出:
10 9 8 7 6
输入:
请输入你要新增的整数的个数:3
5 4 3
输出:
10 9 8 7 6 5 4 3
程序分析:开始输入5个整数,打印出来,后来在原有输入基础上增加3个整数,一并打印输出。
-------------END-------------