美文网首页
C语言中手把手教你动态内存分配

C语言中手把手教你动态内存分配

作者: 程序爱好者 | 来源:发表于2019-08-12 14:19 被阅读0次

    C语言中手把手教你动态内存分配

    动态内存分配

    常见的内存分配的错误

    先上一个内存分配的思维导图:便于联想想象,理解:

    首先我们介绍一下内存分配的方式:

    1:在静态存储区域中进行分配

            内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量

    2:在栈中进行分配

            在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储但愿自动被释放。效率很高,但是分配的内存容量比较有限

    3:在堆中进行分配

            在堆上分配也称为动态内存分配:程序在运行的时候用malloc等函数申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存分配的生存期由我们自己决定,使用非常灵活,但是问题相对也比较多;注意://如果没有释放的话,很容易就会造成内存溢出,因为堆中的内存块是全局的,因此不会因为函数的调用而结束

    动态内存分配中使用的函数:

    1:malloc函数:需要用到的头文件malloc.h

    void *malloc(size_t size) //————–>返回的是一个通用类型的指针,根据需要去进行强转;

    功能:允许从空闲内存池中分配连续内存但不初始化

    参数:size参数实际就是一个所需字节数的整数 malloc(20);

    返回:若分配成功则返回一个指向该内存块的指针,在使用时可根据需要做强制类型转换,否则返回NULL(空指针)//需要判空

    free(p);//释放内存空间,将内存释放出来给系统;

    free函数与malloc函数是成对出现的;

    申请malloc的时候尽量去给它进行一下初始化,防止后面出现一些不确定性的东西;

    malloc的生命周期:只要没有调用free这个函数,进程没有结束,那么此时,这个函数的生命周期就会一直存在在内存中;它是存放在堆空间中的,它不会因为你去函数调用的结束自动去释放,堆当中的内存是全局的

    如:int p = (int )malloc(n*sizeof(int)); //在空闲内存池中分配连续内存n*sizeof(int)个字节的堆内存空间

    malloc的相关实例代码如下:

    #include<stdio.h>

    #include<malloc.h>

    void out(int *p,int n)

    {

        int i;

        for(i=0;i<n;i++)

        { 

            printf("%d",*(p+i));

            printf("---------------\n");

        } 

    }

    int main(void)

    {

        printf("please input one number:");

        int n;

        scanf("%d",&n);

        //申请

        int *p = (int *)malloc(n * sizeof(int));

        //内存申请成功

        if(p != NULL){

            out(p,n);

            int i;

            for(i=0;i<n;i++){

                *(p+i)=i*i;

            }

            out(p,n);

            //释放掉堆内存

            free(p);

        }else{

            //内存申请失败

            printf("malloc is NULL!\n");

        } 

        return 0;

    }

    2:calloc函数:需要用到的头文件stdlib.h

    void *colloc(size_t num_elements,size_t element_size);

    功能:功能同malloc是一样的,但是作初始化

    参数:num_elements是所需的元素的数量,element_size是每个元素的字节数

    返回:同malloc函数一样

    也是需要与free(p)进行对称使用

    calloc相关代码如下所示:

    #include<stdio.h>

    #include<stdlib.h>

    int main(void)

    {

        printf("please input one number:");

        int n;

        scanf("%d",&n);

        int *p = (int *)calloc(n,sizeof(int));

        if(p!=NULL){

            int i;

            for(i=0;i<n;i++)

            {

                printf("%d ",*(p+i));

            }

            printf("\n");

            free(p);

        }else{

            printf("calloc error\n");

        } 

        return 0;

    }

    3: realloc函数:需要用到的头文件(stdlib.h),动态扩大缩小申请的内存

    void *realloc(void *ptr,size_t new_size);

    功能:在指针ptr指向的内存基础上扩大或者缩小内存

    参数:ptr是指向先前通过malloc,calloc和realloc函数后分配的内存块的指针,new_size是内存块的新尺寸,可能大于或者小于原有内存尺寸;这个是追加到new_size的新的内存

    realloc在C语言中也被称为动态数组;

    realloc函数使用的注意点:

    1:当扩展内存的时候,不会对添加进内存块的字节进行初始化

    2:若不能调整内存则返回NULL,但原有内存中的数据是不会发生改变的

    3:若第一个参数为NULL那么功能 等同与malloc函数,若第二个参数为0,那么会释放调用内存块

    realloc(NULL,10*size(int)) 等同malloc(10*sizeof(int));

    realloc(p,0); 等同于free

    4:当缩小或者扩大内存时,一般不会对其进行移动,若无法扩大内存块,那么啃呢个会在别处分配新的内存快,然后把旧内存块的数据复制到新块 中,并将旧块删除释放内存;

    realloc相关的的代码为:

    #include<stdlib.h>

    #include<stdio.h>

    #include<malloc.h>

    void out(int *p ,int n){

        int i;

        for(i = 0 ;i < n; i++){

            printf("%d\n",*(p+i));

        } 

    }

    int main(void)

        //申请4个字节的堆内存空间,未初始化

        int * p = (int *)malloc(5*sizeof(int));

        if(p == NULL) exit(1);

        *p = 1;

        *(p+1)  =2;

        p[2] = 3;

        p[3] = 4;

        p[4] = 5;

        out(p,5);

        printf("===============\n");

        //追加申请10个字节的内存空间,追加的空间也是未进行初始化的

        p = (int *)realloc(p,10*sizeof(int));

        if(p == NULL) exit(1);

        p[6] = 6;

        *(p+6) = 7;

        *(p+7) = 8;

        *(p+8) = 9;

        *(p+9) = 10;

        out(p,10);

        free(p);

        //free之后,将指针置为空

        p = NULL;

        return 0;

    }

    4:free函数

    free之后如果还有这块内存地址的话,此时这块内存归还给了系统,(可能这块内存还处于一个空闲状态)但是还是可以对其进行操作。里面的值短暂的会保留。

    free之后,申请内存的那个指针就会变成野指针(声明了,但是没有任何指向的指针),有时候会出现野指针错误;

    所以尽量在操作之后:将指针置为NULL

    p=NULL;

    注意:申请和释放是成对的,所以程序是不能进行多次free的,否则会崩溃的

    常见的内存错误:

    1:段错误

    使用未分配成功的内存

    避免方式:在使用内存之前检查指针是否为NULL;

    引用分配成功但尚未初始化的内存

    避免方式:赋予初值,即便是赋予零值也不可省略

    内存分配成功并且已经初始化,但操作越过了内存的边界

    避免:注意下表的使用不能超出边界

    忘记释放内存,造成内存泄露

    避免方式:申请内存的方式和释放内存的方式需要成双成对

    释放内存之后却继续去使用这一块内存

    避免方式:使用free内存之后,把指针置为NULL;

    内存错误的注意点:

    指针消亡了,并不表示它所指向的内存会被自动释放,(在free之前,直接将指针设为NULL);

    内存释放了,并不代表指针会消亡或者成了NULL指针;(在free之后,指针并没有进行NULL设置)

    野指针:

    野指针的形成是指针变量没有被初始化,任何指针变量刚被创建的时候不会自动成为NULL指针,它的缺省值是最忌的,它会乱指一气

    指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法内存

    free内存块之后,需要将指针设置为NULL,如果没有设置为NULL,也会出现“野指针”,它是指向“垃圾”内存的指针;

    多次free内存块,是会导致程序崩溃的

    重要的事说三遍~~~~

    交流728483370,一起学习加油!

    交流728483370,一起学习加油!

    交流728483370,一起学习加油!

    相关文章

      网友评论

          本文标题:C语言中手把手教你动态内存分配

          本文链接:https://www.haomeiwen.com/subject/akcujctx.html