还剩48页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
语言指针与内存复习课件C欢语针内习课针语战迎参加C言指与存复程指是C言中最强大也是最具挑性的针对为员关课将习概念之一,掌握指于成优秀的C程序至重要本程系统地复指针内关级应巩识编概念、存管理以及相的高用,帮助大家固知,提高程技能过针内将编写码通深入理解指和存管理,你能够更高效、更可靠的代,并避免常内关错误让们语见的存相我一起深入探索C言的核心机制!课程概述指针基础1们将顾针针我首先回指的基本概念,包括指的定义、声明、初始化和使用方法这础识杂针些基知是理解更复指操作的前提内存管理2们将讨语内栈内内静态内接着我探C言中的存管理机制,包括存、堆存、存以及态内释动存分配和放的方法高级指针概念3们将习级针数针级针针数组关然后我学一些高指概念,如函指、多指、指与的这识对开杂关系等,些知于发复程序至重要常见错误和最佳实践4们将讨论针时错误这错误践最后,我使用指的常见以及防范些的最佳实,帮助编写码你更安全、更可靠的代什么是指针?指针的定义指针的作用针储针让们指是一种特殊的变量,它存指我能够以更灵活的方式内数这访问数现对内的是存地址而非普通据据,实存的直接操内计内过针们态个存地址指向算机存中的作通指,我可以动分们访问内数结某个位置,使我能够间接配存、操作大型据构而不储数数现杂和操作那里存的据需要复制据,以及实复的数结链树据构如表和指针的特点针语区别级语对内级访问指是C言于其他高言的重要特性它提供了存的低时带来编杂错能力,同也了高效率和灵活性,但也增加了程的复性和出的可能性指针的重要性动态内存分配高效的数据结构操函数间数据传递作针们针许数调指使我能够在程序指允函修改其时内过针们现谓运行根据需要分配通指,我可以构用者的变量,实所编译时杂数结传存,而不必在确建和操作复的据的引用递效果通内这链树图过传针数定所需存的大小构,如表、和,递指而非据副态内对数们种动存分配能力而无需移动大量据本,我可以避免复制数针许们过数结于处理大小可变的据指允我通改变大型据构,从而提结数组链内来组数构(如、表、存引用重据,高程序性能树关过数等)至重要而不是通复制据本身指针声明语法指针类型针数针指的类型决定了它所指向的据类型例如,int型指只能指向int型针针针变量,char型指只能指向char型变量指类型影响指运算和解引用操作星号位置针时紧紧贴在声明指,星号*可以跟类型名,也可以变量名,或者位议于两者之间例如int*ptr、int*ptr和int*ptr都是有效的,但建读使用int*ptr格式以提高可性多指针声明当针时在一行中声明多个指,每个变量名前都需要有星号例如针则int*p1,*p2,*p3;声明了三个int型指,而int*p1,p2,p3;只针声明了一个指p1和两个普通int变量p2和p3指针初始化声明指针针时针首先声明一个指变量,例如int*ptr;此指尚未指向任内导为何有效的存地址,使用它可能致未定义行未初始化的指针称为针应该被野指,避免使用定义目标变量创标这将内建一个目变量,例如int x=10;个变量在存中占内们让针这用一定空间,并有一个唯一的存地址,我可以指指向个地址获取地址并赋值获内将赋给针使用地址运算符取变量的存地址,并其值指,现储内们说例如ptr=x;在ptr存的是变量x的存地址,我ptr指向x指针解引用读取值如果ptr指向变量x,那么*ptr就等价于x2解引用操作符的值例如,如果x的值是10,那么表达们式*ptr也会得到值10我可以使用来针时访问printf%d,*ptr;打印指所指向星号*用作解引用操作符,它指针内储所指向的存位置中存的值解引1的值读针数用操作可以取或修改指指向的据修改值获内例如,*ptr表示取ptr指向的存位置来针中的值解引用操作也可以用修改指所指向的将储3值例如,*ptr=20;会值20存到内ptr所指向的存位置,如果ptr指向x,那么x的值就会变成20空指针的定义使用场景初始化实践NULL针针针针内编习惯将对NULL是一个特殊的指常量,表示指空指常用于表示指尚未初始化、存良好的程是未指向任何象的指内语败针对针为这针不指向任何有效的存地址在C言中,分配失、或指所指向的象不再有效初始化NULL,样可以明确指的为数讲进针检针状态续进检NULL通常被定义整0,但从概念上,在行指操作前,通常需要查指是,并在后操作中行安全查例针为针导检它代表无效指或不指向任何地方的否NULL,以避免解引用NULL指致如int*ptr=NULL;随后可以查针溃进指的程序崩ifptr!=NULL再行操作指针运算1指针加减整数2指针相减当们对针进时针我指行加减运算,两个相同类型的指相减会得针针们数指的移动量取决于指类型到它之间的元素个,而不对节的大小例如,于int*p,是字差例如,如果p和q都针针p+1会使指向前移动是int型指,且p比q大8个字节仅仅节则结sizeofint个字,而不,p-q的果是2(假设节这针节这数是1个字使得指运算int占4字)种运算在应数组别自动适不同据类型的大小处理中特有用3指针比较关较针当针可以使用系运算符(如==、!=、、)比指的大小两个指数组时这较们数组对指向同一个的不同元素,种比可以确定它在中的相针较数组链时位置指比在处理和表经常使用指针与数组语数组为数组针对数组数组这关在C言中,名可以视指向第一个元素的指常量例如,于int arr
[5],名arr等同于arr
[0]种等价系使得们针语访问数组我可以使用指法元素,如*arr+i等同于arr[i]数组针区别数组赋针针访问数组别然而,名与指也有重要名是常量,不能被值;而指是变量,可以修改使用指通常更灵活,特是在处数组将数组传给数时针术数组历简单来历数组理的子集或递函指算使得遍变得高效,例如,可以用*ptr++遍元素指针与字符串字符串的内存表示字符指针与字符串字面量字符串操作函数语为针标库许数在C言中,字符串被表示以空字符\0字符指常用于指向字符串例如,char C准提供了多用于字符串操作的函,结数组这尾的字符例如,字符串Hello在*str=Hello;使str指向字符串字面量如strcpy、strcat、strcmp等些内储为数针为数过针存中存{H,e,l,l,o,\0}字符Hello需要注意的是,字符串字面量通函通常接受字符指作参,通指数组针这储读内区应尝试过来数串可以用字符或字符指表示,两种常存在只存域,因此不通操作处理字符串,避免了不必要的据复细别针们则导方式在使用上有微差字符指修改它,否可能致未定义行制,提高了效率为函数指针函数指针定义1数针数针储数们调数数针函指是指向函的指变量它存的是函的入口地址,使我能够间接用函函指的声明需数数要指定返回类型和参列表,以匹配可能被指向的函函数指针声明语法2数针语为针数函指的声明法返回类型*指名参类型列表;例如,int数数针*func_ptrint,int;声明了一个指向接受两个int参并返回int的函的指函数指针应用数针现调数态数调3函指主要用于实回机制、函表和动函度例如,将数针传给数较逻辑创可以函指递排序函,以自定义比;也可以数针数组现简单状态建函指,实命令分派表或的机多级指针三级指针***1级针针指向二指的指二级指针**2针针指向指的指一级指针*3数针指向据的指数据4储内存在存中的实际值级针针链级针级针级针数级针级针级针级针多指是指的概念,其中每一指都指向下一指一指指向据,二指指向一指,三指指向二指,以此类推例如,int x创级针针数=10;int*p=x;int**pp=p;建了一个二指pp,它指向指p,而p指向整x级针针场数传针杂数结维数组针数组虽论多指主要用于需要修改指本身的景,如在函中修改入的指值,或处理复的据构如
二、指等然理上可以无限嵌套,但级针为码读剧实际上很少使用三以上的指,因代可性会急下降指针void通用性类型转换1针数语void指可以指向任意类型的据,是C言2转换为针针使用前需要具体类型的指中的通用指限制4内存操作3进针术内数不能直接行解引用和指算常用于通用存操作函针针数须转换为针void指是一种特殊的指类型,可以指向任何类型的据,但在使用前必具体类型的指例如,void*vp=some_int;int*ip=int将数赋给针转换针*vp;先整地址void指,然后再回int指使用标库许数针现内数准中的多函使用void指实通用功能,如malloc返回void*,使其能够分配任何类型的存;memcpy接受void*参,能够复制数针这语现关数结任何类型的据void指的种通用性使得C言能够实类型无的算法和据构与指针const指向常量的指针常量指针const int*ptr或int const*ptr int*const ptr表示ptr本身的值过表示ptr指向的值不能通ptr修改,(即它所指向的地址)不能改变,这过但ptr本身可以改变指向种指但可以通ptr修改所指向的值针数数数这针须时通常用于函参,表明函不种指必在声明初始化,并数终内会修改指向的据例如,const且始指向同一个存位置它通访问场char*strcpyconst char*dest,常用于需要固定点的景数const char*src中的src参指向常量的常量指针结const int*const ptr合了上述两种限制,表示ptr既不能改变指向,也过这针严数不能通它修改所指向的值种指提供了最格的保护,确保据不会场被意外修改,常用于需要高度安全性的景内存布局代码段(Text Segment)码储码这内读码编译时代段存程序的机器指令部分存通常是只的,以防止程序意外修改自己的指令代段的大小在确定,在程序运行期间保持不变数据段(Data Segment)数储静态这内时结时释数为读数储读写数储据段存已初始化的全局变量和变量部分存在程序启动被分配,并在程序束放据段通常被分只据段(存常量)和据段(存可修改的全局变量)BSS段(BSS Segment)储静态这时为执载时内BSS段存未初始化的全局变量和变量些变量在程序启动被自动初始化零BSS段不占用可行文件空间,只在程序加分配存堆(Heap)态内区当调数时内时缩资堆是用于动存分配的域程序用malloc、calloc等函,存从堆中分配堆的大小可以在运行增长和收,但受到系统源限制栈(Stack)栈储数调数数栈内当进数时数时释栈归过导栈用于存函用信息、局部变量和函参的存分配是自动的入函分配,退出函放的大小通常有限,递深可能致溢出栈内存1自动分配和释放2LIFO操作机制栈内显栈进存的最著特点是其自动化遵循后先出(LIFO)的操内当执进则盘的存管理程序行入一作原,就像一摞子最后放数时该盘这结个作用域(如函),作用上去的子最先被拿走种内栈数调现域的局部变量会在上自动分构使得函用和返回的实非内当开该时这为当数栈帧配存;离作用域,常高效,因前函的总内释这栈顶些变量的存会自动放种是位于内自动化机制减少了存泄漏的风险3栈的局限性栈编译过数调的大小通常是固定的,受系统或器设置限制深的函用嵌套(特别归导栈错误栈内当是递)可能致溢出此外,上分配的存只在前作用域有效,数对这应虑内不能用于需要长期存在的据于些情况,考使用堆存堆内存说特点明示例态时动分配程序运行根据需要分配int*p=mallocsizeofint;显释则内手动管理需要式放,否造成存泄漏freep;显释数生命周期从分配到式放跨函和作用域使用时大小灵活可在运行确定大小int*arr=mallocn*sizeofint;访问栈内开销速度比稍慢存分配系统时产内释碎片化长间运行可能生存碎片反复分配放不同大小的块静态内存全局变量静态局部变量静态全局变量数储静态关键数内静态关键全局变量在函外部定义,存在程序的局部变量使用static字在函全局变量也使用static字定义,数们们数们据段中它的生命周期与程序运行周部定义与普通局部变量不同,它不会但位于函外部它与普通全局变量的开执时数时销区别静态期相同,从程序始行初始化,直到在函返回毁,而是保持其值直到程主要在于可见性全局变量只在结销结静态调数内程序束才被毁全局变量可以被程序序束局部变量只在首次用函定义它的源文件可见,不能被其他文件数访问这码时数调访问这中的任何函,但也增加了代的初始化一次,之后的函用都会使用直接种文件作用域限制提高了耦合度已存在的值程序的模块性动态内存分配malloc函数原型参数1请节数2void*mallocsize_t size;size求分配的字使用注意返回值43进转换检内针败需行类型并查返回值成功返回分配存的指,失返回NULL数节数内该内针内内针malloc函从堆上分配指定字的存块,并返回指向存块的指分配的存不会被初始化,其容是不确定的malloc返回void指,使用前转换为当通常需要适的类型时关键虑请内计别数组时终检为内败对使用malloc的考因素包括确保求的存大小算正确,特是涉及;始查返回值是否NULL,以处理存分配失的情况;配数释内内释内访问这导溃预测为使用free函放不再需要的存,避免存泄漏;避免使用已放的存或越界,可能致程序崩或不可的行使用示例malloc分配单个整数这码储数内int*p=int*mallocsizeofint;行代分配足够存一个整的存,并返回指该内针内数向存的指sizeofint确保分配正确大小的存,不管整在不同系统上的大小如何分配整数数组这码纳数内int*arr=int*malloc10*sizeofint;行代分配一个能容10个整的数组论存块使用sizeofint乘以长度可以确保无int类型的大小如何,都能分配足内够的存检查返回值内败内if arr==NULL{fprintfstderr,存分配失\n;exit1;}存分配可能资败编践检因系统源限制而失良好的程实是查malloc的返回值,并在分配失败时当错误采取适的处理措施使用分配的内存内数组一旦成功分配存,就可以像使用普通一样使用它for int i=0;i10;过针术i++arr[i]=i;或通指算for inti=0;i10;i++*arr+i=i;动态内存释放free函数原型数针数该针须free函的原型是void freevoid*ptr;它接受一个指参,指必是之前过数获数没执内通malloc、calloc或realloc函得的free函有返回值,它只行释存放操作使用规则数释态内释态内栈free函只能用于放动分配的存放非动分配的存(如上的变量)或释过内释导为严错误已经放的存(重复放)会致未定义行,通常会造成重,如程序崩溃内损或存坏内存泄漏防范记调数释内导内践忘用free函放不再使用的存是致存泄漏的主要原因良好的实是在内码径应调错误径分配存后,确保在所有可能的代路上都有相的free用,包括处理路指针置空调针悬针释内为误议调用free后,指变成挂指,指向已放的存避免用,建在用将针为这码尝试释free后指设NULL freeptr;ptr=NULL;样,如果代使用已放针针错误预测为的指,至少会得到空指,而不是不可的行函数calloc函数原型初始化为零使用场景数别calloc函的原型是calloc与malloc的calloc特适合分配关键区别为void*callocsize_t在于,calloc需要初始化零的大型将内数组num,size_t size;它会分配的存全部初例如,int*arr=内来储为这对分配足够的存存始化零于需要int*calloc1000,为数结创num个大小size的元零初始化的据构非sizeofint;建一个内数组结为素,并返回指向分配常有用,如或构包含1000个已初始化针额数数组这存的指与malloc体,可以避免外的初零的整的比败时骤一样,calloc失始化步malloc后手动初始化简返回NULL更洁函数realloc12函数原型返回值处理数时内针realloc函的原型是void*reallocvoid*ptr,realloc成功返回指向重新分配存的指,内针败时size_t new_size;它改变已分配存块的大可能与原指相同或不同失返回NULL,扩缩满内为败时小,可以大或小如果原位置无法足新大但原存块保持不变避免在失丢失原指将数针应临时储小,realloc可能会据移动到一个新位置,使用变量存返回值3数据保留内内realloc保留原存块的容如果新大小比原额内大小大,外的存空间不会被初始化如果新数将断这大小比原大小小,超出部分的据被截数别态种保留原据的特性使realloc特适合动增数结长的据构内存泄漏检测工具1专进检测使用业工具如Valgrind行防范措施2内习惯码结良好的存管理和代构后果3内溃性能下降、存不足、程序崩原因4释态内未放不再使用的动存定义5内释现程序分配存但未放的象内执过内没释现记调内针环导释错误存泄漏是程序行程中,分配的存在不再需要后有被正确放的象常见原因包括忘用free;丢失指向已分配存的指;循引用致的无法放;异常或处径内释码理路中缺少存放代内导内渐终导缓内尽溃资环内为严长期运行的程序中,存泄漏会致可用存逐减少,最可能致程序性能下降、运行慢,甚至因存耗而崩在嵌入式系统或源受限的境中,存泄漏的影响尤重内关键养内习惯内对应释码防范存泄漏的是成良好的存管理,确保每次存分配都有的放代悬挂指针定义危害1释内针导溃数损2指向已放存的指可能致程序崩或据坏防范措施常见原因43释释内将针放后立即置NULL并避免使用放存后未指置NULL悬针称为针针释内针当们调释态内应针挂指(也迷途指或野指)是指向已经被放或已经无效的存地址的指我用free放动分配的存后,相的指变量仍然释内这时为悬针保存着被放存的地址,它就成了挂指悬针访问内为导溃数损别释内给时过悬使用挂指存是未定义行,可能致程序崩、据坏或安全漏洞特危险的是,被放的存可能被重新分配其他用途,此通挂指针进难错误悬针调将针为这对误行的修改可能会影响程序的其他部分,造成以追踪的防范挂指的最佳做法是在用free后立即指设置NULL,样任何它的用都检测针错误会触发可的空指缓冲区溢出缓区试图缓区写数为节数组写节数语进检冲溢出是指程序在冲边界之外入据的情况例如,向大小10字的入15字的据C言不行自动边界缓区导错误内区数预测查,因此冲溢出不会立即致,但会覆盖相邻存域的据,造成不可的后果缓区仅导溃数损还许击过缓区冲溢出不会致程序崩或据坏,是多安全漏洞的根源攻者可以通精心构造的输入触发冲溢出,覆盖返回地址数针执恶码为缓区应内数验证数或函指,行意代防止冲溢出,使用安全的字符串和存处理函(如strncpy代替strcpy),输入据,并在编译时缓区检测启用冲溢出工具指针与结构体结构体指针声明访问结构体成员结针语结过结针访问员时定义构体指的法是struct通构体指成,使用箭针构体名*指名;例如,struct头运算符-stuPtr-age等价于结Student*stuPtr;声明了一个指向*stuPtr.age箭头运算符合了结针结针员访问访问结Student构体的指构体指解引用和成操作,是构过态员简当数传可以通malloc动分配,也可以体成的便方式在函间递结结时针指向已有的构体变量stuPtr=大型构体,使用指可以避免复结student;制整个构体,提高效率结构体数组与指针创结数组针历可以建构体并使用指遍struct Studentstudents
[100];struct过针术历结数组Student*p=students;通指算运算可以高效地遍构体for这结inti=0;i100;i++{p+i-age=20;},里p+i指向第i个构体自引用结构链表节点二叉树节点图节点链结应链节树节数节图数结节表是自引用构的经典用每个表二叉点通常包含据和两个指向子点据构中,点可能包含指向多个其他数节针针节针为现点包含据和指向下一个点的指例如的指struct TreeNode{int data;点的指,通常作邻接表实structstruct Node{int data;struct Nodestruct TreeNode*left;struct TreeNodeGraphNode{int data;struct ListNode过这们创这结许杂树这*next;};通种自引用,我可以建*right;};种构允构建复的形*neighbors;};里的neighbors是一个链现数结树链储当节节任意长度的表,实高效的插入和删除操据构,支持高效的搜索、排序和其他表,存所有与前点相邻的点作操作指针数组定义1针数组数组针指是一个,其元素是指例如,int*ptr_array
[10];声明了一针数组数组数数个包含10个整型指的每个元素都可以指向一个整变量或整数组针数组内连续储针指在存中是存的指变量初始化2针数组时赋指可以在声明初始化,也可以逐个元素值例如,int a=1,b=2,针数组c=3;int*ptr_array
[3]={a,b,c};初始化了一个包含三个指的,别数分指向三个整变量应用场景3针数组针场针指常用于需要集中管理多个指的景,如管理多个字符串(字符指数组现数组态数结数)、实柔性、管理多个动分配的据构等例如,argv参针数组数就是一个字符指,每个元素指向一个命令行参字符串数组指针定义与声明初始化与使用与多维数组的关系数组针数组针针数组针数组数组针维数组时别指是指向的指,而不是指指可以指向一个实际的int指在处理多特有用例数组语为针数组维数组数组声明法类型*指名[array
[10];int*arr_ptr
[10]=array;如,二int arr
[3]
[4]的名arr是访问数组过数组针为将大小];例如,int*arr_ptr
[10];声明了元素可以通*arr_ptr[i]或一个指,类型int*
[4]多数数组针数组维数组传给数时数组针一个指向包含10个整的的指括arr_ptr
[0][i]由于名本身就是指向递函,通常使用指没针为数号很重要有括号int*arr_ptr
[10]表首元素的指,所以arr_ptr是一个指向作参void funcint*arr
[4],int针数组数组针仅仅数组示指整个的指,而不是元素rows指针与多维数组二维数组内存布局维数组内为单连续储内二在存中是以行位存的例如,int arr
[3]
[4]在存连续数数连续数组中占用12个的整空间,可以看作3个包含4个整的理解这内对针维数组关种存布局于使用指操作二至重要访问二维数组元素针术访问维数组可以使用指算二元素如果p指向arr
[0]
[0],那么*p维数组+i*4+j等价于arr[i][j](假设每行4个元素)二名arr可以看数数组针为作是指向包含4个整的的指,类型int*
[4]传递多维数组给函数传维数组给数时维维须递多函,除第一外的所有度大小必指定例如void funcintarr[]
[4],int rows;或void funcint*arr
[4],这为编译计int rows;是因器需要知道如何算元素偏移量指针与动态多维数组1动态分配二维数组2连续内存分配针数组创数为获连续内使用指可以建行可变的得存布局,可以先分配维数组内二int**matrix=int一块大存int*data=int**mallocrows*sizeofint*;*mallocrows*cols*为内创然后每行分配存forint i=sizeofint;然后建指向各行针数组0;irows;i++matrix[i]=int起始位置的指int*malloccols*sizeofint;**matrix=int**mallocrows这许数种方法允每行有不同的列,*sizeofint*;forint i=0;i内连续但存不是的rows;i++matrix[i]=data+i*cols;3内存释放注意事项释态维数组时顺对须释释放动二,序很重要于第一种方法,必先放每行,再针数组放行指forint i=0;irows;i++freematrix[i];freematrix;对释数内释针数组于第二种方法,先放据存,再放指freedata;freematrix;指针与文件操作FILE指针标库过结针进结在C准中,文件操作通FILE构体和FILE指行FILE构体封装了文件的各种信缓区当针这结针息,如文件描述符、冲、前位置等FILE指是指向种构体的指,用于在各种数传文件操作函间递文件信息文件打开与关闭数开针开fopen函打文件并返回FILE指FILE*fp=fopenfilename.txt,r;打模读写须调关闭式包括r()、w()、a(追加)等使用完文件后,必用fclosefp释资数写盘文件,放源并确保据被入磁文件读写读写数针文件函如fread和fwrite使用FILE指指定操作的文件例如,freadbuffer,size,读数将count,fp从fp指向的文件取据到buffer;fwritebuffer,size,count,fp buffer中数写的据入fp指向的文件错误处理败权数败时文件操作可能因各种原因失,如文件不存在、限不足等函如fopen失返回应检当错误NULL,查返回值并适处理iffp==NULL{perrorError openingfile;exitEXIT_FAILURE;}指针与命令行参数argc和argv参数解析类型转换数过数数历数组数转在C程序的main函中,可以通参接收处理命令行参通常涉及遍argv,解命令行参以字符串形式提供,通常需要验证数换为当将数转换命令行输入int mainintargc,char析和每个参例如,forint i=1;i适的类型例如,字符串参数数对杂为数*argv[]argc表示参量(包括程序argc;i++{/*处理argv[i]*/}于复整int value=atoiargv
[1];或浮点针数组专数库数应验名),argv是一个字符指,每个元素的命令行界面,可以使用门的参解析,double value=atofargv
[1];数证转换结指向一个参字符串第一个元素argv
[0]如getopt果以确保有效性通常是程序名函数指针数组数针数组储数针数组许们过态选择调数语为数组数函指是一个存函指的,允我通索引动要用的函声明法返回类型*名[大小]参列表;数针数组数数例如,int*funcArr
[5]int,int;声明了一个包含5个函指的,每个函接受两个int参并返回int数针数组现调状态创数组函指常用于实度表、命令处理器或机例如,可以建一个操作int*ops
[4]int,int={add,subtract,过调这语简别multiply,divide};,然后通索引用result=ops[op_code]a,b;种方法比使用大量if-else或switch句更洁高效,特是数调时在处理大量类似函用回调函数定义机制1调数传给数数回函是被递另一个函的函,由后过数针现数数2时调通函指实函参化,增强灵活性者在某个间点用实现方式使用场景4调数传数针当时3定义回函类型、递函指、在适调事件处理、排序算法、异步操作等机用调数编术许们将数为数传给数这们码扩回函是一种强大的程技,允我函作参递其他函种机制使得我可以在不修改原有代的情况下,自定义和展程为标库数过调数许规则序的行例如,准函qsort通回函允用户定义排序qsortarray,size,sizeofint,compare现调骤调数现调数针数调数将传给数实回机制通常包括三个步定义回函类型(通常使用typedef);实接受回函指的主函;定义回函并其递主函调数驱编图络编领应现扩软关键术回函在事件动程、形用户界面、网程等域广泛用,是实灵活、可展件系统的技指针与位操作内存映射IO位级寄存器操作直接内存访问对进场过针在嵌入式系统中,硬件设备的寄存器常常映硬件寄存器通常需要特定位行操作,而在需要高性能的景中,直接通指操作内过这过针内绕过缓层射到特定的存地址通指向些地址的不是整个寄存器通指和位操作符,我存可以操作系统的存和抽象,提针们读写们现这细内访问过指,我可以直接硬件寄存器,控制可以实种精控制*gpio|=1供最高效的存例如,通mmap为数获内区针读设备行例如,volatile unsigned int5;设置第5位;*gpio=~13;清除第函取存映射域的指,可以直接将检写内*gpio=unsignedint*0x40020000;3位;*gpio14查第4位文件或设备存void*addr=针内指指向GPIO控制寄存器的存地址mmapNULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0;指针别名typedef定义指针类型提高代码可读性为杂针创针别码typedef可以复的指类型建指类型名可以大大提高代的可简别读别对杂针洁的名例如,typedef int性,特是于复的指类型创*FuncPtrint,int;建了一个名例如,typedef char*String;使得为针FuncPtr的类型,表示指向接受两字符指的用途更加明确在声明多数数针针时个int参并返回int的函的指个相同类型的指,使用typedef这别杂针错误种名使得复指类型的声明和可以减少重复并避免String简单使用变得更加name,address,message;抽象和封装针别还数指类型名可以用于抽象和封装据类型例如,可以定义一个指向不透明结针过数构的指类型typedef structList_Struct*List;,然后通函接口操作内现细节这术现数List类型,而不暴露其部实种技是实抽象据类型的常用方法指针与内联汇编内联汇编基础1内汇编许码汇编关键内联允在C代中嵌入指令,通常使用asm或__asm__字联汇编访问针可以C变量,包括指例如,__asm__movl%0,%%eax::r内存操作2将针载ptr;指值加到eax寄存器过内汇编汇编针内通联,可以使用指令直接操作指指向的存例如,将储内这指针运算优化__asm__movl$1,%0::r ptr;值1存到ptr指向的存位置3术内场种技在需要精确控制存操作的景中非常有用针过内汇编现执杂针术某些指操作可以通联实更高效的行例如,复的指算或位汇编级别过现编译操作可能在更高效不,代器的优化能力很强,只有在确实需平台相关操作4应内汇编要的情况下才使用联优化内汇编现关访问执权联常用于实平台相的特殊操作,如特殊寄存器、行特指令或这针访问内现层原子操作些操作往往涉及指操作,如存映射的硬件设备或实底语同步原智能指针概念智能指针起源基本原理语言模拟实现C针传针针对语过结数智能指是C++中的概念,旨在解决统智能指是包装了原始指的象,它自在C言中可以通构体和函模拟智针问题内悬针内别资释针为针指管理的,如存泄漏、挂指动处理存管理,特是源的放智能指行例如,定义一个包含指和虽语针针过资获计数结现创销等然C言本身不支持智能指,但能指通RAII(源取即初始化)原引用的构体,实建、复制和这现内则对结时释资数销时检计数了解个概念有助于理解代存管理思,在象生命周期束自动放源,毁函,并在毁查引用以决定语现内难错误释内虽现想,也可以在C言中模拟实类似功能避免了手动管理存的困和是否放存然不如C++的实优雅,但可以提供类似的安全性指针安全性输入验证时须验证数别当这数将计内在处理外部输入,必据的有效性,特是些据用于算存地址缓区时这检负过导访问或确定冲大小包括查值、大值或其他可能致越界的异常情况当验证许缺乏适的输入是多安全漏洞的根源边界检查访问数组过针内时应严检在或通指操作存,格查边界条件,确保不会越界例如,在环针时应检终循中使用指,明确设置和查止条件for int*p=arr;parr+size;虑数p++考使用安全函如strncpy代替strcpy空指针检查针终检针为在解引用指之前,始查指是否NULL例如,if ptr!=NULL{*ptr=这针导溃数针数时应value;}可以防止因解引用空指致的程序崩在函中接收指参,虑许档说考是否允NULL,并在文中明确明安全释放释内将针为悬针放存后,立即指设NULL,以防止挂指freeptr;ptr=NULL;在释检针释放前,查指是否已经是NULL,以避免重复放if ptr!=NULL{freeptr;ptr=NULL;}内存对齐4816字节对齐结构体对齐对齐影响内对数储关结编译节内对对针进存齐是指据存地址与其大小的系在构体中,器会自动插入填充字以确存齐指操作有直接影响例如,在许数须储员对这导结针术时须虑对态多CPU要求特定类型的据必存在其大保每个成都正确齐可能致构体的行指算,必考齐要求;在动分数节员编译内时数对内小的整倍地址上例如,4字的int可能需总大小大于所有成大小之和可以用器配存,分配函通常会返回正确齐的储数对内访问进数络协议时要存在4的倍地址上未齐的存指令如#pragma pack或存块;在处理二制据或网,可能导错对为对问题可能致性能下降,某些架构甚至会出__attribute__packed控制齐行,但需要处理齐以确保兼容性应谨为过慎使用,因度优化可能影响性能内存泄漏检测工具1Valgrind2AddressSanitizer内调试Valgrind是一款强大的存AddressSanitizer是一种由别组编译时工具,特是其Memcheck件LLVM/Clang和GCC提供的检测内错误内过编译时检测可以各种存,包括存工具它通在插入代内码检测缓区释泄漏、使用未初始化的存、越界,可以冲溢出、放后访问过释错误等Valgrind通模拟CPU使用、双重放等与执内行程序,跟踪每一次存操作,Valgrind相比,详细错误报势因此能够提供的告,包AddressSanitizer的优在于速对较括泄漏的位置和大小度更快,程序性能影响小3其他工具还许内检测除了Valgrind和AddressSanitizer,有多其他存工具,如Electric检测缓区检测内Fence(用于冲溢出)、LeakTracer(用于存泄漏)、Purify(商业工具)等Windows平台上有Visual LeakDetector和Application选择时应虑项Verifier工具考目需求和平台限制指针与并发编程线程安全问题互斥锁保护线环线时访问在多程境中,多个程可能同锁内区导数竞使用互斥(如pthread_mutex_t)保和修改同一存域,致据争、不数线问题针时护共享据是确保程安全的常用方法一致性或其他并发使用指尤其访问针针数获为针对内12在共享指或指指向的据前取需要注意,因指提供了存的直接锁访问释锁访问导访问,后放,可以防止并发,增加了不安全操作的可能性问题致的线程局部存储原子操作线储使用程局部存(Thread Local对简单针数43于的指更新,可以使用原子操作Storage,TLS)可以避免某些共享据锁标问题代替互斥,提高性能C11准引入了的并发在C11中可以使用库针关键线原子操作(),提供了原子指操作函_Thread_local字声明程局部变量,数线独,如atomic_store、atomic_load、每个程都有自己的立副本,无需同步访问atomic_exchange等即可安全垃圾回收语言的手动内存管理C1语内员负责释内这错导C言采用手动存管理方式,程序分配和放存种方式提供了最大的控制和效率,但也容易出,致内释内存泄漏或使用已放的存垃圾回收基本原理内术时识别释内2垃圾回收是一种自动存管理技,由运行系统自动和放不再使用的存垃圾回过对关对们收器通常通跟踪象引用系,确定哪些象不再可达(即垃圾),然后回收它占用内的存语言中模拟垃圾回收C虽语标过库现然C言准不包含垃圾回收,但可以通第三方或自定义实3简单计数标记的垃圾回收机制例如,使用引用、-清除或分代收集内现内等算法,配合特殊的存分配器,可以在C程序中实有限的自动存管理常见指针错误未初始化指针悬挂指针重复释放针悬针针对内区调未初始化的指包含随机值,使用挂指(或野指)是指向同一存域多次用free会导溃释内针悬导严错误内它可能致程序崩或更糟的情况,已放或无效存的指使用致重,可能破坏存分配数损终针时针导预测为内数结问题如据坏始在声明指初挂指会致不可的行常器的部据构避免此的释内继续简单释针将始化它,可以是NULL、有效地址见情况包括放存后使用方法是在放指后立即其过内针针为调检或通malloc分配的存例指;返回局部变量的地址;指设NULL,并在用free前储针为如int*ptr=NULL;或int*ptr超出作用域但被存在全局变量中查指是否NULL ifptr!==var;NULL{freeptr;ptr=NULL;}缓冲区溢出缓区尝试写过冲溢出是指程序入超内数这导分配存边界的据可能致数损溃据坏、程序崩或安全漏洞针内时应终检使用指操作存始查边数界条件,并使用安全的字符串函如strncpy代替不安全的strcpy指针使用最佳实践针践终针针暂时良好的指使用实可以极大地提高程序的可靠性和安全性首先,始初始化指,避免使用未初始化的值;如果指不指向有效对将为针检为别对过数数传针象,其设NULL其次,在使用指前查是否NULL,特是于通函参入的指饰针数对应数饰对应合理使用const修符可以防止指或指向的据被意外修改例如,于不修改的输入参,使用const修;于不改变指向的针针为针内尽针释内将针为指,使用指常量此外,指明确定义生命周期,确保只在有效期使用;量减少全局指的使用;在放存后指置悬针释惯标针权NULL,防止使用挂指最后,采用一致的命名和注例,明确示指的用途和所有调试技巧使用调试器内存检查工具静态分析调试检针内静态执码检器是查指和存的强大工具GDB除了前面提到的Valgrind和分析工具可以在不行代的情况下调试许检内内还许专测问题(GNU器)允您查变量、存容AddressSanitizer,有多门的工具潜在工具如Clang Static状态检测诊断内关问题和程序常用命令包括p(打印变量可以帮助和存相例如,Analyzer、Coverity、PVS-Studio和检内内监检测内访问错误现许针错值)、x(查存容)、watch(视Dr.Memory可以存泄漏和;Cppcheck可以发多常见的指使用显针内误针内变量变化)例如,使用p ptr示指值,memwatch和mpatrol提供了存分配的,如未初始化、空指解引用、存泄漏显针检测库这过使用p*ptr示指指向的值,使用x/10x跟踪和功能;debug_malloc可以替等些工具通常可以集成到构建程中,针进换标内数额检续码质检ptr查看指指向的10个16制值准存分配函,提供外的查提供持的代量查总结与展望深入学习1级数结编高据构和系统程实践应用2过项巩针内通目固指和存管理技能最佳实践3编码标辅采用安全准和工具助核心概念4针础内掌握指基和存管理课们习语针内础针级题数针维数组编针在本程中,我系统地复了C言中指和存管理的核心概念,从基的指声明、初始化和操作,到高主如函指、多和并发程中的指安全性们讨针错误践编写码我也探了常见的指和最佳实,帮助你更可靠、更安全的代针语战议进习资计语讲语专编指是C言的精髓,掌握它既是挑也是机遇建一步学的源包括《C程序设言》KR深入解C言核心概念;《C家程》Expert C讨级题错误线资编Programming探高主和常见陷阱;《C陷阱与缺陷》C Trapsand Pitfalls帮助避免常见;以及在源如cppreference.com和GeeksforGeeks的C程过续习践将针时部分通持学和实,你能够充分利用指的强大功能,同避免其潜在风险。
个人认证
优秀文档
获得点赞 0