深入学习C


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,或者当你的分配的空间在函数结束后还需要存在。

1
2
3
4
5
6
7
8
9
10
11
12
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不能直接赋值

1
2
3
4
5
6
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:

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

4 小心野针

初始化一个指针的时候,切记要令其指向NULL;
在使用完成一个指针后,切记要进行free.
在free一个指针过后,切记要令其指向NULL


文章作者: 崔文耀
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 崔文耀 !
  目录