2 动态分配内存
2.1 什么是动态分配内存?为什么要分配内存?
通常我们的变量都是预先分配的,系统自动给分配和回收的。
- 什么是动态分配内存
程序执行的过程中,动态地分配或者回收存储空间的分配内存的方法。 - 为什么要动态分配内存
当声明一个数组时,必须用一个常量指定数组的长度,但是数组的长度往往在运行时才知道。这是由于数组所需要的内存空间取决于输入数据。
2.2 如何使用动态分配内存
C99可以使用变量作为数组定义的大小,在C99之前只能使用动态分配内存实现。
int arr[n];
近似于
int* arr = (int*)malloc(n*sizeof(int));
// 操作arr如同操作int arr[n]
free(arr);
2.3 申请动态分配内存malloc()
stdlib.h
中定义函数void* malloc(size_t size)
,向系统申请大小为size
的内存空间。返回结果是void*
,使用时转换成需要的指针类型。如果申请失败,返回NULL
。
- 初始化动态分配内存
申请动态内存内的值为?
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
scanf("%d",&n);
int* arr = (int*)malloc(sizeof(int)*n);
for(int i = 0;i < n;++i){
printf("%d ",arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
3
0 0 0
2.4 释放动态分配内存free()
free()
归还申请的内存
free()
避坑
1、忘记free()
2、修改了申请地址,然后free()
int* arr = (int*)malloc(n*sizeof(int));
free(arr+1);
3、多次free()
int* arr = (int*)malloc(n*sizeof(int));
free(arr);
free(arr);
4、free()
非malloc
内存。
int n = 0;
free(&n);
- 实例1:数组
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
scanf("%d",&n);
int* arr = (int*)malloc(sizeof(int)*n);
for(int i = 0;i < n;++i){
scanf("%d",&arr[i]);
}
for(int i = 0;i < n;++i){
printf("%d ",arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
实例2:字符数组
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
scanf("%d",&n);
char* arr = (char*)malloc(sizeof(char)*n);
if(NULL == arr){
return 1;
}
getchar();
for(int i = 0;i < n;++i){
scanf("%c",&arr[i]);
}
for(int i = 0;i < n;++i){
printf("%c ",arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
2.5 申请动态分配内存calloc()
,初始化为0
C 库函数 void *calloc(size_t nitems, size_t size)
分配所需的内存空间,并返回一个指向它的指针。
clloc()
和malloc()
区别:
malloc函数:不能初始化所分配的内存空间,在动态分配完内存后,里边数据是随机的垃圾数据。
calloc函数:能初始化所分配的内存空间,在动态分配完内存后,自动初始化该内存空间为0。
int* arr = (int*)calloc(n,sizeof(int));
free(arr);
类似于
int arr[n] = {0};
申请到的内存通常不总是空的,通常要初始化,采用以下方式:
int* arr = (int*)malloc(n*sizeof(int));
memset(arr,0,n*sizeof(int));
free(arr);
- 实例:创建一个可以一直输入的数组arr
#include <stdio.h>
#include <stdlib.h>
int main(){
int n = 0;
int* arr = NULL;
int m;
for(;;){
int res = scanf("%d",&m);
if(EOF ==res) break;
if(0 == n){
arr = calloc(1,sizeof(int));
}else{
arr = realloc(arr,sizeof(int)*(n+1));
}
arr[n] = m;
++n;
}
for(int i = 0;i < n;++i){
printf("%d ",arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
2.6 重新调整内存大小realloc()
void* realloc (void* ptr, size_t size);
- 1、如果当前内存段后面有足够的内存空间,那么就直接扩展这段内存,realloc()返回原来的首地址;
- 2、如果当前内存段后面没有足够的内存空间,那么系统会重新向内存树申请一段合适的空间,并将原来空间里的数据块释放掉,而且realloc()会返回重新申请的堆空间的首地址;
- 3、如果创建失败,返回NULL, 此时原来的指针依然有效;
- 实例:创建一个可以一直输入的数组arr
#include <stdio.h>
#include <stdlib.h>
int main(){
int n = 0;
int* arr = NULL;
int m;
for(;;){
int res = scanf("%d",&m);
if(EOF ==res) break;
arr = realloc(arr,sizeof(int)*(n+1));
arr[n] = m;
++n;
}
for(int i = 0;i < n;++i){
printf("%d ",arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
}
2.7 分配内存小结
函数 | 作用 |
---|---|
malloc() | 分配内存块,不初始化 |
calloc() | 分配内存块,初始化为0 |
realloc | 调整先前分配的内存块大小 |
free() | 释放分配内存块 |
- 实例:二维数组申请内存方式
#include <stdio.h>
#include <stdlib.h>
int main(){
int n,m;
scanf("%d%d",&n,&m);
int** parr = malloc(n*sizeof(int*));
for(int i = 0;i < n;++i){
parr[i] = malloc(sizeof(int)*m);
for(int j = 0;j < m;++j){
scanf("%d",&parr[i][j]);
}
}
for(int i = 0;i < n;++i){
for(int j = 0;j < m;++j){
printf("%d ",parr[i][j]);
}
printf("\n");
}
free(parr);
parr = NULL;
}
2.8 标准库中相关函数
函数 | 作用 |
---|---|
memset() | 填充内存 |
memcpy() | 内存拷贝 |
memmove() | 内存移动 |
memcmp() | 内存比较 |
memchr() | 查找内存中第一个出现指定字符的位置 |
- 实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
int arr1[5] = {1,2,3,4,5};
int arr2[5];
memcpy(arr2,arr1,sizeof(arr1));
printf("arr2: ");
for(int i = 0;i < 5;++i){
printf("%d ",arr2[i]);
}
printf("\n");
memset(arr2,-1,sizeof(int)*3); //依靠二进制进行赋值,只能赋0和-1
printf("arr2: ");
for(int i = 0;i < 5;++i){
printf("%d ",arr2[i]);
}
printf("\n");
if(memcmp(arr1,arr2,sizeof(arr1)) == 0){
printf("arr1 == arr2\n");
}else{
printf("arr1 != arr2\n");
}
memmove(arr1,arr2,sizeof(int)*3);
printf("arr1: ");
for(int i = 0;i < 5;++i){
printf("%d ",arr1[i]);
}
printf("\n");
}
arr2: 1 2 3 4 5
arr2: -1 -1 -1 4 5
arr1 != arr2
arr1: -1 -1 -1 4 5