还剩25页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
《程序设计指针》课件分享C欢迎参加《C程序设计指针》课程!本课程将深入探讨C语言中最强大也最具挑战性的特性之一指针通过本课程,您将全面掌握指针的基础知识、操作技巧以及在实际编程中的应用主讲人王教授日期2025年5月10日课程代码CS-301课程概述指针概念及基础知识详细介绍指针的本质、声明方式及初始化技巧,建立坚实的理论基础指针操作和内存管理掌握指针的算术运算、类型转换以及动态内存分配与释放常见应用场景和实例通过实际案例讲解指针在数据结构、函数参数传递中的应用指针使用的最佳实践学习业界公认的指针使用规范和技巧,提高代码质量学习目标12理解指针的本质和内存模型掌握指针的声明和使用掌握计算机内存的基本结构,了解指针作为内存地址的实熟练掌握各类指针的声明语法、初始化方法,能够正确应质含义,建立清晰的内存模型概念用指针读取和修改数据34学会使用指针进行内存管理掌握指针与数组和函数的关系掌握动态内存分配函数的使用,理解内存泄漏的成因与预理解指针与数组的深层联系,能够使用函数指针实现回调防,实现高效的内存管理机制和高级编程技术第一部分指针基础指针的本质指针的目的指针是一种特殊的变量,存储的指针的设计目的是提供对内存的是内存地址而非数据本身理解间接访问能力,实现对数据的高指针首先要明确内存地址的概念效操作和管理通过指针,我们以及变量在内存中的存储方式可以在不复制数据的情况下处理大型数据结构指针的基本操作掌握指针的声明、初始化、解引用等基本操作是学习指针的第一步这些操作构成了使用指针的基础技能集什么是指针?指针的定义指针的表示指针是一种特殊的变量,它存储的值是另一个变量在内存中的地内存地址通常以十六进制表示,如0x7fff5fbff7c8在不同的系址通过这个地址,我们可以间接地访问和修改另一个变量的统中,地址的长度可能不同,32位系统通常是4字节,而64位系值这种间接访问机制使得指针成为C语言最强大的特性之一统则是8字节在C语言中,我们使用运算符获取变量的地址,使用*运算符通在内存模型中,每个变量都占据一定的内存空间,而每个内存单过指针访问指向的变量这种机制允许我们在不知道变量具体名元都有一个唯一的地址指针正是通过存储这些地址来指向这称的情况下,对其进行操作些变量的内存模型简介代码段存储程序的可执行机器代码数据段存储全局变量和静态变量堆动态分配的内存,由程序员管理栈存储局部变量和函数调用信息计算机内存可以看作是一个巨大的字节数组,每个字节都有一个唯一的地址在32位系统中,地址为4字节长,可以表示高达4GB的内存空间;而在64位系统中,地址为8字节长,理论上可以表示极其庞大的内存空间为什么需要指针?高效传递大型数据结构动态内存分配和管理当函数需要处理大型数据结构指针是实现动态内存分配的关时,通过传递指针而非复制整键工具通过malloc等函数分个数据结构,可以显著提高程配的内存只能通过指针访问,序性能这种方式避免了不必使程序能够根据运行时需求灵要的内存消耗和数据复制开活分配和释放内存资源销实现复杂数据结构指针是实现链表、树、图等复杂数据结构的基础这些数据结构中的节点通过指针相互连接,形成灵活而高效的数据组织方式指针的声明基本语法星号位置多指针声明指针变量的声明遵循数在C语言中,星号的位当在同一行声明多个指据类型*指针变量名;的置相对灵活int*针时,需要注意星号的基本语法例如,int p;、int*p;和int*p;作用范围例如,int*p;声明了一个指向整在语法上都是等价的*p,q;中,p是指针而q型的指针变量p星号不过,为了提高代码可是普通整型变量如果*是指针声明的关键标读性,建议采用一致的希望声明多个指针,应志,表示该变量是一个风格,如int*p;这种使用int*p,*q;这种形指针与类型分开的写法式指针的初始化声明指针变量int*p;获取变量地址int a=10;指针指向变量p=a;指针变量在声明后必须经过初始化才能安全使用初始化的方式主要有两种一是使用取地址运算符获取已有变量的地址;二是将指针初始化为NULL,表示它暂时不指向任何有效地址未初始化的指针含有随机值,被称为野指针,使用它们可能导致程序崩溃或数据损坏指针的解引用声明并初始化读取值int a=10;int*p=a;printf%d,*p;验证修改修改值printf%d,a;*p=20;解引用是指针最重要的操作,通过解引用操作符*可以访问指针所指向的内存位置存储的值当我们写*p=20;时,实际上是在修改p所指向的变量a的值解引用操作的内部工作原理是计算机首先读取指针p中存储的内存地址,然后访问该地址处的内存单元指针的大小48位系统中的指针大小字节位系统中的指针大小字节3264在32位系统中,无论指针指向什么类型的数在64位系统中,所有类型的指针都占用8个据,它本身都占用4个字节的内存空间,可以字节,这使得它们能够表示极其庞大的地址表示高达4GB的地址空间空间100%类型相同的指针在同一系统中,不同类型的指针如int*、char*、double*占用的内存空间完全相同指针变量的大小取决于计算机的体系结构,而非它所指向的数据类型可以使用sizeof运算符来测量指针的大小,例如printf指针大小%zu字节\n,sizeofint*;指针的类型强类型指针无类型指针函数指针强类型指针如int*、char*、double*等,void*是一种特殊的指针类型,可以指向函数指针指向可执行代码而非数据它指向特定类型的数据指针的类型决定任何类型的数据,但在使用前必须进行们的声明语法较为复杂,如int*fpint,了解引用时如何解释内存中的二进制数类型转换它常用于需要处理不同类型int声明了一个指向接受两个int参数并返据,以及指针算术运算的步长例如,数据的通用函数中,如内存分配函数回int的函数的指针函数指针在实现回int*解引用时会读取4字节作为一个整mallocvoid*不能直接解引用,也不调机制、事件处理和动态函数调用等方数,而char*只会读取1字节作为一个字能进行指针算术运算面非常有用符空指针NULLNULL指针是一个特殊的指针常量,它不指向任何有效的内存地址在C语言中,NULL通常被定义为void*0,表示地址为0的指针NULL指针的主要用途是表示指针不指向任何东西,这在初始化指针、函数返回错误状态、以及终止链表等场景中非常有用在使用指针前检查它是否为NULL是一个良好的编程习惯,可以避免尝试访问无效内存导致的程序崩溃例如if p!=NULL{*p=10;}第二部分指针操作指针算术运算学习如何通过加减运算移动指针,理解指针运算与数据类型的关系,以及指针比较运算的应用场景指针与数组的关系深入理解数组名作为指针的特性,掌握使用指针高效访问和处理数组元素的技巧指针与限定符const学习如何使用const创建不同类型的只读指针,理解指向常量的指针和常量指针的区别指针算术运算运算示例结果指针+整数p+2指向p后第2个元素的指针指针-整数p-1指向p前第1个元素的指针指针相减q-p p和q之间的元素个数指针比较pq p是否位于q之前指针的算术运算是C语言中一个强大但易错的特性当对指针进行加减运算时,实际增减的内存地址单位取决于指针的类型例如,对int*类型的指针p执行p+1,实际上是将地址增加sizeofint个字节,通常是4字节指针的比较运算可用于确定相对位置关系,通常用于数组元素的比较而两个指针相减的结果表示它们之间的元素个数,常用于计算数组长度或遍历范围指针与数组
(一)数组的内存布局数组在内存中是连续存储的一组元素,数组名本身可以视为指向第一个元素的常量指针这种连续存储的特性是指针能够高效访问数组的基础指针访问数组表达式a[i]与*a+i是等价的,都表示访问数组的第i个元素这种等价性揭示了数组下标操作的本质它是指针算术和解引用的组合指针遍历效率使用指针遍历数组通常比使用下标更高效,因为它减少了地址计算的次数这在处理大型数组时特别明显,能够带来显著的性能提升指针与数组
(二)指针数组数组指针指针数组是元素类型为指针的数组,声明形式为int*arr
[10];,数组指针是指向数组的指针,声明形式为int*arr
[10];,表示表示一个包含10个int*类型指针的数组指针数组常用于存储不一个指向含有10个int元素的数组的指针数组指针常用于处理同长度的字符串或管理多个动态分配的内存块多维数组,尤其是在函数参数传递中每个数组元素都是一个指针,可以指向不同的内存位置,实现非理解数组指针需要掌握声明中括号的优先级规则,其中*arr表连续数据的高效管理示arr是一个指针,而
[10]表示它指向一个10元素的数组字符串与指针与指针const指向常量的指针常量指针声明const int*p或int const*p声明int*const p特点不能通过指针修改所指对象特点指针本身的指向不能改变,的值,但指针本身可以改变指向但可以通过指针修改所指对象的值示例const int*p=x;*p=10;示例int*const p=x;*p=10;错误p=y;正确正确p=y;错误指向常量的常量指针声明const int*const p特点既不能改变指针的指向,也不能通过指针修改所指对象的值示例const int*const p=x;*p=10;错误p=y;错误第三部分动态内存管理内存调整内存释放掌握使用realloc函数调整已理解free函数的正确使用方法分配内存块大小的技巧和内存释放的重要性内存分配错误处理学习如何使用malloc和学习如何避免和处理常见的内calloc函数动态分配内存存管理错误内存分配概述栈内存堆内存静态分配动态分配vs vs栈内存由系统自动管理,用于存储局部变量和函数调用信息栈静态分配在编译时确定内存大小,如数组声明int arr
[10];静内存的分配和释放遵循后进先出LIFO原则,效率高但大小有态分配简单可靠,但缺乏灵活性,可能导致内存浪费或不足限程序员无需显式管理栈内存,变量超出作用域后自动释放动态分配在运行时根据需要分配内存,如int*arr=mallocn*sizeofint;动态分配允许程序根据实际需求使用内存,适用堆内存是一块较大的内存池,用于动态分配堆内存需要程序员于事先不知道确切大小的情况,但需要小心管理以避免内存泄手动申请和释放,提供了更大的灵活性,但管理不当会导致内存漏泄漏或碎片化问题函数malloc函数原型内存分配错误处理void*mallocsize_t malloc在堆上分配指定当内存不足或分配失败size;大小的连续内存块分时,malloc返回NULL配的内存内容是未初始良好的编程实践要求在malloc函数接受一个化的,包含随机值分使用分配的内存前检查size_t类型的参数,表配大小通常使用sizeof返回值是否为NULL,示要分配的字节数它运算符计算,如以防止访问无效内存导返回一个void*类型的指malloc10*致程序崩溃针,指向分配的内存块sizeofint的起始地址函数calloc特性malloc calloc函数原型void*mallocsize_t void*callocsize_t n,size size_t size参数含义总字节数元素个数和每个元素的字节数内存初始化不初始化随机值初始化为0常见用途通用内存分配数组分配calloc函数用于分配和初始化内存,其原型为void*callocsize_t n,size_tsize与malloc不同,calloc接受两个参数n表示要分配的元素个数,size表示每个元素的字节数calloc会将分配的内存全部初始化为零,这在需要清零内存的场景下很有用,如分配数组时函数realloc原内存分配int*arr=int*malloc5*sizeofint;首先分配一块可容纳5个整数的内存内存大小调整arr=int*reallocarr,10*sizeofint;将内存块扩展为可容纳10个整数数据保留与释放原有数据保留,新分配部分未初始化调整成功后自动释放原内存realloc函数用于调整已分配内存块的大小,其原型为void*reallocvoid*ptr,size_t size当需要扩大或缩小已分配的内存时,realloc非常有用它会尝试在原地扩展内存块,如果不可行,则会分配新的内存块并复制原有数据函数free函数原型内存释放原理使用注意事项void freevoid*ptr;free函数将指定的内存块标记为可释放内存后,相应的指针变成了悬用,使其可以被后续的内存分配挂指针,继续使用它会导致未定义free函数接受一个指针参数,该指请求重新使用它并不会清除内存行为一个好的习惯是在free后将针必须是之前通过malloc、calloc中的数据,也不会改变指针变量本指针设为NULLp=NULL不要尝或realloc分配的内存块的地址身的值,只是改变了内存块的状试释放非动态分配的内存或同一块free不返回任何值态内存多次,这会导致严重错误常见内存错误内存泄漏内存泄漏是指程序分配了内存但忘记释放,导致这部分内存在程序运行期间一直无法使用随着时间推移,泄漏的内存会不断累积,最终可能导致程序崩溃或系统资源耗尽悬挂指针/野指针悬挂指针是指向已释放内存的指针使用这类指针访问内存是危险的,因为该内存可能已被重新分配给其他变量野指针问题可以通过在释放内存后将指针设为NULL来避免缓冲区溢出缓冲区溢出发生在程序向分配的内存区域之外写入数据时这不仅会破坏相邻内存中的数据,还可能被恶意利用来执行未授权代码,是一个严重的安全隐患内存分配示例#include#includeint main{int n,i;int*arr;//获取用户输入的数组大小printf请输入数组元素个数:;scanf%d,n;//动态分配内存arr=int*mallocn*sizeofint;//检查内存分配是否成功if arr==NULL{printf内存分配失败!\n;return1;}//初始化数组for i=0;in;i++{arr[i]=i*10;}//打印数组内容printf数组内容:\n;for i=0;in;i++{printfarr[%d]=%d\n,i,arr[i];}//释放内存freearr;arr=NULL;//避免悬挂指针return0;}。
个人认证
优秀文档
获得点赞 0