版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++UniversityTutorial指针和基于指针的字符串深入理解内存地址、指针操作与字符串处理Contents课程目录系统掌握C语言指针的核心概念与实际应用01指针基础概念02指针的声明与操作03指针与数组04指针与函数05基于指针的字符串CHAPTER01指针基础概念从内存地址到指针变量,建立底层思维模型C++FUNDAMENTALS指针:地址即数据指针的核心思想是将内存地址视为一种可存储、可传递的数据类型。理解"地址即数据"这一观念是掌握指针的第一步,它打破了"变量只能存值"的传统认知,为间接访问内存奠定了理论基础。01intx1000内存中每个变量都有唯一的地址编号,如intx可能被分配在1000号单元,该地址本身就是一个可操作的数值。02地址作为数据可以被存储在另一个变量中,这个专门存放地址的变量就是指针变量。03指针的本质是"指向"关系:通过存储目标变量的地址,实现对目标变量的间接访问和操作。04这种"地址即数据"的设计使C++能够直接操作内存,赋予了程序员极大的灵活性和底层控制力。计算机内存条DDR5实物特写CONCEPT指针变量与变量的指针'指针变量'是存储地址的变量本身,而'变量的指针'是指向某个特定变量的指针。前者强调变量类型,后者强调指向关系。01指针变量是类型为"指针"的变量,其存储的内容不是普通数值,而是另一个变量的内存地址02"变量的指针"强调指向关系,如px存储了x的地址1000,则称px为x的指针,px指向x03内存模型中常用箭头表示指向关系:指针变量框中写地址值,箭头指向目标变量的存储框04实际编程中变量的真实地址由操作系统动态分配,教学时常用简化地址(如1000)来描述指针编程教学课堂实景MemoryModel指针的内存模型指针变量本身也占用内存空间,其存储的内容是目标变量的地址。通过"读取指针值→定位目标地址→获取目标数据"的三步过程实现间接访问,这是指针操作的核心机制。内存布局示例01变量x分配在1000号单元,存储值为2;指针变量px分配在1004号单元,存储值为1000。这种分离存储体现了"指针即地址"的本质特性。02指针变量自身也占内存:32位系统上占4字节,64位系统上占8字节,与普通变量一样拥有独立的内存地址,同样需要存储空间来保存地址数据。03px地址是1004,px的值是1000,*px(解引用)结果是2,构成完整的"指针→地址→数据"三级指向链。间接访问机制01直接访问:通过变量名x直接读取1000号单元的值,编译器在编译期自动完成变量名到内存地址的映射转换,访问路径最短。02间接访问:通过指针px先获取存储的地址1000,再以该地址为目标读取实际数据,相比直接访问多了一层"寻址"步骤。03间接访问的核心价值在于:程序可以在运行时动态决定访问哪个变量,实现灵活的数据操作,支持动态内存分配、函数参数传递、数据结构构建等高级编程模式。MemoryModel为什么需要指针指针存在的核心价值在于三个方面:实现运行时动态内存分配、提升大数据量传递的效率、以及构建链表和树等复杂数据结构。指针赋予C++直接操控内存的能力,是系统级编程和高性能计算的基石。动态内存管理通过new/delete在堆区按需分配和释放内存,解决编译期无法确定数据规模的问题高效参数传递传递指针(地址)而非复制整个数据对象,对大型结构体和数组可显著降低内存和时间开销构建复杂数据结构链表、二叉树、图等数据结构依赖指针建立节点间的逻辑连接,无指针则无法实现底层硬件交互操作系统、驱动程序和嵌入式开发需通过指针直接访问特定内存地址来操控硬件寄存器系统级编程的底层基础设施CHAPTER02指针的声明与操作掌握指针变量的定义、初始化与核心运算符SyntaxFundamentals指针变量的声明指针变量的声明使用"类型标识符*变量名"格式,星号表明该变量存储的是地址而非普通值。声明多个指针变量时每个变量名前都必须加星号,这是初学者最常见的语法陷阱之一。01基本语法为"类型标识符*指针变量名",如int*intp声明指向整数的指针,char*chPtr声明指向字符的指针。类型*名称02类型标识符决定了指针指向的数据类型,编译器据此确定解引用时读取多少字节以及如何解释数据。字节宽度03同时声明多个指针变量时,每个变量名前的星号不可省略:double*p,*q正确,double*p,q则q为普通变量。逐个加*04声明时指针变量未初始化则包含随机地址值(野指针),使用前必须赋初值或置为nullptr以避免未定义行为。野指针PointerOperators核心运算符:&和*取地址运算符&获取变量的内存地址,解引用运算符*通过指针访问目标变量的值。两个运算符互为逆操作。Operator取地址运算符&语法为&变量名,返回该变量在内存中的地址值,如px=&x将x的地址存入指针px不能用常数对指针直接赋值(如px=1000是错误的),因为编译器无法验证该地址的合法性&运算符的结果类型是"指向该变量类型的指针",如&x(x为int)的类型是int*Operator解引用运算符*语法为*指针变量,访问指针所指向地址处存储的值,如*px等价于x(当px=&x时)可通过*修改目标变量的值:*px=10等同于x=10,这是指针实现"间接修改"的关键能力声明中的*与使用中的*含义不同:int*px的*是类型修饰,*px=5的*是解引用运算符C++Pointers指针的赋值与运算同类型指针之间可以赋值和比较,指针还可以进行算术运算(加减整数)。指针算术的单位是目标类型的大小而非字节数,这一特性使指针能够自然地遍历数组元素。01指针赋值要求类型匹配:int*p1=&x,*p2=p1使两个指针指向同一变量,此后修改*p2会影响x和*p102指针比较运算:==和!=判断是否指向同一地址,<和>比较地址高低,常用于数组遍历的终止条件判断03指针算术以目标类型大小为单位:int*p执行p+1地址增加4字节,double*p执行p+1地址增加8字节04同类型指针相减:结果为两地址间可容纳的目标类型元素个数,常用于计算数组长度编程实践场景·指针操作的实际编码过程C++FUNDAMENTALS指针与const的三种组合const与指针的组合产生三种不同的约束,掌握这三种组合是编写安全C++代码的基础。指向常量的指针constint*p=&value不能通过*p修改目标值,但p可以重新指向其他变量常用于函数参数保护,保证函数内部不会修改调用方的数据值只读常量指针int*constp=&xp的指向一旦初始化就不可更改,但可通过*p修改x的值必须在声明时初始化,类似于引用的不可重绑定特性指向锁定指向常量的常量指针constint*constp=&y既不能通过*p修改值,也不能让p指向其他变量适用于固定访问只读数据的场景,提供最高级别的数据保护双重锁定PointerSafety空指针、野指针与悬空指针指针安全编程的三大风险是空指针、野指针和悬空指针。C++11引入的nullptr提供了类型安全的空指针表示。遵循"初始化置空、使用前检查、释放后归零"三原则可有效避免指针相关的未定义行为。空指针nullptrC++11引入的类型安全空指针,表示不指向任何有效对象,解引用将导致程序崩溃(段错误)。相比传统NULL宏,nullptr具有明确的指针类型,可避免重载解析歧义。C++11标准·类型安全野指针未初始化的指针变量包含随机垃圾地址,解引用后行为不可预测,是最难调试的指针错误之一。常见于栈上未初始化指针、malloc后未赋值直接使用等场景。最难调试·未定义行为悬空指针指向已被delete释放内存的指针,该内存可能已被重新分配,访问会导致数据损坏或崩溃。即使程序暂时运行正常,也可能在后续触发难以复现的内存错误。delete后残留·内存风险安全编程三原则声明时初始化为nullptr、使用前检查if(p!=nullptr)、delete后立即将指针置为nullptr。配合智能指针(unique_ptr/shared_ptr)可进一步实现自动化内存管理。初始化·检查·归零·智能指针C++MEMORY动态内存管理:new与deletenew在堆区动态分配内存并返回指针,delete释放已分配的内存。每次new必须有配对的delete,数组形式new[]必须配对delete[]。单个对象的动态分配●int*p=newint(42)—在堆区分配一个int大小的内存并初始化为42,p指向该内存●deletep—释放p指向的堆区内存,归还给系统;释放后p变为悬空指针,应立即置nullptrnew/delete数组的动态分配●int*arr=newint[n]—在堆区分配n个int的连续空间,n可以是运行时变量,突破栈区大小限制●delete[]arr—释放动态数组必须使用方括号形式,仅用delete会导致只释放首元素,其余内存泄漏new[]/delete[]常见风险与防范●内存泄漏—new后忘记delete,长期运行程序会耗尽系统内存;可用智能指针自动管理生命周期●重复释放—对同一指针执行两次delete导致未定义行为;释放后置nullptr可安全避免此问题Leak/Double-freeMemoryManagement智能指针:现代C++的内存管理方案C++11引入的智能指针(unique_ptr和shared_ptr)通过RAII机制自动管理动态内存,在离开作用域时自动释放资源。智能指针几乎消除了手动delete带来的内存泄漏风险,是现代C++推荐的所有权管理方式。独占所有权同一对象只能有一个unique_ptr拥有,离开作用域自动delete,支持move转移所有权unique_ptr共享所有权多个shared_ptr可指向同一对象,内部引用计数归零时自动释放,适合多处共享资源shared_ptr工厂函数make_shared<int>(42)一次分配对象和控制块,比直接new更高效且异常安全make_shared局限与风险不适合非内存资源管理,循环引用时shared_ptr会导致泄漏,需用weak_ptr打破weak_ptrC/C++POINTER多级指针多级指针即指向指针的指针,通过多次解引用逐层访问数据。二级指针(**)是最常见形式。二级指针声明int**pptr=&ptr,pptr存储ptr的地址,**pptr经两次解引用得到最终值。多级指针声明时,星号数量对应解引用层级。**pptr函数中修改指针需在函数内改变传入指针的指向而非指向的值时,参数类型必须是指针的指针。通过二级指针可在函数内部修改外部指针变量本身。参数类型命令行参数argvmain函数的argv是二级指针,每个*argv[i]指向一个命令行参数字符串。argc记录参数个数,argv[0]通常为程序名。char**argv动态二维数组先分配行指针数组再逐行分配列空间,实现灵活的矩阵存储与动态内存管理。释放时需先逐行释放再释放行指针数组。int**matrixCHAPTER03指针与数组揭示数组名的指针本质与指针算术的遍历技巧C·PointerSemantics数组名的指针特性数组名在表达式中自动退化为指向首元素的常量指针(等价于&arr[0]),但数组名本身不可被重新赋值。这一特性使指针能够自然地访问数组元素,也是数组传参时退化为指针的根本原因。01数组名退化为指针intarr[5]arr&arr[0]int*intarr[5]中arr等价于&arr[0],类型为int*,指向数组第一个元素。这是C语言数组设计的核心机制,使得数组能够以指针形式参与运算。02数组名是常量指针arrarr++arr=parr的指向固定不可变,arr++和arr=p均非法,编译器会报错。只有普通指针变量才能做移动操作,数组名始终绑定到固定的内存地址。03sizeof的区别sizeof(arr)sizeof(p)sizeof(arr)返回整个数组字节数(如5×4=20),而sizeof(p)仅返回指针本身大小(4或8字节)。这是区分数组和指针的关键手段,常用于计算数组元素个数。04取数组地址的特殊性&arrint(*)[5]arrint*&arr类型为int(*)[5](指向整个数组的指针),与arr退化后的int*不同。两者步长不同,前者移动跳过整个数组,后者移动跳过一个元素。C/C++·PointerArithmetic指针算术与数组遍历下标运算符arr[i]在编译器内部被转换为*(arr+i),本质是指针算术加解引用。利用指针递增可以高效遍历数组,指针每加1自动前进一个元素大小的字节数,无需手动计算偏移。等价访问方式01arr[i]*(arr+i)arr[i]等价于*(arr+i):下标运算符本质是指针偏移加解引用,这是C/C++的核心设计哲学02p[i]*(p+i)p[i]等价于*(p+i):当p指向数组首元素时,p可以像数组名一样使用下标访问03i[arr]*(i+arr)i[arr]也等价于*(i+arr):由于加法交换律,这种奇特写法合法但不推荐,影响代码可读性指针遍历技巧01ptr++sizeof(int)ptr++遍历数组,每次自动前进sizeof(int)字节,无需手动计算偏移02ptr<arr+n指针比较ptr<arr+n作为循环条件,利用地址的有序性判断是否到达数组末尾03arr+i指针遍历底层效率略优于下标遍历,省去了每次计算arr+i的加法操作CStringFundamentals字符数组与C风格字符串C风格字符串是以'\0'终止符结尾的字符数组,字符串处理函数通过遍历指针直到遇到'\0'来确定字符串长度。理解字符数组的内存布局是掌握基于指针的字符串操作的前提。01chars[]="hello"{'h','e','l','l','o','\0'}字符串本质是字符数组:chars[]="hello"在内存中存储为{'h','e','l','l','o','\0'},共6个字节6bytes02strlen'\0'终止符是字符串的核心标记:strlen等函数从首字符开始逐字节扫描,遇到'\0'停止并返回长度strlen()03chars[]="abc"constchar*p="abc"字符数组与字符串常量的区别:chars[]="abc"可修改,constchar*p="abc"指向只读区不可修改可变vs只读04chars[5]="hello"常见陷阱:忘记预留'\0'的空间导致越界,如chars[5]="hello"没有空间放终止符,后续操作将产生未定义行为UB风险CHAPTER04指针与函数引用调用、返回指针的函数与函数指针回调机制C++指针·函数参数值传递与引用调用C++默认的值传递只复制实参副本,函数内修改不影响原始变量。通过传递指针实现"引用调用",函数可以间接修改调用方的数据,这是指针在函数编程中最基础也最重要的应用。值传递的局限COPYvoidswap(inta,intb)voidswap(inta,intb)只交换形参副本,实参x、y的值在函数调用前后保持不变COST值传递对大型对象效率低下:传递一个1000字节的结构体需要完整复制,浪费时间和内存1000bytes指针实现引用调用ADDRESSvoidswap(int*a,int*b)swap(&x,&y)voidswap(int*a,int*b)接收实参地址,通过*a和*b直接修改原始变量,调用方式为swap(&x,&y)EFFICIENT指针传参只传递一个地址(4或8字节),无论目标数据多大都不会产生复制开销4–8bytesMULTI-RETURN引用调用使函数能够返回多个结果:通过多个指针参数同时修改多个外部变量C++POINTER返回指针的函数函数可以返回指针类型,但绝不能返回局部变量的地址,因为局部变量在函数退出后已被销毁。安全的返回对象包括动态分配的堆内存、传入的指针参数和静态/全局变量的地址。01函数返回指针的语法:int*findMax(int*arr,intsize),返回类型为int*,表示返回一个整数地址。02致命错误:返回局部变量地址(如intx=5;return&x)会导致悬空指针,访问已销毁的内存产生未定义行为。03安全方式一:返回new分配的堆区内存,如returnnewint(result),调用方负责delete。04安全方式二:返回传入的指针参数(如数组元素地址)或static/全局变量地址,生命周期不受函数限制。大学计算机实验室·学生编程实景SYNTAX&PATTERN函数指针函数指针存储函数的入口地址,使程序能够在运行时动态选择调用哪个函数。函数指针是实现回调机制、策略模式和事件驱动架构的核心工具,广泛应用于标准库函数和框架设计中。声明与使用01声明语法:返回类型(*指针名)(参数列表),如int(*fp)(int,int)声明指向双参数整型函数的指针02赋值与调用:fp=add将函数地址赋给fp,调用时fp(3,5)或(*fp)(3,5)均可int(*fp)()核心应用场景回调机制:将函数指针作为参数传入,让调用方在适当时机执行自定义逻辑,如qsort的比较函数策略模式:根据运行时条件选择不同的函数指针,实现行为的动态切换,避免大量if-else分支事件驱动:在GUI编程和游戏引擎中,事件处理器通过函数指针注册,事件触发时自动回调qsort·Strategy·EventFunctionPointerArray函数指针数组与应用函数指针数组将多个同类型函数组织为可索引的表,通过下标动态选择调用目标。这种设计消除了冗长的switch-case结构,使程序更具扩展性,是实现命令分发和插件机制的常用技巧。声明语法返回类型(*数组名[大小])(参数列表),如int(*ops[4])(int,int)定义含4个函数指针的数组。括号优先级决定数组特性,是C语言函数指针的核心语法。Syntax计算器应用将add、sub、mul、div四个函数指针存入数组,通过ops[choice](a,b)直接分发调用。用户输入操作符索引,程序自动路由到对应函数执行运算。Dispatch扩展性优势新增操作只需追加函数和指针,无需修改分发逻辑,符合开闭原则。相比switch-case的硬编码,函数指针数组让代码更易维护和扩展。Open-ClosedTypedef简化typedefint(*FuncPtr)(int,int)简化声明,FuncPtrops[4]更清晰易读。类型别名隐藏复杂语法细节,提升代码可读性,是大型项目的最佳实践。ReadabilityCHAPTER05基于指针的字符串字符指针初始化、字符串操作与C标准库函数CLANGUAGE·POINTER字符串指针的初始化方式字符指针可以通过字符数组或字符串字面量两种方式初始化。数组方式在栈区分配可修改的内存,字面量方式指向只读数据区不可修改。理解两种方式的内存分布差异是避免字符串操作错误的关键。字符数组方式可修改01chars[4]={'a','b','c','\0'}'\0'chars[4]={'a','b','c','\0'}显式列出每个字符,必须手动添加'\0'终止符02chars[]="abc"'\0'chars[]="abc"编译器自动计算大小并添加'\0',数据存储在栈区可自由修改03数组名s是常量指针,不能指向其他内存,但数组内容可通过下标或指针运算任意修改STACK·WRITABLE字符串字面量方式只读01constchar*p="abc""abc\0"constchar*p="abc"系统在只读数据区分配空间存储"abc\0",将起始地址赋给p02*p='x'p指向的内容不可修改(*p='x'会崩溃),但p本身可重新指向其他字符串03多个指向相同字面量的指针可能共享同一内存地址(编译器优化),修改会影响所有引用READ-ONLY·SHAREDC++InputMethods字符串的读入方式cin>>以空白字符为分隔读入单词,无法处理含空格的字符串;cin.getline()读入整行直到换行符,是处理完整句子的正确方式。01cin>>s以空白字符(空格、Tab、换行)为终止条件,每次只读入一个单词,剩余内容留在输入缓冲区单词级读取02cin.getline(s,n)读入最多n-1个字符直到遇到换行符,自动添加'\0',可正确处理含空格的完整句子整行读取03混合使用陷阱cin>>后紧跟getline时,前者遗留的换行符会被后者立即读取为空行,需用cin.ignore()清除cin.ignore()04gets()已废弃无法限制读入长度导致缓冲区溢出风险,C++14起已从标准库中彻底移除缓冲区溢出STANDARDLIBRARYC标准库字符串函数C标准库的字符串函数全部基于字符指针实现,通过遍历指针直到'\0'来操作字符串。使用时必须确保目标缓冲区足够大,否则极易引发缓冲区溢出安全漏洞。LENGTH©strlen(s)逐字节扫描至'\0',返回字符个数,时间复杂度O(n)strcpy(dest,src)逐字符复制到dest直到'\0',dest空间不足则溢出O(n)CONCAT&COMPAREstrcat(dest,src)找到dest的'\0'位置追加src,需容纳拼接总长度strcmp(s1,s2)逐字符比较ASCII值,返回0/正/负值表示大小关系ASCIISAFEALTERNATIVESstrn*系列strncpy、strncat、strncmp增加长度限制n,防止溢出std::string现代C++推荐替代方案,自动管理内存且接口丰富SAFECPointerTechniques指针处理字符串的经典技巧利用字符指针和'\0'终止符的特性,可以实现无需预知长度的字符串遍历、反转和回文判断等算法。双指针技术(首尾各一个指针向中间逼近)是字符串处理中最常用的指针编程范式。指针遍历while(*p){process(*p);p++;}利用'\0'值为0的特性作为循环终止条件,简洁高效while(*p)字符串反转设head指向首字符、tail指向'\0'前一个字符,交换*head和*tail
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- escesa非心脏手术指南心血管病评估和管理
- i药物及其临床应用
- DNA是主要的遗传物质白慧涓
- B8先期产品质量规划课程讲义
- ABO血型课件适合中小学生
- 2026年智能工业设计类资格考试智能工业设计师资格试卷
- 2026年汽车工程师《汽车设计技术》真题卷
- 2026年珐琅工艺毕设题目及答案
- 车辆消防安全课件
- 量具器具校准维护规范
- 甘孜州2026年社会工作服务岗招募(5人)考试备考题库及答案详解
- 急性肺栓塞介入治疗进展2026
- 2026秋外研版九年级上册英语单词表
- 2026语文新教材五年级上册必背内容及打卡表
- 2026年监狱干警思想动态分析
- 国企党务工作者(党建岗)面试题和专题题20问及答案
- 2026石墨双极板在燃料电池中的成本分析报告
- 2026年汽车维修店安全教育培训计划
- 2024年医院依法执业培训
- 玉米品种耐热性评鉴体系技术规程
- 偏瘫患者的转移训练
评论
0/150
提交评论