首页 > 编程语言 >c++第十天

c++第十天

时间:2023-04-23 11:33:06浏览次数:40  
标签:malloc 第十天 int void c++ 内存 指针 size

指针复习:     什么是指针:         数据类型 定义指针变量 整型 内存编号 访问对应内存     为什么使用指针:         1、函数之间共享变量             输入、输出         2、提高传参效率             指针变量4\8字节         3、使用堆内存时     如何使用指针:         定义:类型* 变量名_p;             变量名以p结尾与普通变量以示区分             一个*只能定义一个指针变量             初始化为NULL             类型决定了能够连续访问的字节数         赋值:变量名_p = 有效地址               p = &变量名               p = malloc(字节数)         解引用:*变量名_p;             通过指针变量中存储的整数编号去访问内存             该过程很可能产生段错误,是由于赋值时的内存地址非法导致的     指针需要注意的问题:         空指针:值为NULL的指针叫做空指针             对空指针解引用一定段错误,用于初始化以及函数返回值的错误标志                 如何避免空指针带来的段错误:                     来历不明的指针使用前先判断                     函数的返回值\函数的参数         野指针:指针的值不确定             对野指针解引用的后果:                 1、一切正常                 2、段错误                 3、脏数据             野指针的危害比空指针要大,因为无法分辨是否是野指针             如何不产生野指针:                 1、指针一定要初始化                 2、不要返回局部变量的地址                 3、堆内存释放后,指向堆内存的指针及时置空     指针运算:         指针 + n    前进n个元素宽度         指针 - n    后退n个元素宽度         指针 - 指针 计算出两个指针之间间隔了多少个元素,必须类型相同才能相减     指针与const:         const int* p\ int const *p  保护指针指向的内存不能修改         int* const p    保护指针的指向不能修改                 当函数的参数是指针,但是又不想被函数共享修改时,考虑使用const保护         指针数组与数组指针:         指针数组:成员是指针变量的数组             int* arr[10];         数组指针:专门指向数组的指针             int (*p)[10];             指向长度为10,成员为int类型的数组的指针         指针与数组名区别:         数组名就是数组的首地址,它与数组首地址是映射关系,相当于一个特殊的指针,但是它是个常量,不能修改         数组作为函数的参数传递时,蜕变成指针,因此长度丢失         指针是变量,它与存储的地址之间是指向关系,是可以更改的         当一个指针指向数组首地址时,指针可以当做数组名使用,数组名也可以当做指针使用             int* p;             int arr[10]             p[i] == *(p+i)             arr[i] == *(arr+i)             sizeof(arr) 计算数组的总字节             sizeof(&arr) sizeof(&arr[0])             sizeof(p)   4/8         二级指针:         指向指针的指针,存储的是指针变量的地址         定义:int** 变量名_pp;         赋值:变量名_pp = &指针变量;         解引用:*变量名_pp == 指针变量;             **指针变量 == *指针变量 == 数据         注意:             当函数间需要共享普通变量时,传递一级指针             当函数间需要共享指针变量时,传递二级指针 ------------------------------------ 一、函数指针     函数名就是一个地址(整数),代表了该函数在代码段中的位置         函数指针就是专门指向某种函数的指针,它里面存储的是该函数在代码段中的位置(函数名)     例子:     int (*funcp)(const char*, ...) = scanf;         funcp是指向返回值为int,参数为const char*和...这样函数的指针     funcp("%d",&num);
    typedef 返回值类型 (*FP)(参数类型1,参数类型2,...);     FP 相当于函数指针类型 可以用于定义函数指针变量     FP funcp;     funcp(实参1,实参2)
    回调模式的函数:     void qsort(void *base, size_t nmemb, size_t size,             int (*compar)(const void *, const void *));

