• C语言-入门-内存管理(二十)


    在这里插入图片描述

    什么是进程

    程序,是经源码编译后的可执行文件,可执行文件可以多次被执行,比如我们可以多次打开 office。而进程,是程序加载到内存后开始执行,至执行结束,这样一段时间概念,多次打开的wps,每打开一次都是一个进程,当我们每关闭一个 office,则表示该进程结束。

    内存空间布局

    有了进程和程序的概念以后,我们再来看一下,程序被加载到内存以后内存空间布局是什么样的
    在这里插入图片描述
    在这里插入图片描述
    总体来讲说,程序源代码被编译之后主要分成两种段:程序指令和程序数据。代码区属于存放程序指令,常量区、全局数据区、堆区、栈区属于存放程序数据。程序代码区、常量区、全局数据区在程序加载到内存后就分配好了,并且在程序运行期间一直存在,大小固定,只能等到程序运行结束后由操作系统收回。栈区、堆区在程序运行时动态开辟。堆需要手动释放

    栈内存(Stack)

    • 栈中存放任意类型的变量,即自动类型的局部变量, 随用随开,用完即消。
    • 内存的分配和销毁系统自动完成,不需要人工干预
    • 栈的最大尺寸固定,超出则引起栈溢出(局部变量过多,过大 或 递归层数太多等就会导致栈溢出)
    int ages[10240*10240]; // 程序会崩溃, 栈溢出
    
    • 1

    在这里插入图片描述

    堆内存(Heap)

    • 堆内存可以存放任意类型的数据,但需要自己申请与释放
    • 大小,想像中的无穷大,但实际使用中,受限于实际内存的大小和内存是否连续性

    在这里插入图片描述

    malloc和free函数

    通过malloc申请的存储空间一定要释放, 所以malloc和free函数总是成对出现
    malloc函数
    在这里插入图片描述
    free函数
    在这里插入图片描述

    #include 
    #include 
    #include 
    int main()
    {
        // 1.申请1块4字节的存储空间
        int *p = (int *)malloc(sizeof(int));
        // 2.初始化4个字节存储空间为0
        memset(p, 0, sizeof(int));
        // 3.释放申请的存储空间
        free(p);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    free()到底释放了什么? free释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常重要!指针是一个变量,只有程序结束时才被销毁。free释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了,导致未知的问题发生。非常重要啊这一点!

    在上面我们还用到一个函数memset(指针,0,数据大小) 这个函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行批量初始化工作。它是直接操作内存空间,而且通常是给数组或结构体进行批量初始化。一般的变量如 char、int、float、double 等类型的变量直接*p=0初始化即可,没有必要用 memset。如果用 memset 的话反而显得麻烦

    calloc函数

    和malloc一样,但可以初始化内存空间为0值
    在这里插入图片描述

    #include 
    #include 
    #include 
    int main(int argc, char* argv[])
    {
        // 1.申请4块,4个字节的存储空间
        int *p = calloc(4, sizeof(int));
        printf("%d",*p);
        // 3.释放申请的存储空间
        free(p);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    realloc函数

    基于现有空间进行扩容或者缩小,利用这一特性可以完成数组动态扩容
    在这里插入图片描述

    注意事项:

    • 若参数ptr==NULL,则该函数等同于 malloc
    • 返回的指针,可能与 ptr 的值相同,也有可能不同。若相同,则说明在原空间后面申请,否则,则可能后续空间不足,重新申请的新的连续空间,原数据拷贝到新空间, 原有空间自动释放
    #include 
    #include 
    #include 
    int main()
    {
        // 1.申请4个字节存储空间
        int *p = NULL;
        p = realloc(p, sizeof(int)); // 此时等同于malloc
        // 2.使用申请好的空间
        *p = 666;
        printf("*p = %i\n",  *p);
        // 3.释放空间
        free(p);
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    #include 
    #include 
    #include 
    
    int main()
    {
        // 1.申请4个字节存储空间
        int *p = malloc(sizeof(int));
        printf("p = %p\n", p);
        // 如果能在传入存储空间地址后面扩容, 返回传入存储空间地址
        // 如果不能在传入存储空间地址后面扩容, 返回一个新的存储空间地址
        p = realloc(p, sizeof(int) * 2);
        printf("p = %p\n", p);
        // 2.使用申请好的空间
        *p = 666;
        printf("*p = %i\n",  *p);
        // 3.释放空间
        free(p);
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    动态分配内存

    编程时,如果您预先知道数组的大小,那么定义数组时就比较容易。例如,一个存储人名的数组,它最多容纳 100 个字符,所以您可以定义数组,如: char name[100];

    但是,如果您预先不知道需要存储的文本长度,例如您想存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来分配内存,如下所示:

    #include 
    #include 
    #include 
    
    
    int main(int argc, char *argv[]) {
        char *description;
        /* 分配30字节的内存 */
        description = (char *) malloc(30 * sizeof(char));
        if (description == NULL) {
            fprintf(stderr, "Error - unable to allocate required memory\n");
        } else {
            strcpy(description, "Zara ali a DPS student.");
        }
        /* 假设您想要存储更大的描述信息,那么我们将description内存大小进行动态调整为100字节大小 */
        description = (char *) realloc(description, 100 * sizeof(char));
        if (description == NULL) {
            fprintf(stderr, "Error - unable to allocate required memory\n");
        } else {
            //拼接字符串
            strcat(description, "She is in class 10th");
        }
    
        printf("Description: %s\n", description);
    
        /* 使用 free() 函数释放内存 */
        free(description);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    您可以尝试一下不重新分配额外的内存,strcat() 函数会生成一个错误,因为存储 description 时可用的内存不足。

    如果想看更高级的用法可以看我博客里这篇文章C语言-数据结构-单向链表

    在这里插入图片描述

    点赞 -收藏-关注-便于以后复习和收到最新内容
    有其他问题在评论区讨论-或者私信我-收到会在第一时间回复
    在本博客学习的技术不得以任何方式直接或者间接的从事违反中华人民共和国法律,内容仅供学习、交流与参考
    免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我、以迅速采取适当措施,避免给双方造成不必要的经济损失。
    感谢,配合,希望我的努力对你有帮助^_^
  • 相关阅读:
    WPF的由来
    计算机网络复习-第五章传输层
    Linux拷贝查找和压缩文件
    【深度学习】GPT-3
    JAVA系列 面向对象编程?子类到底能继承父类的那些东西?如何继承?static方法能被继承吗?构造函数能被继承吗?继承中常见误区总结。
    他山之石,可以攻玉, 改造fasthttp实现高性能网络通信
    为什么Token手动添加到请求的Header中,通常使用“Authorization“字段?
    MySQL架构MMM
    Claude3荣登榜首,亚马逊云科技为您提供先行体验!
    测试开发-celery框架详解
  • 原文地址:https://blog.csdn.net/weixin_45203607/article/details/126346355