版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C语言程序设计第05章指针与函数(2)|重庆大学计算机学院Contents本章目录C语言程序设计·第05章指针与函数(2)01返回指针值的函数02指向函数的指针变量03函数指针作为参数传递04指针数组与命令行参数CHAPTER01返回指针值的函数掌握函数返回指针的定义方式、使用场景与内存安全要点CHAPTER05·POINTERS&FUNCTIONS返回指针值的函数:概念与定义C语言允许函数返回指针型数据(地址),通过'数据类型符*函数名(参数表)'的格式定义。返回指针值的函数在动态内存分配、数据结构操作和系统编程中具有不可替代的作用,但必须注意返回地址的有效性。大学计算机编程课堂教学场景RETURNTYPE函数返回值类型不限于整型、实型、字符型等基本类型,还可以是指针型数据,即一个内存地址SYNTAX定义格式为'[存储类别符]数据类型符*函数名(形式参数表)',星号*表示函数返回值为指针类型EXAMPLE'float*fun(floatx,floaty)'中,fun返回的是指向实型数据的指针,而非实型数值本身CAUTION返回指针值时需确保所指内存区域在函数返回后仍然有效,避免返回局部自动变量的地址CodeExample实例:返回指针的阶乘累加函数通过静态局部变量配合返回指针的函数,可以在函数外部间接访问函数内部的计算结果。static关键字确保局部变量在函数返回后仍存活,是返回指针值函数的常用搭配手段。函数定义要点01返回指针声明:long*fac(longn)定义返回long型指针的函数,星号位于函数名前,表明返回值为地址而非数值02静态变量存活:函数内部使用staticlongp=1声明静态变量,保证p在函数返回后仍然有效且保留上次计算结果03地址返回:returnp返回静态变量p的地址,主调函数通过解引用运算符*获取p的值主函数调用逻辑01指针接收:声明long*pi指针变量用于接收fac函数返回的地址,实现通过指针间接获取函数计算结果02循环累加:循环调用pi=fac(i),每次将返回地址赋给pi,再通过sum=sum+*pi完成阶乘值的累加03风险警示:若fac内p不用static修饰而用普通auto变量,返回地址将指向已释放的栈内存,导致未定义行为SafetyGuidelines返回指针值函数的安全准则返回指针值函数的核心风险在于返回已失效的内存地址。C语言中局部自动变量在函数返回时自动释放,返回其地址将产生悬空指针,引发未定义行为。必须通过静态变量、动态分配或参数传递确保地址有效性。01局部自动变量(auto)存储于栈区,函数返回时栈帧销毁,返回其地址将产生悬空指针,读取结果不可预测DANGLINGPOINTER02使用static修饰局部变量,使其存储在静态存储区,生命周期贯穿整个程序运行期,函数返回后仍可安全访问STATIC03通过malloc/calloc在堆区动态分配内存并返回地址,调用者需负责在使用完毕后调用free释放,避免内存泄漏DYNAMIC04返回函数参数中传入的指针地址,如strcpy返回目标字符串首地址,保证地址始终有效PARAMPASSCHAPTER05·指针与函数函数返回指针的四种方式对比函数返回指针有四种常见方式,各自在内存安全性、灵活性和使用复杂度上存在显著差异。理解每种方式的底层内存机制,是避免悬空指针和内存泄漏的基础。函数返回指针方式的安全性对比返回方式存储区域安全性适用场景与注意事项返回局部auto变量地址栈区(自动释放)✘危险函数返回后内存被回收,产生悬空指针,严禁使用返回static局部变量地址静态存储区✔安全变量生命周期贯穿全程;但多次调用共享同一内存,不适合多线程返回malloc动态分配地址堆区(手动管理)✔安全灵活性最高,适合不确定大小的数据;调用者必须free释放返回传入参数的地址调用者栈帧/堆区✔安全广泛用于字符串操作函数如strcpy、strcat,地址由调用者保证有效摘要:返回局部auto变量地址是唯一危险的方式,其余三种均可安全使用但各有适用场景CHAPTER02指向函数的指针变量从函数入口地址到函数指针的定义、赋值与调用全流程CHAPTER05·POINTERS&FUNCTIONS函数入口地址与函数指针概念每个函数编译后在内存中占据一片连续存储区,函数名即为该存储区的首地址(入口地址)。定义一个指针变量使其指向函数入口地址,就构成了函数指针——它存储的不是数据地址,而是可执行代码的起始位置。01每一个函数都是一个程序模块,编译后在内存中占有一片连续存储区,函数名代表该存储区的首地址02函数入口地址类似于数组首地址:a≡&a[0],func≡函数的入口地址03定义一个指针变量并使其指向函数的入口地址,该指针变量即称为"指向函数的指针变量"04函数指针存储的是代码段中的地址而非数据段地址,解引用的含义是"跳转到该地址执行函数体"计算机内存条硬件实物—内存中的每个地址对应一个存储单元CHAPTER05·POINTERS&FUNCTIONS函数指针变量的定义语法函数指针定义格式为"返回值类型(*指针变量名)(形参表)",其中括号优先级是关键:(*变量名)确保先解析为指针,而非误读为返回指针的函数。01定义格式拆解完整格式完整格式为数据类型(*指针变量名)(形参表),如void(*fp)(intx,inty)定义fp为函数指针变量,指向返回值为void、接受两个int参数的函数。数据类型数据类型指定指针指向的函数的返回值类型,如int、double、void等。类型必须与目标函数返回值完全一致,否则编译器会发出类型不匹配的警告或错误。括号优先级(*指针变量名)中的括号至关重要:确保*先修饰变量名,声明这是一个指针。若去掉括号写成void*fp(),则变成"返回void*的函数"定义,语义完全不同。02赋值与调用赋值方式赋值方式:将函数名直接赋给函数指针,如fp=swap。函数名在表达式中自动退化为函数入口地址,无需显式取地址符&。调用格式一调用格式一:(*fp)(实参表),使用解引用运算符显式表示通过指针间接调用目标函数,语义最为清晰明确,是推荐的写法。调用格式二调用格式二:fp(实参表),省略解引用运算符的简写形式。C语言标准允许这种写法,编译器能够自动识别并正确调用,代码更为简洁。Chapter05·Pointer&Function实例:用函数指针调用swap函数函数指针的完整使用流程包括三步:定义匹配签名的指针变量、将目标函数名赋值给指针、通过指针调用函数。虽然直接调用函数更简洁,但函数指针的价值在于实现运行时动态绑定,为回调和策略模式奠定基础。01定义目标函数:定义函数voidswap(intx,inty),实现两数交换功能,作为函数指针指向的目标函数。02声明函数指针:定义函数指针void(*fp)(intx,inty),参数类型和返回值类型必须与swap完全匹配。03赋值指向函数:赋值fp=swap,将函数名swap的入口地址赋给指针变量fp,此后fp指向swap函数。04通过指针调用:调用(*fp)(a,b)或fp(a,b)均可触发swap执行,两种写法等价,后者是C语言允许的简写形式。05核心价值:可在运行时改变fp指向不同函数,实现同一调用代码执行不同逻辑——回调与策略模式的基础。Chapter05·Pointers&Functions实例:函数指针实现动态计算选择通过函数指针在运行时动态绑定不同的计算函数,同一调用代码可执行不同的计算逻辑。这种"一个调用点、多种行为"的模式是策略模式的雏形,广泛应用于数值计算、事件处理和插件架构中。函数定义f1(intx)计算1+Σ(1/k²),k从2到x步长为2,使用循环累加每一项的倒数平方f2(intx)计算1+Σ(1/k²),k从3到x步长为2,与f1区别在于起始值和步长不同主函数逻辑double(*fp)(intx)定义函数指针,类型为返回double、接受int参数的函数fp=(cond)?f1:f2读入n值,根据奇偶性或业务条件将fp指向f1或f2,实现计算策略的动态切换(*fp)(n)统一调用,无需if-else分支,代码结构更清晰,扩展性更强BINDINGMECHANISM函数指针vs直接调用:核心差异直接函数调用在编译时确定目标地址(静态绑定),函数指针调用在运行时确定目标地址(动态绑定)。动态绑定虽然牺牲了少量性能(一次间接寻址),但换来了运行时切换执行逻辑的能力,是实现回调、事件驱动和插件架构的底层基础。直接调用与函数指针调用的对比对比维度直接函数调用func()函数指针调用(*fp)()绑定时机编译时确定目标函数地址运行时根据指针值确定目标执行效率直接跳转,速度最快多一次间接寻址,略有开销灵活性调用目标固定,无法动态切换可在运行时改变指向不同函数典型应用常规业务逻辑调用回调函数、事件处理、策略模式代码可维护性大量分支时if-else膨胀用函数指针表替代分支,代码简洁函数指针的核心优势在于运行时动态绑定,以少量性能开销换取极大的架构灵活性CHAPTER03函数指针作为参数传递回调机制的原理、通用函数设计与数值积分实例CHAPTER05·POINTER&FUNCTION回调机制:函数指针作为参数的核心原理将函数指针作为参数传递给另一个函数,使被调函数能在执行过程中"回调"传入的函数。这种机制将通用逻辑与具体策略解耦:通用函数负责流程框架,策略函数负责具体计算,二者通过函数指针在运行时绑定。定义格式在形参表中声明如double(*p)(floatx),表示接受一个函数指针作为参数回调本质被调函数不关心具体计算逻辑,只通过指针调用传入的函数,实现"控制反转"典型应用C标准库qsort通过传入不同比较函数指针对任意类型数据实现自定义排序核心优势一个通用函数可搭配多种策略函数使用,避免重复编写相似代码,大幅提升代码复用率CLanguage·Chapter05实例:梯形法求定积分的通用函数通过函数指针参数设计的collect通用积分函数,实现了数值计算方法与被积函数的彻底解耦。同一个计算框架可搭配任意被积函数使用,是"策略模式"在C语言中的经典实现。通用函数设计函数原型:doublecollect(double(*p)(floatx),floata,floatb,intn),函数指针p接收被积函数地址梯形法核心:将区间[a,b]等分为n段,步长h=(b-a)/n,用n个小梯形面积之和近似曲边四边形面积面积累加公式:area=(f(a)+f(b))/2+Σf(a+i·h),其中i从1到n-1,最后乘以步长h实际应用示例计算f₁(x)=1+x:在[0,2]上调用collect(f1,0,2,n),f1函数地址自动退化为指针传入计算f₂(x)=1/(1+4x²):在[-1,1]上调用collect(f2,-1,1,n),同一框架切换被积函数精度控制:等分数n从键盘输入,n越大精度越高;可扩展为辛普生法等更高精度数值积分算法AlgorithmSteps梯形法算法实现细节梯形法将曲边区域离散为n个小梯形求面积之和,中间等分点的函数值各被相邻两个梯形共享使用两次,仅首尾端点使用一次。这种"端点半权、中间全权"的计算模式是数值积分的基础技巧。步骤操作内容对应代码逻辑1计算步长hh=(b-a)/n;2处理端点a和b(半权)area=(f(a)+f(b))/2;3累加中间等分点函数值(全权)for(i=1;i<=n-1;i++)area+=f(a+i*h);4乘以步长得到积分近似值area=area*h;5返回积分结果returnarea;梯形法通过离散化将连续积分转化为有限项求和,等分数n越大精度越高CALLBACKPATTERN经典案例:qsort函数与自定义比较C标准库qsort函数通过接受比较函数指针作为参数,实现了对任意类型数据的通用排序。用户只需编写比较规则函数,qsort内部的高效排序算法即可自动适配,完美诠释了"框架+策略"的回调设计模式。函数原型01voidqsort(void*base,size_tnmemb,size_tsize,int(*compar)(constvoid*,constvoid*))02第四个参数compar是函数指针,指向用户自定义的比较函数,决定排序的升降序和数据类型解释方式03比较函数返回负值表示升序排列,返回正值表示降序排列,返回零表示两元素相等实际应用示例01整数升序:return*(int*)a-*(int*)b;02结构体排序:将void*转换为结构体指针,按目标字段比较大小03多规则切换:传入不同比较函数指针即可切换排序规则,无需修改排序算法本身DESIGNPATTERN函数指针作参数的设计模式总结函数指针作参数本质上是"控制反转"思想的C语言实现:通用框架定义流程,策略函数定义行为,运行时动态绑定。通用框架函数负责算法骨架和执行流程,不包含具体业务计算逻辑。框架代码高度抽象,专注于流程控制而非数据运算。算法骨架策略函数负责具体计算细节,通过函数指针参数注入到通用框架中。实现算法与使用的分离,提高代码模块化程度。计算细节运行时绑定传入不同策略函数地址,同一框架处理不同业务需求。实现多态效果,避免大量条件分支和重复代码。最大化复用开闭原则新增策略只需编写新函数并传入地址,无需修改框架。对扩展开放、对修改封闭,降低维护成本。零修改扩展现代语言演进C++用模板替代,Java用接口+Lambda实现,思想一脉相承。函数指针模式奠定了回调机制的理论基础。LambdaCHAPTER04指针数组与命令行参数从指针数组的概念到main函数命令行参数的完整解析CHAPTER05·指针与函数指针数组的概念与定义指针数组是每个元素均为指针变量的数组,定义格式为"数据类型*数组名[大小]"。它与数组指针在语法上仅差一对括号,但语义完全不同。定义与语法int*p[5]定义了指针数组p,含5个元素,每个元素都是int型指针,可分别指向不同的int变量运算符优先级:[]高于*,因此int*p[5]先解析p[5]为数组,再与*结合为指针数组对比int(*p)[5]:括号改变优先级,先解析*p为指针,再与[5]结合为指向5元素数组的指针典型应用场景管理多个字符串:char*strs[]各元素分别指向一个字符串常量首字符,实现灵活的字符串集合管理管理动态内存块:数组各元素分别指向malloc分配的独立内存区域,实现不规则数据的统一管理构建二维数组的灵活替代:指针数组各行可指向不同长度的数组,避免固定列数的内存浪费CHAPTER05·POINTERARRAY实例:指针数组管理字符串集合字符指针数组是管理多个字符串的最高效方式,每个元素仅存储首地址而非复制内容,避免二维数组列宽固定导致的内存浪费。01char*days[]={"Monday","Tuesday",...,"Sunday"}声明定义:char*days[]={"Monday","Tuesday",...,"Sunday"},共7个字符指针元素7ptr02存储机制:每个元素仅存储字符串常量的首地址,不复制字符串内容,内存占用仅7个指针56B03chardays[7][10]对比二维数组:chardays[7][10]每行固定10字节,短字符串如"Mon"浪费大量空间70B04days[i]*(days+i)遍历输出:days[i]等价于*(days+i),获取第i个字符串首地址*(p+i)05排序优势:交换两个字符串只需交换指针值(4/8字节),无需移动字符串内容,效率极高O(1)CHAPTER05·POINTERS&FUNCTIONS命令行参数:argc与argv详解main函数的完整签名支持接收命令行参数,argc记录参数总数,argv是字符指针数组,是编写CLI工具的基础机制。DEFINITIONS参数含义argc(argumentcount)整型参数,记录命令行参数总个数,包含程序名本身,至少为1argv(argumentvector)字符指针数组,argv[0]固定为程序名,argv[1]至argv[argc-1]为用户传入参数argv[argc]固定为NULL指针,作为参数列表终止标记,可用于遍历时的边界判断EXAMPLES实际示例$./copyfile1.txtfile2.txtargc=3,argv[0]='./copy',argv[1]='file1.txt',argv[2]='file2.txt'for(i=0;i<argc;i++)printf("argv[%d]=%s\n",i,argv[i])通过循环遍历argv即可获取所有参数,逐一打印索引与对应字符串值结合字符串处理函数解析带标志参数如-ooutput.txt,实现类似gcc、git等工具的命令行接口POINTER&FUNCTION·CHAPTER05命令行参数的内存布局命令行参数在内存中以"指针数组+字符串池"的方式组织:argv数组存储各参数的首地址,实际字符串内容存储在独立的内存区域。这种分离设计使得参数传递高效且灵活,不受字符串长度限制。$命令行'myapp-vinput.txt'的内存布局数组下标argv元素值(地址)指向的字符串内容说明0argv[0]=0x7fff0010"myapp"固定为程序名(可执行文件名)1argv[1]=0x7fff0020"-v"第一个用户参数(版本标志)2argv[2]=0x7fff0030"input.txt"第二个用户参数(输入文件名)3argv[3]=NULL—终止标记,固定为NULLargc=3,argv[0]为程序名,argv[1]和argv[2]为用户参数,argv[3]=NULL为终止标记CHAPTER05·POINTER&FUNCTION实例:简易命令行参数解析程序通过遍历argv数组并判断每个参数的首字符是否为'-',可以区分选项标志和普通参数。这种简易解析方式虽然不如getopt库完善,但涵盖了命令行参数处理的核心逻辑,是理解Linux工具参数机制的起点。01程序框架intmain(intargc,char*argv[]),先检查argc是否满足最少参数要求,不足则打印用法提示并退出。▸典型用法:./program-h或./programfile.txt02选项解析遍历argv[1]到argv[argc-1],用argv[i][0]=='-'判断是否为选项标志,strcmp比对具体选项名。▸支持短选项:-v-ooutput.txt03参数提取非选项参数按位置顺序提取为文件名或数值参数,如第一个非选项参数为源文件、第二个为目标文件。▸位置参数:./programinput.txtoutput.txt04错误处理对未识别的选项打印警告信息,对缺失的必需参数返回非零退出码,遵循Unix工具的约定。▸退出码:0成功,1参数错误,2文件错误CHAPTER05·POINTER&FUNCTION二级指针与指针数组的深层关系指针数组名作为函数参数时自动退化为二级指针(如char*argv[]等价于char**argv),二级指针允许函数内部修改调用者的指针指向,这在链表操作和动态数据结构中是不可替代的技术手段。语法等价关系01参数等价性:char*argv[]与char**argv在函数参数中等价——数组名退化为指向首元素的指针,即指向char*的指针02逐层解引用:argv[i]等价于*(argv+i),argv[i][j]等价于*(*(argv+i)+j),逐层解引用获取最终字符03间接深度:多级指针的层数决定了间接访问的深度——一级指针解引用得数据,二级指针解引用得一级指针函数参数中的二级指针01传一级指针:传int*p时,函数内可修改*p的值(即p指向的数据),但无法改变p本身的指向02传二级指针:传int**pp时,既可修改**pp(数据),也可修改*pp(指针指向),如让指针指向新分配的内存03典型应用:链表头插入voidinsert(Node**head,intval),需通过二级指针修改头节点的指向CHAPTER05·指针与函数函数指针数组与跳转表模式函数指针数组将多个函数指针组织为数组结构,通过索引直接调用目标函数,形成"跳转表"(jumptable)。这种模式用数组索引替代多层if-else或switch分支,在命令分发、状态机和事件处理中实现O(1)时间复杂度的函数调度。定义格式double(*ops[4])(double,double)={add,sub,mul,div},4个元素分别指向加减乘除函数(*ops[4])(double,double)调用方式ops[op_index](a,b)通过索引直接调用目标函数,时间复杂度O(1),无需分支判断O(1)直跳性能对比switch需逐个比较case值,最坏情况O(n);函数指针数组直接索引跳转,性能恒定O(n)→O(1)典型应用计算器命令分发、嵌入式状态机转移表、协议解析器中的消息处理函数注册状态机·命令分发·协议解析CHAPTER05·POINTERS&FUNCTIONS指针与函数:四种组合关系总览指针与函数的交叉组合形成四种核心模式:返回指针的函数、指向函数的指针、指针作函数参数、指针数组与函数指针数组。掌握这四种模式的定义语法、使用场景和注意事项,是精通C语言高级编程的标志。指针与函数的四种组合关系组合模式定义语法示例语义说明典型应用返回指针的函数int*func(intx)函数返回值为int型指针(地址)malloc封装、字符串处理函数函数指针int(*fp)(intx)fp是指向函数的指针,函数接受int返回int回调机制、策略模式指针作函数参数voidfunc(int*p)函数参数为int型指针,可修改调用者数据地址传递、数组操作函数指针作参数voidfunc(int(*fp)(int))函数参数为函数指针,可回调传入的函数qsort比较函数、积分被积函数函数指针数组int(*ops[4])(int,int)数组元素为函数指针,形成跳转表命令分发、状态机五种组合覆盖了C语言指针与函数交叉应用的全部核心场景CLanguage·Pointers&Functions常见错误与调试技巧指针与函数的结合使用中存在三大高频错误:函数指针定义括号遗漏导致语义变化、函数指针类型不匹配引发栈损坏、返回局部变量地址产生悬空指针。理解每个错误的底层原因,配合编译警告和调试工具,可有效预防和定位问题。高频错误01int*fp(int)int(*fp)(int)括号遗漏—int*fp(int)被解析为返回int指针的函数声明,而非函数指针定义,必须写为int(*fp)(int)02类型不匹配—函数指
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【知识清单】初中地理八年级下册7.1南方地区自然特征与农业默写速记
- 2026年重庆市城市建设投资集团招聘试题及答案
- 2027年中考历史七下总复习必刷题-明清时期的经济与文化发展
- 2025年中国显示器市场规模和企业市占率调研-智研咨询发布
- 2026年浙江省苏教版小学语文上册第5单元同步练习题
- 2026母婴用品新零售渠道变革与消费者偏好调研报告
- 个人借款合同范本
- 2026免税零售行业消费升级与渠道变革分析报告
- 文章-咖啡机配件镜面处理关键点
- 五年级上数学课外辅导计划
- 躬耕教坛强国有我-第42个教师节国旗下讲话稿(学生版)
- 收集食堂泔水合同5篇
- 2026呼和浩特市总工会招聘工会社会工作者和专职集体协商指导员考试备考试题及答案详解
- 泸州市兴泸水务(集团)股份有限公司 2026年第二次公开招聘笔试参考题库及答案详解
- 【二年级】【秋季上】【语文】开学家长会:为了孩子齐用心【课件】
- 2026年中考化学(安徽卷)真题详细解读及评析
- 人工智能辅助教育实施方案
- 2026年秋期人教版部编版小学数学四年级上册全册教学计划教案
- 2026人教版五年级数学上册第一单元第1课《观察简单组合体(1)》教案
- 全国2026年10月自学考试行政管理学试题和答案
- 2026年电力工程造价从业人员专业能力评价考试(专业技术公共基础)全真模拟试题及答案
评论
0/150
提交评论