C语言从头学33——内存管理(一)

一、基本情况
       C语言的内存管理分成系统管理与程序员用户手动管理两部分。系统管理的内存,主要是函数内部的变量(局部变量),这部分变量在函数运行时进入内存,这部分内存区域成为"栈区",函数运行结束后操作系统自动从内存卸载。用户手动管理的内存,主要是程序运行的整个过程中都存在的变量(全局变量),这部分所在的内存区域称为"堆区",这些变量需要用户手动从内存释放。如果使用后忘记释放,它就一直占用内存,直到程序退出时再交给操作系统才会清理。
二、void 指针
       计算机中的内存空间都被分配了唯一的地址编码,通过内存指针可以找到指定的内存区域。指针变量需要有类型,如:int* p=&x; 声明了一个 int 型指针,这个指针指向整型变量 x 所在地址,当编译器从这个地址拿到数据时,就知道存储的是 int 型数据。当不确定存放什么类型的数据,只想先找块内存地址时,就用到了void类型指针。void类型指针也称为不定类型指针,可以指向任何类型的数据。
        void类型的指针可以与其他类型的指针互相转换,使用方法也没有特别之处,只是不能通过 " * " 方式解析出存储的内容。
        int x = 10; //声明整型变量 x
        void* p = &x; //声明void指针并指向x的地址,说明int型指针(&x)转为了void指针。
        int* q = p; // void指针又转回了整型指针
        printf( "%i\n", *q ); //运行结果:10
       注意区分 void* 与 void 的区别:void是无类型,用其声明函数时表示无返回值;而void*,虽然是无类型但有指针,是有东西返回的。
三、与内存管理相关的函数
1、malloc()
       这个函数可以分开来记,m是内存的缩写,alloc是分配的缩写,合起来就是分配内存。
       功能:从堆区申请一段连续的内存区块 (提醒:堆区内存是需要程序员自行管理的,用后要销毁,这一点要时刻记着);使用格式:malloc(参1);
       参数:参1 是内存区块大小(size_t类型的非负整数,sizeof 返回值即此类型)
       返回值:void* 指针(申请的内存给谁使用我们就用什么类型指针接收)
       用法:使用 malloc 函数声明的变量在堆区,故多采取匿名声明方式,即不采用对具体变量取址方式而是 malloc 直接返回指针,见下:
         int* ptr = (int*) malloc(sizeof(int)); //在堆区声明了一个int型指针变量
         括号中的强转非必须,malloc返回的是void*,可以用int*接收,此处加强转使得代码易于理解。
         注意事项:
          a. 使用malloc函数要包含<stdlib.h>头文件,如仅包含<stdio.h>编译正常,但不能正常运行,牢记。
          b. 给 ptr 赋值:*ptr=1000;。
          c. malloc 与 free(后边会遇到)配对使用,勿忘free (ptr);。
          d. malloc分派地址不一定成功,不成功时返回NULL,为此可加一个if语句进行处置。
          e. malloc只管分派内存,不管初始化,如需初始化,需另调用函数。
          f. malloc最常用的场合,就是为数组和自定义数据结构分配内存。
2、 memset()
        功能:将某指针所指向的内存区块中的每个字节进行统一赋初值
        参数:参1 指向目标内存的指针 参2 赋值内容(int型ASCII码值或char型字符) 参3 赋值字节数(size_t类型)
        返回值:返回被指向目标内存的指针,接收没有意义,与参1 相同。
        用法:memset(ptrDestMem,'A',sizeof(char)*1024) //对长度为1024字节的内存区块每个字节都赋字符A
        注意事项:
         a. 这个函数所属头文件为<string.h>,有些编译器不包含此头文件也能正常使用,如出现运行错误时,请包含。
         b. 注意memset是对字节(不是位)的操作;参3是指有多少个字节需赋值,它可以小于或等于目标内存字节数,但不能越界超出。
         c. 参2的值最大不能超过一个字节所能容纳(int型255),超过也写不进去。
2、free()
        功能:与malloc配对的函数,用于释放malloc函数分配的内存,防止内存泄漏
        参数:malloc函数返回的指针
        用法:free(ptr);
       注意事项:
       a. 使用free需要包含的头文件也是<stdlib.h>,勿忘。
       b. free函数只能执行一次,不能反复释放同一内存地址,被释放完的指针也不能再使用。
       c. malloc与free最好先成对写好,再在中间插入其他代码,以防忘记。
 3、realloc()
      re重新、再之意、alloc分派缩写,合起来是重新分派内存
      功能:修改已经分配的内存块的大小(加大或减小)。
      参数:参1 原内存区块指针 参2 增减后内存块大小(还是size_t类型)
      返回值:void*指针(可用原指针类型变量接收)
      用法:void* newPtr=realloc(ptr,sizeof(int)*10);
    注意事项:
      a. 使用realloc函数也需要包含<stdlib.h>。
      b. 原指针指向的内存区块已经被新指针替代,所以程序结束应free的是新指针,原指针不必再free,否则运行错误。
      c. realloc可能分派内存失败,失败返回NULL,所以加一个 if 语句处置为好
