10.动态内存管理


书写程序的原则:谁申请地址,待程序执行结束后谁要释放。动态内存管理的函数包括有malloc calloc realloc free,其中free函数要与前三者在一个函数中同时使用或者在同一个模块中。

一.malloc

  • 函数定义:void *malloc(size_t size);
    在堆上寻找size大小的空间,并以地址的方式返回给程序。

  • 示例代码:

    //基本使用
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main()
  5 {
  6     int *p = NULL;
  7     p = malloc(sizeof(int));  //malloc返回值时一个指针
  8     
  9     if(p == NULL)
 10     {    
 11         printf("malloc() is error!");
 12         exit(1);
 13     }
 14     
 15     *p = 10;
 16     printf("p = %d\n",*p);
 17     free(p);  //释放指针指向的首地址所代表的内存空间。
 18     exit(0);
 19 }
 
 //输出结果:
 p = 10

为数组动态分配内存(变长数组):

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main()
  5 {
        int *p =NULL;
  6     int num = 6;
  7     *p = malloc(sizeof(int) * num);
  8     int i;
  9     
 10     for(i = 0;i < num; i++)
 11         scanf("%d",&p[i]);
 12     
 13     for(i = 0;i < num; i++)
 14         printf("%d ",p[i]);
 15     printf("\n");
 16 
 17     exit(0);
 18 }   
 //输出结果:
 jxs@jxs-ubuntu:~/Desktop/c  language/alloc$ ./arr
45
56
23
89
56
89
45 56 23 89 56 89 

有关内存溢出的例子:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 void func(int *q,int n)
  5 {
  6     q = malloc(n);
  7     if(q = NULL)
  8         exit(1);
  9     return;
 10 }
 11 
 12 int main()
 13 {
 14     int *p = NULL;
 15     int num = 100;
 16     
 17     func(p, num);
 18     free(p);
 19     
 20     exit(0);
 21 }
 //该程序在编译的时候不会报错,但是确实是出现了内存泄漏。

原因在于:
image

可以更正为:

#include <stdio.h>
#include <stdlib.h>
void func(int **q,int n)  //int *q
{
    *q = malloc(n);  //q
    if(*q = NULL)  //q
        exit(1);
    return ;
}
int main()
{
    int *p = NULL;
    int num = 100;
    func(&p, num);   //func(p,num)
    free(p);
    
    exit(0);
}
#include <stdio.h>
#include <stdlib.h>
void *func(int *q,int n)  //空类型指针
{
    q = malloc(n);
    if(q = NULL)
        exit(1);
    return q;
}
int main()
{
    int *p = NULL;
    int num = 100;
    p = func(p, num);
    free(p);
    
    exit(0);
}

二.calloc

  • 函数定义:void *calloc(size_t nmemb, size_t size);

寻找nmemb * size(一个 memb 占用 size 大小空间)大小的连续空间,即为每个memb申请size大小的空间,一共有n块同样大小且连续的空间,同样以地址的方式返回。并把空间内的每个字节初始化为0。

其他用法与malloc相同,因此如果要求申请的内存初始化为0,就调用该函数。

三.reallocreallocarray

1.realloc

1). 函数定义:void *realloc(void *ptr, size_t size);

重新分配一块动态内存,比如上述函数分配的内存不够或者多了,该函数可以重新分配一块满足后来要求size大小的空间。

  • 比如说使用calloc函数分配的空间100个字节不够用,而实际需要300个字节,此时,relloc函数接收这100个字节空间的最后一个地址,接着向下连续寻址,直到一共300个字节,如果下面的地址被其他变量占用,那么就会重新寻找其他内存区域,寻找到连续的300个字节的空间,之后将原来的那块空间释放掉,返回新空间得首地址。位于原来地址的数据,都会移动到该新地址,即原来的首地址发生改变。
  • 如果分配的内存比实际使用的要多,为了缩减为要求的空间大小,relloc会逐步的将对于的地址进行缩减,直至空间达到实际要求的大小。原来的空间数据不发生变化。

2). 特点:

  • ptr是要调整的内存地址,size为调整之后的新大小;
  • 返回值为调整之后的内存起始位置;
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间;

2.reallocarray

1). 函数定义:void *reallocarray(void *ptr, size_t nmemb, size_t size);

改变由ptr指向的内存空间的大小,直至数组有足够存储的空间存储nmemb个元素。每一个元素占用size大小空间。
等同于realloc(ptr, nmemb * size);但是与realloc调用不同的是,该函数会在multiplication时缺乏安全性会导致overflow,如果发生了溢出,该函数会返回NULL,将 errno 设置为ENOMEM,并保持原始内存块不变。

四.free

  • 函数定义:void free(void *ptr);
  • free函数用于释放指向ptr的内存空间,其必须在先前已经调用malloc calloc realloc函数之一才能使用,否则如果先于这三个函数调用,将会出现不可预料的错误,如果ptrNULL将不会进行任何操作。
  • free(p)表示指针p对其原指向的那块内存空间不再有引用权限。free之后需要将原来的指针写成NULL,避免野指针的出现:
//你:租客;编译器:房东
int *p ;  //定义指针p    (你对房东说:我要租房间p)
p = malloc(100);   //指针指向分配的100个字节的空间的首地址  (你向房东说p得100平)

*p = 10;  //将10存储到p指向的那块地址空间中  (你让‘10’ 住了进来,现在房间使用权在你,你可以让任何人住进来)
free(p);  //释放p指向的那块地址空间,此时p 已经不再指向原来那块地址空间。 (你因某些原因退租,让房东帮忙给退了)
//因此下面的对原地址的直接引用属于野指针。所以释放空间之后:
p = NULL;  //令指针为空  (房间p确定已经空了下来,等待或者已经给了下一位租客,但使用权不在你手上,而是在房东手上)

*p = 100;  //因此你无权再让其他人(100)拎包入住
//除非你再重新租住。
  • 示例代码:
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main()
  5 {
  6     int *p = NULL;
  7     p = malloc(sizeof(int));
  8     
  9     if(p == NULL)
 10     {
 11         printf("Error!Try again!\n");
 12         exit(1);
 13     }   
 14     
 15     *p = 10;
 16     printf("%p --> %d\n",p,*p);
 17     free(p);
 18     
 19    //p = NULL;  //避免p成为野指针
 20     *p = 100;
 21     printf("%p --> %d\n",p,*p);   //p指向的的地址可能不会发生改变,但这样使用很危险!
 22      
 23     
 24     
 25     exit(0);
 26 }   
posted @ 2023-06-29 17:07  假行僧me  阅读(17)  评论(0编辑  收藏  举报