数据结构与算法基础——内存动态管理

malloc——申请动态内存空间

free——释放动态内存空间

calloc——申请并初始化一系列内存空间

realloc——重新分配内存空间

malloc

  void *malloc(size_t size)

  malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这块空间的指针。

  如果函数调用成功,返回一个指向申请的内存空间的指针由于返回类型是void 指针(void *),所以它可以被转换成任何类型的数据;如果函数调用失败,返回值是NULL

int main()
{    
    int *ptr;
    ptr=(int *)malloc(sizeof(int));
    //向内存申请空间,转换int类型的指针    
    if(ptr==NULL)
    {
        printf("分配内存失败了!\n");
        exit(0);
    }
    printf("请输入一个整数:\n");
    scanf("%d",ptr);
    printf("你输入的整数是:%d\n",*ptr);
    return 0;
}    

 

free

  void free(void *ptr);

  free函数释放ptr参数指向的内存空间。该内存空间必须是由malloc、calloc 或realloC函数申请的。否则,该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。注意:该函数并不会修改ptr参数的值,所以调用后它仍然指向原来的地方(变为非法空间)
  

int main()
{    
    int *ptr;
    ptr=(int *)malloc(sizeof(int));
    //向内存申请空间,转换int类型的指针    
    if(ptr==NULL)
    {
        printf("分配内存失败了!\n");
        exit(0);
    }
    printf("请输入一个整数:\n");
    scanf("%d",ptr);
    printf("你输入的整数是:%d\n",*ptr);
    free(ptr);        // 指向一个随机地址
    printf("你输入的整数是:%d\n",*ptr);
    return 0;
}    

 

内存泄露

  如果申请了内存空间必须使用free函数来回收内存空间,否则会导致内存泄露。
  如果申请了内存空间,又指向其他的地址也会导致内存泄露;

  主要有两种:

    - 隐式内存泄漏(即用完内存块没有及时使用free函数释放)
    - 丢失内存块地址

#include <stdio.h>
#include <stdlib.h>
int main(void)
{    
    int *ptr=NULL;
    int num,i;
    printf("请输入待录入整数的个数:\n");
    scanf("%d",&num);
    ptr=(int *)malloc(num *sizeof(int));    // 指定的整数存储在num里面
    for(i=0;i<num;i++)
    {
        printf("请录入第%d个整数:",i+1);
        scanf("%d",&ptr[i]);
    }
    printf("你录入的整数是:\n");
    for(i=0;i<num;i++)
    {
        printf("%d\t",ptr[i]);
    }
    putchar('\n');
    free(ptr);    
    return 0;
}    

 

初始化内存空间

以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中:
  -memset    使用一个常量字节填充内存空间
  -memcpy    拷贝内存空间
  -memmove   拷贝内存空间
  -memcmp    比较内存空间
  -memchr    在内态空间中搜索一个字符
  区别:字符串的函数不同是,返回值不同,string类型是返回字符型的指针,mem是void.

  用memset函数对内存空间进行初始化

    int *ptr=NULL;
    int i;
    ptr=(int *)malloc(N *sizeof(int));
    if(ptr==NULL)
    {
        exit(1);
    }
    memset(ptr,0,N *sizeof(int));
    for(i=0;i<N;i++)
    {
        printf("%d",ptr[i]);
    
    }
    putchar('\n');
    free(ptr);
    return 0;
}    

calloc函数
  void *calloc(size_ t memb,size_ t size) ;
calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为nmemb*size),这些内存空间全部被 初始化为0

calloc函数与malloc函数的一个重要区别是:

  • calloc函数在申请完内存后,自动初始化该内存空间为零
  • malloc函数不进行初始化操作,里边数据是随机的
calloc()分配内存空间并初始化
int *ptr=(int *)calloc(8,sizeof(int));

malloc()分配内存空间并用memset()初始化
int *ptr=(int *)malloc(8*sizeof(int));
memset(ptr,0,8*sizeof(int));

  上面两者等价。

realloc函数

  对内存不够用(不用realloc)的情况下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{    
    int *ptr1=NULL;
    int *ptr2=NULL;
    // 第一次申请的内存空间
    ptr1=(int *)malloc(N *sizeof(int));
    // 申请的内存空间不够用时
    // 第二次申请
    ptr2=(int *)malloc(N *sizeof(int));
    // 拷贝ptr1的数据到ptr2中
    memcpy(ptr2,ptr1,10);
    free(ptr1);
    // 对ptr2进行若干操作...
    free(ptr2);
    return 0;

realloc函数原型:
  void *realloc(void *ptr,size_ t size);
以下几点是需要注意的:

  • realloc函数修改ptr指向的内存空间大小为size字节;
  • 如果新分配的内存空间比原来的,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
  • 该函数将移动内存空间的数据并返回新的指针
  • 如果ptr参数为NULL,那么调用该函数就相当于调用malloc( size)。

 

  • 如果size参数为0,并且ptr参数不为NULL,那么调用该函数就相当于调用free(ptr)除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc或realloc函数返回。

  用realloc接收用户的输入,直到输入结束符:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{    
    int i,num;
    int count=0;
    int *ptr=NULL;
    do
    {
        printf("请输入一个整数(输入-1表示结束):");
        scanf("%d",&num);
        count++;
        ptr=(int *)realloc(ptr,count *sizeof(int));
        if(ptr==NULL)
        {
            exit(1);
        }
        ptr[count-1]=num;
    }while(num!=-1);

    printf("输入的整数分别是:\n");
    for(i=0;i<count;i++)
    {
        printf("%d\t",ptr[i]);
    }
    putchar('\n');
    free(ptr);
    return 0;
}    

 

 

C语言的内存布局规律

  

   

 

 

 

代码段( Text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。

数据段(Initialized data segment) 通常用来存放已经初始化的全局变量和局部静态变量。

BSS段(Bss segment/Uninitialized data segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩展或缩小。当进程调用malloc等函数分配内存 时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。

栈和堆区别:

  • 申请方式:

     堆由程序员手动申请
     栈由系统自动分配

  • 释放方式:

     堆由程序员手动释放
     栈由系统自动释放

  • 生存周期:

  堆的生存周期由动态申请到程序员主动释放为止,不同函数之间均可自由访问栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能互相访问。

  • 发展方向:

    堆和其它区段一样,都是从低地址向高地址发展;
    栈则相反,是由高地址向低地址发展。






 

 

 

  



 

 



posted @ 2021-03-16 16:38  一个特立独行的猪  阅读(149)  评论(0)    收藏  举报