四、应用举例

#include<stdio.h>
#include<stdlib.h> //malloc、free、realloc
#include<string.h> //memset
int main(void)
{
//A void指针的使用float PI = 3.14159;void* pPI = &PI;float r = 2.5;printf("半径2.5圆的面积:%f\n", r * r * *(float*)pPI);//*(float*)pPI—pPI强转为float指针后再解出指向的值
//B malloc、memset、free函数使用int n = 8;void* pMyMem = malloc(sizeof(char)*n); //char占1字节,malloc分派n字节的内存,返给void指针if (pMyMem == NULL)return 0; //若分派内存失败,程序结束void* myMem2=memset(pMyMem,'B',sizeof(char)*8); //对malloc分派的内存区块个字节都写入字符'B'。//并用myMem2接收返回的指针if (pMyMem == myMem2)printf("memset写入区块指针与其返回的指针相同\n");char* transCh = pMyMem; //将void指针转成char型指针printf("显示写入内容:");for (int i = 0; i < n; i++){printf("%c ", *transCh); //显示写入的字符transCh++;}printf("\n");//换行free(pMyMem); //释放malloc函数分派的内存//free(ch); //只有malloc分派的内存才需要释放,且只释放一次(这里会报错)
//C realloc、free函数的使用int* pMem = malloc(sizeof(int)*5);if (pMem == NULL)return 0;for (int i = 0; i < 5; i++) pMem[i] = (i+1)*10;for (int i = 0; i < 5; i++) printf("%i ", pMem[i]);printf("\n重新增加分派内存后\n");int* newpMem = realloc(pMem, sizeof(int) * 10);if (newpMem == NULL)return 0;for (int i = 0; i < 10; i++) newpMem[i] = (i + 1) * 10;for (int i = 0; i < 10; i++)printf("%i ", newpMem[i]);free(newpMem); //释放realloc的内存//free(pMem);//pMem已被重置,不能再释放,此语句会造成运行失败getchar(); //暂停屏幕return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/870821.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue中使用$set方法给对象添加属性

vue中可以使用$set()给对象添加属性&#xff0c;但不是所有的对象都可以使用&#xff0c;vue中api明确说明&#xff0c;它必须用于向响应式对象上添加属性 响应式对象&#xff0c;vue的响应式原理&#xff0c;可以查看&#xff1a;深入响应式原理 — Vue.js ①对象赋值 this…

读懂一本书

各位好,今天我们要分享的这本书叫作《读懂一本书》。 很不好意思,书的作者是我。并不是我写的所有的书我都一定要讲,我也有很多合辑类的书籍是从来不讲的,我讲过《可复制的领导力》,讲过《低风险创业》,还有今天的这本《读懂一本书》,都是我有一些原创的观点和价值在里…

leetcode热题100.单词拆分(动态规划进阶)

最近参加工作比较忙&#xff0c;抽出时间分享一篇题解&#xff0c;希望对大伙有帮助&#x1f388;&#x1f388; 今天分享一道动态规划的题目&#xff0c;大家快刷起来吧&#x1f9be;&#x1f9be; Problem: 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字…

React组件间通信的几种方式

一、Props向下传递&#xff08;Top-Down Propagation&#xff09; 父组件通过props将其状态或数据传递给子组件。 父组件&#xff1a; class ParentComponent extends React.Component {state { message: Hello World };render() {return <ChildComponent message{this.…

真正适合零基础的机器学习入门书!数学不好?python不会?通通都能拿下!!

在数字化时代&#xff0c;机器学习无疑是一股强劲的革新动力&#xff0c;正悄无声息地渗透并革新各行各业&#xff0c;成为推动创新、提升效率的关键法宝。 对于想要涉足这个领域&#xff0c;渴望掌握机器学习精髓的初学者来说&#xff0c;《Python机器学习基础教程》就是一本…

C++ list容器的底层实现

一.list是什么 list 是 C容器中的带头双向链表&#xff0c;头结点不存储数据&#xff0c;头结点的下一个元素是第一个存储数据的元素&#xff0c;头结点的前一个元素连接着最后一个存储数据的元素。&#xff08;结构如下图所示&#xff09; 其中链表里每一个节点的结构分为&…

AI究竟是在帮助开发者还是取代他们

前言 人工智能&#xff08;AI&#xff09;的迅猛发展正在各行各业引发深远影响。尤其是在软件开发领域&#xff0c;AI的应用日益广泛&#xff0c;带来了效率和创新的提升。然而&#xff0c;随着AI技术的不断进步&#xff0c;人们也开始担心AI是否会取代人类开发者&#xff0c;…

PyQt5开发笔记:2. 2D与3D散点图、水平布局和边框修饰

一、装pyqtgraph和PyOpenGL库 pip install pyqtgraph pip install PyOpenGL 注意&#xff1a;一定不要pip install OpenGL&#xff0c;否则会找不到 二、3D散点图效果 import pyqtgraph as pg import pyqtgraph.opengl as gl import numpy as np# 创建应用程序 app pg.mkQ…

【计算机组成原理 | 第二篇】计算机硬件架构的发展

目录 前言&#xff1a; 冯诺依曼计算机架构 现代计算机架构&#xff1a; 总结&#xff1a; 前言&#xff1a; 在当今数字化时代&#xff0c;计算机硬件不仅是技术进步的见证者&#xff0c;更是推动这一进步的基石。它们构成了我们日常生活中不可或缺的数字生态系统的核心&a…

数据失踪了?小米手机数据恢复并不难,3个方法就能搞定

手机数据就如同我们的“数字生命线”&#xff0c;一旦失去&#xff0c;便仿佛陷入了一片数据的荒漠&#xff0c;感到无助与迷茫。小米手机用户们&#xff0c;你是否曾遭遇过这样的困境&#xff1a;打开手机&#xff0c;却发现重要的照片、联系人、短信等数据不见了&#xff0c;…

Flutter和React Native(RN)的比较

Flutter和React Native&#xff08;RN&#xff09;都是用于构建跨平台移动应用程序的流行框架。两者都具有各自的优势和劣势&#xff0c;选择哪个框架取决于您的具体需求和项目。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 以下是…

数据库作业六

创建视图v_emp_dept_id_1&#xff0c;查询销售部门的员工姓名和家庭住址 CREATE VIEW v_emp_dept_id_1 AS SELECT e.emp_name,e.address FROM dept d, emp e WHERE e.dept_id (SELECT dept_id FROM dept WHERE dept_name 销售部); SELECT * FROM v_emp_dept_id_1; 创建视…

乐财业:打造财税服务的“硬核“竞争力

乐财业 智慧财税赋能平台 乐财业是目前市面上唯一一家真正实现“业财税”"三位一体全面融合的综合赋能平台&#xff0c;全新打造一站式、流程化、生态化的全产品供应链&#xff0c;立足于企业“业财"融合的发展趋势&#xff0c;凭借20年的财税服务经验&#xff0c;站…

CoreDump使用与实现原理

一、背景 系统发生native crash时&#xff0c;针对内存异常访问、内存踩踏等疑难问题&#xff0c;由于tombstone信息量不足无法精确定位分析这类问题。 二、coredump介绍 2.1 什么是coredump 当用户程序运行过程中发生异常, 程序异常退出时, 由Linux内核把程序当前的内存状…

C语言笔记29 •单链表经典算法OJ题-1.合并两个升序链表•

1.合并两个升序链表&#xff08;创建头节点 简化代码&#xff09; ListNode* lowlisthead(ListNode*)malloc(sizeof(ListNode)); 新颖之处就是创建头节点&#xff08;哨兵位&#xff09;能够减少代码&#xff0c;不用每次都判断链表是否为NULL&#xff0c; 注意的是&#xff1a…

笔记:如何使用Microsoft.Extensions.Options

一、目的&#xff1a; Microsoft.Extensions.Options 是 .NET Core 中用于处理配置选项的一个库。它提供了一种强类型的方式来读取和绑定配置数据&#xff08;例如来自 appsettings.json 文件、环境变量或其他配置源的数据&#xff09;&#xff0c;并将其注入到应用程序中。这个…

ss工具dump出vsock 端口号异常分析

端口冲突时&#xff0c;会出现bind fail异常&#xff0c;这时可以用ss --vsock -pl命令dump出所有listen状态的vsock,但实际发现传入的9000端口&#xff0c;dump出来却是10275&#xff0c;如下图&#xff1a; 难道是内核把端口改了&#xff1f;分析内核态源码&#xff0c;ss最终…

模拟器大揭秘:功能多样,热门APP一网打尽

在咱们日常的数字生活中&#xff0c;模拟器这个词儿你可能不陌生&#xff0c;但它到底能干啥&#xff1f;又有哪些好用的模拟器APP呢&#xff1f; 今天&#xff0c;咱们就来聊聊模拟器的功能&#xff0c;并推荐几款热门的模拟器APP&#xff0c;帮助大家更好地利用这一技术。 …

Math/System/Runtime/Object

1、Math &#xff08;1&#xff09;常用方法 类型方法名说明public static intabs (int a)返回整数的绝对值public static doublepow (double a,double b)计算a的b次幂的值public static int max (int a,int b) 获取两个int值中的较大值public static intmin (int a,int…

java读取配置文件(包含国家于二字码对应关系文件)

读取配置文件 1.java文件 import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ClassPathResource;import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Map; Slf4j public class…