二、C语言进阶:动态分配内存

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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值