为什么你的 C 语言程序总是崩?可能是动态内存没搞懂

malloc :

malloc:void* malloc(size_t size);

申请空间 ->设置这片空间的开始周期

  • size:要申请多少字节
  • size_t:无符号整数类型(专门用来表示大小、长度、个数)
  • 返回值:  成功 → 返回内存首地址                  失败 → 返回 NUL

举例:

    int* p = (int*)malloc(40);

申请 40 字节堆内存,用 int 指针 p 接收*

3 条铁律

  1. malloc 申请的是堆内存
  2. 必须判断是否 == NULL
  3. 必须手动 free,否则内存泄漏

calloc:

callocvoid* calloc(size_t num, size_t size

  • num:元素个数
  • size:单个元素字节大小总字节数 = \(num \times size\)
  1. 从堆区申请内存
  2. 自动把内存全部初始化为 0
  3. 返回 void*,使用要强转类型

举例:

int *p = (int*)calloc(5, sizeof(int));

申请5个int空间,初始全0


malloc与calloc:

1.calloc功能和malloc一模一样:在堆区申请一片空间设置这个空间的出生周期

2.区别一:malloc申请size个字节 calloc申请num*size个字节

3.区别二:malloc对所有的字节按照cd进行填充 calloc对所有的字节按照00进行填充


malloc与calloc申请空间判断是否合法

#include<stdio.h>
#include<stdlib.h>
int main() {
    int* p = (int*)malloc(40);
    if (p==NULL) {
        printf("申请空间不足\n");
        return 0;
    }
    printf("扩容前:%p\n",p);

    int* q = (int*)realloc(p, 80);
    if (q == NULL) {
        printf("扩容空间不足\n");
        return 0;
    }
    printf("扩容后:%p\n", q);

    return 0;
}

realloc:

realloc:void* realloc(void* ptr, size_t new_size);

ptr:原来 malloc / calloc / realloc 出来的指针

size_t:无符号整数类型(专门用来表示大小、长度、个数)

new_size:新的总大小(不是增加多少!)

返回值:新内存的地址

三种工作情况

  1. 原内存后方空闲空间充足原地扩容,地址不变
  2. 后方空间不足:新开辟内存,自动拷贝旧数据,释放旧内存,返回新地址
  3. 扩容失败:返回 NULL,原内存保留不动

free:

free:void free(void* ptr);

void* ptr接收任意类型的指针

free:释放你用 malloc / calloc / realloc 申请的堆内存

你可以把堆内存想象成:你租的一间房子

malloc = 租房子

realloc = 换更大/更小的房子

free = 退房


free(p);

p = NULL;

free (p) 后不写 p=NULL,语法没错,但非常危险!

  • free(p) = 归还内存
  • p 本身的值没变 → 变成野指针
  • free 之后 p 变成 野指针你再用 *pp[i]

    就是:非法闯入别人的房子!

free的正确释放

free只可释放堆区的第一个(起始)地址

free : 释放空间,设置这片空间的结束周期.

free 只是释放内存不是结束程序!

例题用realloc1~10扩容至1~20:

#include<stdio.h>
int main() {
    // 堆区申请空间 40Byte(1~10)
    int* p = (int*)malloc(40);
    if (p == NULL) {
        printf("申请空间太大 申请失败\n");
        return;
    }
    
    for (int i = 0; i < 10; i++) p[i] = i + 1;
    printf("扩容前:"); 
    for (int i = 0; i < 10; i++) printf("%d ", p[i]); 
    printf("\n");
    
    // 扩容 需要放1~10 + 11~20
    int* q = (int*)realloc(p, 80);
    if (q == NULL) {
        printf("扩容空间太大 申请失败\n");
        return 0;
    }

    // 核心:更新指针
    p = q;//将第一个地址都给p
    q = NULL;//销毁q的地址 置空

    for (int i = 10; i < 20; i++) p[i] = i + 1;
    printf("扩容后:"); 
    for (int i = 0; i < 20; i++) printf("%d ", p[i]); 
    printf("\n");

    if (p == q) {
        printf("p之前40Byte后续还有连续空余的40Byte\n");
    }

    // 释放空间
    free(p);
    // 将之前保存的地址彻底抹去,避免发生非法访问
    p = NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值