二、万能指针:void*     在C语言中,任意类型的指针可以自动转换为void*,void*类型的指针也可以自动转换为任意类型
三、堆内存 什么是堆内存:     是进程的一个内存段(text、data、bss、stack、heap)     由程序员手动管理     特点是足够大,缺点是使用麻烦
为什么要使用堆内存:     1、随着程序的复杂数据量变多     2、其它内存段的申请和释放不受控制,堆内存的申请释放受控制
如何使用堆内存:     注意:C语言中没有任何控制堆内存的语句,只能通过C标准库提供的函数进行使用     #include <stdlib.h>     void *malloc(size_t size);     功能:从堆内存中申请size个字节的内存,申请成功会得到连续的内存     返回值:成功时返回申请到的连续内存的首地址,失败返回NULL     注意:malloc不会专门对申请到的内存清理为0
    void free(void *ptr);     功能:释放一段堆内存,只是释放使用权,不会专门清理内存数据     ptr:要释放的堆内存的首地址     注意:free不能连续释放同一个地址和非法地址         但是可以free(NULL)
    void *calloc(size_t nmemb, size_t size);     功能:从堆内存中申请nmemb个大小为size字节的一块连续内存     返回值:成功时返回申请到的连续内存的首地址,失败返回NULL     注意:通过calloc申请到的内存会全部清理为0         依然是一块连续的堆内存
    void *realloc(void *ptr, size_t size);     功能:改变已有堆内存块的大小     ptr:待调整的内存块首地址     size:是调整后的内存块的字节数     返回值:是调整后的内存块首地址,有可能会改变,因此必须重新接收新地址         如果不能在原内存块的基础上调整:             1、申请一块新的符合要求的内存块             2、把原内存中的内容拷贝到新内存中             3、把原内存释放并返回新内存的首地址     malloc的内存管理机制:     1、当首次向malloc申请内存时,malloc会向操作系统申请堆内存,操作系统会直接分配33页(1页=4096字节)内存给malloc管理,但这样不意味着可以越界访问,因为malloc可能会把内存分配给"其他人"使用,这样就产生了脏数据     2、每个内存块之间一定会有一些空隙(4~12字节),一部分空隙是为了内存对齐,其中一定有4个字节用于记录malloc的维护信息,如果维护信息被破坏会影响下一次的free的调用     使用堆内存时需要注意的问题:     内存泄漏:         内存无法使用,也无法被释放,当再次需要时只能重新申请,然后又重复以上过程,日积月累后会导致系统中可用的内存越来越少           注意:程序一旦结束,属于它的所有资源都会被操作系统回收         *如何尽量避免内存泄漏:             谁申请的谁释放,谁知道该释放谁释放         *如何判断定位内存泄漏:             1、查看内存的使用情况                 windows 任务管理器 Linux 命令ps -aux             2、代码分析工具mtrace,检查malloc、free的使用情况             3、封装新的malloc和free函数,记录调用信息到日志中             void* zzxx_malloc(size_t size)             {                 void* p = malloc(size);                 //  记录时间、行数、所属函数等信息到日志中                 return p;             }             void zzxx_free(void* ptr)             {                 free(ptr);                 //  记录到日志中             }
    内存碎片:         已经被释放但是又无法继续使用的内存叫做内存碎片,是由于申请和释放的时间不协调导致的,内存碎片无法避免只能尽量减少         *如何减少内存碎片:             1、尽量使用栈内存,栈内存不会产生内存碎片             2、不要频繁地申请和释放内存             3、尽量申请大块内存自己管理
内存清理函数:     #include <strings.h>     void bzero(void *s, size_t n);     功能:把一块内存全部清理为0     s:内存块的首地址     n:要清理的内存字节数
    #include <string.h>     void *memset(void *s, int c, size_t n);     功能:把内存块按字节设置为c     s:内存块的首地址     c:想要设置的ASCII码值     n:要设置的内存字节数     返回值:返回设置后的内存首地址 s         链式调用:一个函数的返回值可以作为另一个函数的参数             free(memset(p,0,100));     堆内存中定义二维数组:     指针数组:         类型名* arr[n];         for(int i=0; i<n; i++)         {             arr[i] = malloc(sizeof(类型)*m);         }         申请到 n行m列 的二维数组,每行内存可能不连续         注意:每一行的m值可不同,可以得到不规则的二维数组         缺点:容易产生内存碎片         优点:可以不规则、容易申请成功
    数组指针:         类型名 (*arrp)[m] = malloc(sizeof(类型)*m*n);         申请到 n行m列 的二维数组,并且全部内存都是连续的         优点:不容易产生内存碎片         缺点:相对而已对内存要求更高
    注意:无论哪种方式申请,最后都是当做二维数组访问arr[i][j]
    练习1:计算出100~1000之间的所有素数,存储到堆内存中,尽量不要浪费内存         1、向统计个数,再重新赋值         2、realloc 一边计算,一边扩容

标签:malloc,第十天,int,void,c++,内存,指针,size
From: https://www.cnblogs.com/mrlinan/p/17346013.html

相关文章

  • C++ - 多线程之初识多线程
    1.认识多线程传统的C++(C++11之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h>。C++11提供了语言层面上的多线程,包含在头文件<thread>中。它解决了跨平台的问题,提供......
  • Effective Modern C++ 学习笔记
    闲话今天是2023年4月23日,俺开始正式学习面试相关内容了。打算先从EffectiveModernC++这本书开始学起,作为日后代码风格、习惯的指导。不过俺没有一起学习的小伙伴,qwq。与ICPC切割之后,内心都轻松了许多。小醉一宿之后还是十分愉悦的。欢迎加入C++学习群:https://j......
  • 基于C++控制台的吃豆人小游戏
    访问【WRITE-BUG数字空间】_[内附完整源码和文档]玩家目标是吃掉所有豆豆,途中,若玩家撞到怪兽则游戏结束。游戏中存在超级豆子,吃到后,所有怪兽静止,且玩家进入无敌状态(可撞怪兽使之回到初始位置)。玩家可使用键盘方向键进行选择、控制移动,回车键确定,Esc键返回,空格键暂停。控制台小游戏......
  • C++创建对象时,有哪些内容?
    数据成员在类的作用域中,数据成员类似全局变量,而成员函数是操作数据成员的函数成员函数内联函数介绍目的:为了提高运行时的效率注意:在内联函数体中不要有复杂结构(如循环语句和switch语句)在类中声明内敛函数的方式:将函数体放在类的声明中使用inline关键词举例classPoin......
  • c++ vector容器类元素初始化,resize,reserve
    vector<Person>p;//此处Person为类名,仅此一行代码,会调用p(即vector本身)的构造函数,此时p是空的,其元素的构造函数并未被调用//p.reserve(3);//reserve函数预留空间,一下为源码template<typename_Tp,typename_Alloc>voidvector<_Tp,_Alloc>::reserve(size_ty......
  • [C++基础] 面向对象、C 与 C++ 区别篇
    [C++基础]面向对象、C与C++区别篇 一、面向对象1面向对象与面向过程的含义?1、面向对象面向对象是把数据及对数据的操作方法放在一起,作为一个相互依存的整体,即对象。对同类对象抽象出其共性,即类,类中的大多数数据,只能被本类的方法进行处理。类通过一些简单的外部接口与......
  • 团队项目第十天
    我们的项目预计3周完成,今天是第27天,实际完成度70%今天各成员完成度如下:彭锁群:今日完成:       明日目标:       遇到问题(已解决或未解决):杨凯文:今日完成:       明日目标:       遇到问题(已解决或未解决):杨康:  今日......
  • c++打卡训练(14)
    三色球问题:一共十二个球,红色白色都是三个,黑色有六个,摸出八个球,问有几种可能?流程图:伪代码:源代码:#include<stdio.h>intmain(){ intred,white,black; for(red=0;red<=3;red++){ for(white=0;white<=3;white++){ black=8-red-white; if(black<=6){ printf("红色:%d,......
  • 【CMU15-445 FALL 2022】Project #0 - C++ Primer
    关于参考&鸣谢课程官网CMU15445vscode/clionclang12cmake环境配置C++调试窗口显示“forstringvariable【CMU15-445数据库】bustubProject#0:Trie树实现(C++Primer)2022CMU15-445学习群——152391370前言按照课程要求,本文并不会给出实现代码,可以当做是我遇到问题的总......
  • C++课本第四章例题
    个人银行账户管理程序1#include<iostream>2#include<cmath>3usingnamespacestd;4classSavingsAccount{//储蓄账户类5private:6intid;//账号7doublebalance;//余......