深入学习C

本文详细介绍了C语言中的内存管理,包括malloc、calloc、realloc和free函数的使用。讲解了如何在堆上动态分配和释放内存,以及realloc的常见陷阱和注意事项。强调了手动内存管理的重要性以及指针在函数参数传递中的行为。
摘要由CSDN通过智能技术生成

title: 深入学习C
tags: [C]
categories:

  • C
    date: 2021-07-01 21:12:45

C

内存管理

内存管理函数

  1. void *malloc(int num);
    

在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。

  1. void *calloc(int num, int size);
    

在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是0。

  1. void *realloc(void *address, int newsize);
    

该函数重新分配内存,把内存扩展到 newsize。

  1. void free(void *address);
    

该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。

关于 realloc 的坑

1、realloc失败的时候,返回NULL

2、realloc失败的时候,原来的内存不改变,不会释放也不会移动

3、假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉, realloc返回新内存的地址。

4、如果size为0,效果等同于free()。

5、传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的,或者是NULL

6、传递给realloc的指针可以为空,等同于malloc。

如果在连续的realloc中,有一次的size==0,则相当于free了目标指针,则这个指针就变成了野指针,继而在下一次realloc中,就会报错

记住,内存分配一定不要忘记size是 num*sizeof(type)

QUS

1

什么情况下指针需要使用malloc分配内存,什么时候不需要

1.在c语言中,内存模型分为栈和堆。

2,这两种模型内存的方式是不同的,在栈中存放的变量是由系统自动管理的,在函数结束后系统会自动释放,不需要人为的进行任何操作。

3,而在堆中存放的是用户自己管理的内存,手动分配的,malloc建立,系统不会在函数体执行结束后自动释放,需要用户手动释放通过free函数。

当你对分配的空间进行自己的管理和释放需要使用malloc,或者当你的分配的空间在函数结束后还需要存在。

int * create()
{
    int *p = (int*)malloc(sizeof(int));//此时在堆中建立了存放int的空间。

    *p=2;
    returen p;
}
int main()
{
    int *a = create();//此时执行完后 刚刚在函数体内用malloc分配的空间还在,还存着2。
    printf("%d",*a);//输出2
}
2

为什么可以对 malloc函数声明 的*p直接赋值 而 对 int *p声明中的*p不能直接赋值

int * p = (int *)malloc(sizeof(int));                   
此时p是一个int指针,它指向malloc分配给他的一个地址,此地址已经有意义,只是这个地址内部的值还是随机的,比如我们认为p=0x1234              
*p = 20;                
此时往0x1234这个地址内部放入一个int数,完全OK的操作         
但是int * q, 仅仅定义了q是一个int型的地址,但是q此时是随机值(windows下一般为0xcccc),也就是俗称的野指针          
那么*p = 20; 的操作就是极度危险的,因为没人能预测你到底把这个20放到了系统的哪里,很可能会造成不可预测的破坏。           
3

紧紧抓住c语言形参与实参的关系,这样才能更好的使用指针

由于是值传递,所以传入指针的值,在函数中进行更改不会改变实参的数据。
eg:

Item itemsave;
GetItemLinkList(&list, 2, &itemsave);
//这个函数这样实现
//直接改变itemsave时改变形参,对外面的实参没有任何影响。  只有 *itemsave=    才会有作用。
itemsave = &(p->item);
//这样是不对的,以为函数中的itemsave只是一个形参,其指向的内存和传入的实参是一样的,但是这行代码又修改了itemsave的指向,对实参无法造成任何影响。
//必须改为这样
*itemsave=p->item;
//这样,直接修改 *itemsave就是在修改实参的值//
这也就是为什么说指针传入的值可以修改,不是说可以直接对指针进行修改,而是拿着传入的指针的值,由此得到指向的内存地址(实参的内存地址)然后就可以直接修改这块内存的值了,即修改实参。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值