C语言学习之动态内存分配第一讲

里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放


一、动态内存分配

    数组的元素存储于内存的连续位置,数组可以在声明后编译就分配所需内存,也可以使用动态内存分配在运行时为他分配内存。

1.1当声明数组时,必须用一个编译时常量为数组指定数组长度,这种分配内存的方的优缺点如下:

     1.1.1优点

              1. 使用简单只需在编译时常量指定数组长度。

     1.1.2缺点

              1.如果不确定数组内运行时具体需要多少内存,一旦实际元素超过分配的内存则出错。

              2.如果为了解决第一个缺点而大量声明内存空间,一旦实际元素过少时会严重浪费内存空间

1.2执行内存分配和释放函数

这些函数都在C函数库stdlib.h中

   1.2.1 malloc  

              1.函数原型:void  *malloc(size_t  size);

               size_t是一个无符号类型定义于stdlib.h中 size即为分配的内存大小返回值是指向内存起始位置的指针,由于使用返回指针的类型为void  * 型指针所以标准的表示void  *类型指针可以转换成任意类型指针,但是有些编译器可能要求使用强制类型转换。

               char* p; 

               p=(char*)malloc(20);

内存并未初始化,如果需要的话则需要手动初始化或者使用calloc函数。实际分配内存时可能回避你要求的超微多一旦,这个由编译器决定所以不能指望他肯定会分配连续的要求内存。如果申请内存为空的或者申请的内存系统无法满足要求,则会返回一个NULL指针,所以每个申请的内存必须检查返回指针,确保它并非NULL。NULL 实际上是字面值常量0。他在这里骑着视觉提醒作用告诉我们我们测试的是一个指针而不是整数。

    1.2.2 calloc

                1.函数原型: void  *calloc( size_t  num_elements,  size_t  exement_size);

                 calloc不同于malloc是calloc会在返回指针之前把申请内存初始化为0,如果0不是想初始化的内容则这里会浪费时间。num_element是要初始化的元素数量而 element_size时要初始化元素每个占用字节数,通过这些可以计算总共需要的分配的内存。

    1.2.3 realloc

                 1.函数原型:void  *realloc( void  *ptr , size_t  new_size);

                  realloc用于修改一个原来已经分配的内存块的大小。可以扩大一个内存块则原来的内容保留新增加的内存添加到原先内存块后面,可以缩小内存则缩小尾部的部分内存,剩余的内存和数据保留。如果原先的内存无法改变大小,则realloc会重新分配一个正确的大小的内存,并把原先的内容复制到新的快上,新词在使用realloc后你就不能在使用原来的指向内存的指针了,而是应该使用realloc所返回的新指针。

                  2 特殊情况:

                            (1)如果ptr = NULL 那么相当于调用malloc (size) size=0那么相当于调用了free(prt)。

                            (2)如果修改的内存小于实际的内存则会直接返回原来的内存地址。

                            (3)如果修改的内存大于实际的内存

                                   1.realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,则可以成功则返回原来内存指针地址。

                                   2.若堆的内存不足时则直接在堆里找一块新的内存为new_size的空间同时把原先的内容拷贝到新地址函数返回新内存地址,

里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放

这里原始内存中的数据还是保持不变的。当内存不再使用时,应使用free()函数将内存块释放。

里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放

                                   3.

里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放

如果申请失败,将返回NULL,此时,原来的指针仍然有效
下面就举两个例子,来说明一下。

1) realloc() 第一种行为引发的Bug
   
   
  1. void *ptr = realloc(ptr, new_size);
  2. if (!ptr) {
  3. // 错误处理
  4. }
这里就引出了一个内存泄露的问题,当realloc() 分配失败的时候,会返回NULL。但是参数中的 ptr 的内存是没有被释放的。如果直接将realloc()的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成内存游离和泄露。

正确的处理应该是这样:
   
   
  1. void *new_ptr = realloc(ptr, new_size);
  2. if (!new_ptr) {
  3. // 错误处理。
  4. }
  5. ptr = new_ptr

2) 第三种行为引发的Bug
实际上,malloc(0)是合法的语句,会返还一个合法的指针,且该指针可以通过free去释放。这就造成了很多人对realloc()的错误理解,认为当size为0时,实际上realloc()也会返回一个合法的指针,后面依然需要使用free去释放该内存。
   
   
  1. void *new_ptr = realloc(old_ptr, new_size);
  2. //其它代码
  3. free(new_ptr);
由于错误的认识,不去检验new_size是否为0,还是按照new_size不为0的逻辑处理,最后并free(new_ptr)。这里就引入了double free的问题,造成程序崩溃。

所以,realloc() 这个设计并不怎么优良的函数陷阱还是不少的,一不小心就踩雷了,上面只是两个简单的小例子,大家在实际使用的时候还应该注意一些其他小问题。

     1.2.4 free 

              1.函数原型:void  free(void *pointer);

里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放

                          功 能: 与malloc()函数配对使用,释放malloc函数申请的动态内存。(另:对于free(p)这句语句,如果p 是NULL 指针,那么free 对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。

                   错误的范文分配内存之外的区域所引起的后果类似越界访问数组,但这个错误还可能破坏可用内存池,导致程序失败,如果一个指针不是早先的malloc,calloc,realloc函数反悔的,他是不能作为参数传给free函数的。你也不能只是放一块内存的一部分。如果传给free函数一个指针没让他释放非动态分配的内存可能导致程序立即终止或者晚些时候终止。
                  内存泄露是指内存被动态分配以后,当他不在被使用时未被释放。内存泄露会增加程序的体积有可能导致程序或者系统崩溃。


里原始内存中的数据还是保持不变的。

当内存不再使用时,

应使用

free()

函数将内存块释放

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值