版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++高级语言程序设计第四章数组—从一维到多维,从静态到动态Contents本章目录数组与指针的核心知识体系概览01一维数组基础与应用02指针与指针数组03二维数组与多维数组04数组与函数及动态存储05字符数组与字符串处理CHAPTER01一维数组基础与应用掌握连续内存中同类元素的组织方式与访问规则C++FUNDAMENTALS一维数组的定义与初始化一维数组是C++中存储同类型数据的连续内存结构,定义时需指定类型、名称和常量大小,支持完全初始化、部分初始化和自动推断三种初始化方式,未显式初始化的元素默认为零值。C++编程环境·数组定义代码实拍01基本语法类型数组名[常量]方括号内必须是编译期常量02完全/部分初始化逐个赋值所有元素,或仅赋前几个、剩余自动置零03自动推断大小省略方括号内数字,编译器根据初值列表自动确定长度04默认值差异全局数组默认0(静态区),局部数组为垃圾值(栈区)MemoryLayout一维数组的内存布局与下标访问数组元素在内存中连续排列,数组名即首元素地址,下标访问的本质是"基址+偏移量"的地址运算,理解这一机制是掌握指针与数组关系的前提。01连续存储inta[5]在内存中占用5×4=20字节连续空间,元素a[0]到a[4]依次排列,相邻元素地址差恰好为sizeof(int)即4字节20B02数组名即地址数组名a等价于&a[0],是常量指针(不可修改a本身的指向),通过a可获取整个数组的起始内存位置a≡&a[0]03下标运算本质a[i]被编译器转换为*(a+i),即从首地址偏移i个元素单位后取值,因此下标从0开始、最大为n−1*(a+i)04越界访问风险C++不进行数组边界检查,访问a[5]或a[−1]不会报编译错误,但会读写非法内存,导致程序崩溃或数据损坏无边界检查ARRAYFUNDAMENTALS一维数组的典型应用模式数组的核心操作模式包括遍历求和、极值查找和元素逆序,这些模式体现了'循环+条件判断'的基本算法思想,是后续排序、查找等复杂算法的构建基石。遍历求和与统计用for循环遍历所有元素累加求和,结合计数器计算平均值,是最基础的数组操作范式O(n)极值查找(打擂台法)将a[0]设为初始最大/最小值,逐一与后续元素比较并更新,遍历一轮即可找到全局极值打擂台法数组逆序(首尾交换法)设置头尾两个下标i=0和j=n-1,交换a[i]与a[j]后i++、j--,循环n/2次完成逆序n/2次数组拷贝与比较C++不支持数组整体赋值(a=b非法),必须逐元素拷贝;比较两个数组也需逐元素判断逐元素SortingAlgorithms一维数组经典应用:排序算法冒泡排序与选择排序是基于数组的两种基础排序算法,均通过嵌套循环实现元素重排,理解其原理有助于掌握算法设计中的比较-交换范式与复杂度分析方法。冒泡排序外层循环控制轮数(n−1轮),内层循环相邻元素两两比较,若a[j]>a[j+1]则交换,每轮将当前最大值沉底。n−1轮沉底选择排序每轮从未排序区间选出最小元素的下标,与未排序区间首元素交换位置,逐步构建有序前缀。最小值选择复杂度分析两种算法时间复杂度均为O(n²),空间复杂度O(1),属于原地排序;冒泡排序可通过设置标志位提前终止优化。O(n²)·O(1)标准库推荐C++标准库提供std::sort()函数(位于<algorithm>头文件),底层为快速排序优化实现,实际开发中推荐使用。std::sort()MemoryArchitecture变量的存储类型与内存分区C++程序运行时内存分为栈区、堆区、全局/静态存储区和代码区四大区域,变量的存储类型决定了其内存位置、生命周期和访问方式。四种存储类型对照表存储类型适用范围内存区域生命周期关键特点auto局部变量(默认)栈区函数/代码块执行周期自动分配释放,无需显式写autostatic局部/全局变量全局/静态存储区整个程序运行周期局部static仅初始化1次,全局static限制文件作用域extern全局变量声明全局/静态存储区整个程序运行周期用于跨文件共享全局变量(仅声明不定义)register局部变量(频繁使用)寄存器(或栈区)函数/代码块执行周期建议存寄存器提速,不能取地址(&)栈区Stack存放局部变量和函数参数,由编译器自动分配和释放,空间有限但访问速度快,普通局部数组即分配在此。堆区Heap由程序员通过new/delete手动管理的动态内存区域,空间大但需手动释放,动态数组即分配在堆区。全局/静态存储区存放全局变量和static修饰的变量,程序启动时分配、结束时释放,static局部变量仅初始化一次且值持久保留。寄存器Register建议编译器存入CPU寄存器以提升频繁访问变量的速度,但不能对其取地址(&运算非法),实际存储位置由编译器决定。四种存储类型分别对应不同的内存区域和生命周期管理方式,直接影响数组和变量的行为特征。SCOPERULES标识符的作用域与可见性规则C++标识符的作用域分为函数原型、块、函数和文件四个层次,遵循'就近屏蔽'原则——内层作用域的同名标识符会隐藏外层定义,正确理解作用域规则是避免变量命名冲突和逻辑错误的关键。函数原型作用域仅在函数声明的参数列表中有效,如voidfun(inta)中的a只到原型结束,函数定义时可使用不同参数名参数列表块作用域由{}界定,如函数体、if/for代码块内的变量;嵌套块中内层变量会屏蔽外层同名变量,退出内层块后外层变量恢复可见嵌套屏蔽文件作用域全局变量和函数的默认作用域,从定义位置到文件末尾均可见;加static修饰后限制为当前文件内部使用,防止跨文件冲突static同名屏蔽陷阱若局部变量与全局变量同名(如都叫num),函数内优先使用局部变量,全局变量被隐藏,需通过作用域解析运算符::访问全局版本::CHAPTER02指针与指针数组深入理解地址运算、指针与数组的等价关系C++FUNDAMENTALS指针的基本概念与核心操作指针是存储内存地址的变量,通过取地址(&)和解引用(*)两个互逆运算符实现地址与值的转换,指针的类型决定了解引用时读取的字节数,正确使用指针是C++高效内存操作的基础。01定义语法'类型*指针名',如int*p;类型决定解引用时读取的字节数,int读4字节,double读8字节。TYPE*PTR02取地址与解引用&获取变量内存地址,如p=&a;*通过地址访问目标值,*p=10等价于修改a的值。&↔*03指针自身占用64位系统上指针变量占8字节、32位占4字节,与所指向数据类型的大小无关。8BYTE04野指针与空指针未初始化的指针指向随机地址,极其危险;应初始化为nullptr,避免非法内存访问导致崩溃。=NULLPTRC/Pointer&Array指针与数组的等价关系数组名本质上是指向首元素的常量指针,a[i]与*(a+i)在编译器层面完全等价,指针算术运算使得通过指针遍历数组既高效又灵活,但数组名与指针变量在sizeof运算和赋值行为上存在本质差异。数组名即首地址inta[5]中a等价于&a[0],类型为int*,但a是常量指针,不可执行a++或赋值操作。a≡&a[0]下标与指针等价a[i]被编译器转换为*(a+i),p[i]也等价于*(p+i),可通过指针变量访问数组元素。a[i]=*(a+i)指针算术运算p+1不是地址值加1,而是跳过一个元素大小(如int指针+1跳过4字节)。p+1→+4Bsizeof关键区别sizeof(a)返回数组总字节20,sizeof(p)仅返回指针大小8B;数组名不可赋值,指针可以。20Bvs8BC++·Memory指针数组的定义与典型应用指针数组是元素类型为指针的数组,每个元素存储一个内存地址,常用于管理长度不一的字符串集合或构建不规则的二维数据结构,是C++中实现灵活数据组织的重要工具。大学生编程学习场景Syntax定义语法:int*pArr[5]表示含5个int指针的数组,每个元素是独立指针变量,可分别指向不同int变量或数组String字符串管理:char*names[]中每个指针指向不同长度字符串常量,比二维字符数组节省内存且使用灵活Compare与数组指针区别:指针数组是多个独立指针集合(每行可不同长),int(*p)[5]是指向整行的单个指针Usage典型场景:main函数参数argv就是指针数组,操作系统将命令行参数作为字符串数组传递给程序POINTER·ARRAYTRAVERSAL指针运算与数组遍历方式对比C++中遍历数组有下标法和指针法两种基本方式,底层都基于"基址+偏移"的地址运算,指针法通过直接操作内存地址在某些场景下更灵活高效,两个同数组指针相减可得元素间距。METHOD01下标法遍历for(inti=0;i<n;i++)a[i],写法直观易读,编译器内部将a[i]转换为*(a+i)执行,是初学者的首选方式。a[i]→*(a+i)METHOD02指针法遍历int*p=a;*(p+i)或*p++,直接操作地址,在早期编译器中比下标法效率更高。直接地址操作OPERATION01指针递增p++使指针移向下一个元素,地址增加sizeof(类型)字节;p--反向移动,可灵活实现正向和反向遍历。sizeof(T)步进OPERATION02指针相减若p和q指向同一数组,p−q的结果为两指针间的元素个数,常用于计算子数组长度。ptrdiff_tCHAPTER03二维数组与多维数组从矩阵思维到行列优先的内存映射机制C/C++·数组与指针二维数组的定义与初始化方式二维数组在概念上表现为行列矩阵,但物理上仍是一维连续存储,定义时必须明确列数(行数可省略),初始化支持按行分组、按序展开和部分初始化三种方式。01定义语法类型数组名[行数][列数],如inta[3][4]定义3行4列共12个int元素,总占用3×4×4=48字节连续内存48字节02按行分组初始化inta[2][3]={{1,2,3},{4,5,6}},外层花括号表示行,内层花括号表示每行的列元素,写法最直观{{…},{…}}03按序展开初始化inta[2][3]={1,2,3,4,5,6},按内存中元素排列顺序依次赋值,编译器自动按列数换行{1,2,3,4,5,6}04行数可省略列数不可省inta[][3]={1,2,3,4,5,6},编译器根据总元素数和列数自动推算行数为2,但列数必须显式指定a[][3]MEMORYMODEL二维数组的行优先存储机制C++二维数组采用行优先方式将矩阵映射到一维连续内存中,元素a[i][j]的实际地址为"首地址+(i×列数+j)×元素大小"行优先存储inta[3][4]在内存中按a[0][0]…a[0][3]、a[1][0]…a[2][3]的顺序连续排列48字节地址计算公式a[i][j]地址=a+(i×COLS+j)×sizeof(元素类型),COLS为列数i×C+j行优先遍历更高效外层行、内层列使内存访问连续,CPU缓存命中率更高;列优先遍历导致缓存频繁失效缓存命中与列优先的区别Fortran/MATLAB采用列优先存储,跨语言传递矩阵数据时需特别注意内存排列差异Fortran/MATLABApplicationScenarios二维数组的典型应用场景二维数组是矩阵运算、网格数据和图像处理的基础数据结构,通过行列索引可高效访问和修改元素,在科学计算、游戏开发和计算机视觉等领域有广泛应用。矩阵运算01矩阵加法对应元素相加C[i][j]=A[i][j]+B[i][j],要求两矩阵行列数相同,用双重循环实现02矩阵转置行列互换B[j][i]=A[i][j],原地转置需注意方阵与非方阵的不同处理策略03矩阵乘法C[i][j]=ΣA[i][k]×B[k][j],需三重循环,时间复杂度O(n³),是线性代数运算的核心网格与图像01棋盘/地图表示用二维数组存储网格状态(如intboard[8][8]),每个元素记录格子信息02灰度图像处理元素对应像素亮度值(0-255),图像滤波、边缘检测等算法均基于邻域运算03动态规划表格DP算法中常用二维数组存储子问题结果,如背包问题dp[i][j]表示前i个物品容量j的最优解C++FUNDAMENTALS多维数组与现代C++替代方案C++支持任意维度的数组但实际使用中维度很少超过三维,因为内存占用和代码复杂度会急剧增长;现代C++推荐使用std::vector替代原生数组,获得动态大小、自动内存管理和安全边界检查等优势。多维数组定义三维数组定义如inta[2][3][4],共24个元素,可理解为"二维数组的数组";更高维度语法类似但可读性和内存开销急剧上升,实际开发中建议谨慎使用。维度示例2×3×4内存连续布局多维数组内存仍为一维连续:a[D1][D2][D3]中元素a[i][j][k]的偏移量为(i×D2×D3+j×D3+k)×sizeof(类型),编译器自动完成多维到一维的地址映射。存储特性连续内存原生数组局限大小必须在编译期确定、不支持整体赋值、传递给函数时退化为指针丢失长度信息、无数组越界检查,这些缺陷导致原生数组在现代C++中逐渐被淘汰。主要缺陷4项局限std::vector替代vector<int>v(10)创建动态数组,支持push_back扩容、size()获取长度、at()安全访问,是现代C++的首选容器,彻底解决了原生数组的安全隐患。核心优势动态扩容CHAPTER04数组与函数及动态存储掌握数组参数传递机制与堆区内存的动态管理C++·FUNDAMENTALS数组作为函数参数的三种方式数组作为函数参数时会自动退化为指向首元素的指针,丢失原始大小信息,因此必须额外传递长度参数;理解这一退化机制是正确设计数组处理函数和避免缓冲区溢出错误的关键。01voidfunc(inta[],intn)—形式上写数组但实际传递的是指针,a[]等价于*a,函数内sizeof(a)只得到指针大小inta[]02voidfunc(int*a,intn)—与方式一完全等价,更明确地表达了"传递的是地址而非整个数组"的事实int*a03voidfunc(int(&a)[5])—通过数组引用传递,保留了数组类型和大小信息,但大小必须在编译期确定,灵活性受限(&a)[5]04由于退化机制,函数无法获知数组大小,必须额外传入n参数或用begin/end指针对,否则极易导致越界访问n/begin·endC++MemoryManagement动态内存分配:new与delete操作符new/delete是C++在堆区进行动态内存管理的核心操作符,支持运行时按需分配和释放内存,但必须严格配对使用,否则将导致内存泄漏或程序崩溃。new操作符在堆区按需分配内存,int*p=newint(10)分配单个变量;int*arr=newint[n]支持运行时变量长度的数组分配。newint(n)delete操作符释放堆区内存,deletep释放单个对象;delete[]arr释放数组。必须与new严格配对,new[]配delete[],不可混用。delete[]arr内存泄漏风险忘记用delete释放已分配内存,该内存将无法被再次使用,长期运行中累积的泄漏最终会耗尽系统资源。MemoryLeak智能指针替代unique_ptr和shared_ptr自动管理动态内存生命周期,离开作用域时自动释放,大幅降低出错风险。SmartPointerMEMORYMANAGEMENT动态数组的创建、使用与管理动态数组通过new在堆区分配,大小可在运行时确定,突破了静态数组必须编译期定长的限制,但需要程序员手动管理内存的分配与释放,是理解C++内存模型的关键实践。01创建动态数组通过int*arr=newint[n]分配,n可以是运行时变量(如用户输入),返回指向首元素的指针,用法与静态数组相同。newint[n]02动态二维数组先分配行指针数组,再逐行分配列空间,每行独立管理,支持不规则行数的灵活结构。int**mat03释放动态数组必须用delete[]释放整个数组,释放后应将指针置为nullptr防止悬空指针被误用。delete[]04静态vs动态静态数组编译期定长、存于栈区、自动释放;动态数组运行期定长、存于堆区、手动释放,适合大数据量或长度不确定的场景。StackvsHeapPREPROCESSOR编译预处理命令与头文件管理编译预处理命令在正式编译前由预处理器执行文本替换操作,#include实现代码模块化复用,#define提供宏替换功能,条件编译指令防止头文件重复包含,这些机制是C++项目组织和代码管理的基础工具。#include文件包含<…>从标准库路径搜索,"…"从当前项目路径搜索,预处理器将头文件内容原样插入替换#include#define宏定义无参宏纯文本替换无类型检查;带参宏需注意参数加括号,避免优先级歧义#defineIncludeGuard头文件保护#ifndef/#define/#endif包裹头文件,防止多次包含导致类或函数重定义编译错误#ifndef/#endif现代C++替代方案const/constexpr替代无参宏,inline函数替代带参宏,#pragmaonce简化头文件保护ModernC++VARIABLESCOPE全局变量与局部变量的对比分析全局变量与局部变量在存储区域、生命周期、默认初始值和作用域上存在根本差异,理解这些差异对正确使用数组至关重要。全局变量定义在函数外部,存储在全局/静态存储区。程序启动时分配、结束时释放,未初始化时默认值为0,作用域覆盖整个文件。全局/静态区局部变量定义在函数或代码块内部,存储在栈区。进入作用域时分配、离开时自动释放,未初始化时值为随机垃圾值,必须手动赋初值。栈区跨文件共享全局变量可通过extern声明在其他文件中访问;若加static修饰(staticintg_num),则作用域限制在当前文件内,防止命名冲突。extern/static数组场景应用大型数组建议定义为全局变量或使用动态分配,避免栈溢出(栈区空间有限,通常几MB);小型临时数组用局部变量即可。栈溢出防护CHAPTER05字符数组与字符串处理从C风格字符串到std::string的演进与实践C/C++FUNDAMENTALS字符数组的定义与C风格字符串字符数组存储char类型元素,C风格字符串必须以'\0'空字符结尾,实际空间比可见字符数多1。定义方式chars[10]定义可存10个字符的数组;逐个字符初始化时,末尾必须显式添加终止符'\0'chars[10]常量初始化chars[]="Hello"编译器自动追加'\0',数组实际大小为6(5字符+1终止符),这是最常用的方式自动追加'\0'终止符作用strlen/strcpy等标准库函数依赖'\0'判断字符串结束位置,缺少终止符将导致越界读取和不可预测行为strlen/strcpy数组vs字符串chars[5]={'a','b','c','d','e'}是字符数组但非字符串——无'\0'则不能整体输出,会越界读取无'\0'≠字符串C-StyleStringOperationsC风格字符串的输入输出与库函数C风格字符串通过cstring头文件提供的库函数进行操作,这些函数依赖'\0'终止符工作但不进行边界检查,使用时必须确保目标缓冲区足够大,否则将导致缓冲区溢出等严重安全隐患。Input输入方式cin>>s以空白符分隔读取单词,无法读空格;cin.getline(s,n)读取整行最多n−1个字符并自动加'\0',更安全。Output输出方式cout<<s从首字符输出直到遇到'\0',无需逐字符循环;若字符数组缺少'\0'则输出内容不可控。cstring常用库函数strlen(s)返回字符数(不含'\0');strcpy/strcat分别用于拷贝与拼接;strcmp(s1,s2)按字典序比较。Warning安全陷阱strcpy和strcat不检查目标数组容量,src超出dst剩余空间将导致缓冲区溢出,推荐strncpy/strncat限制拷贝长度。C++StandardLibrarystd::string类:现代C++字符串处理std::string是C++标准库提供的字符串类,封装了动态内存管理和丰富的操作接口,支持直接赋值、拼接、比较和子串查找,从根本上消除了C风格字符串的'\0'管理和缓冲区溢出问题,是现代C++开发的首选。基本操作直接赋值、s1+s2拼接、s1==s2比较、s.length()获取长度,无需关心内存分配和'\0'终止符s=s1+s2与C字符串互转s.c_str()返回constchar*用于调用C库函数;strings(cstr)从C字符串构造,实现两种风格无缝衔接c_str()↔string丰富接口substr提取子串,find查找位置,replace替换,insert插入,erase删除——覆盖字符串操作全场景substr·find·replace性能考量内部采用小字符串优化(SSO),短字符串直接存在栈上;频繁拼接时建议用reserve()预分配容量减少重分配SSO·reserve()StringComparisonC风格字符串与std::string对比C风格字符串与std::string在内存管理、操作接口、安全性和性能特征上存在显著差异,std::string在绝大多数场景下更优,但C风格字符串在与CAPI交互和嵌入式资源受限场景中仍有不可替代的价值。对比维度C风格字符串(char[])std::string内存管理手动管理,需预留足够空间自动管理,动态扩容终止符必须手动维护'\0'内部自动维护,对用户透明赋值与拼接需用strcpy/strcat函数直接用=和+运算符比较操作需用strcmp()函数直接用==、<、>运算符安全性易缓冲区溢出,无边界检查at()方法提供越界检查适用场景CAPI交互、嵌入式
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- escesa非心脏手术指南心血管病评估和管理
- i药物及其临床应用
- DNA是主要的遗传物质白慧涓
- B8先期产品质量规划课程讲义
- C++大学教程指针和基本指针的字符串
- ABO血型课件适合中小学生
- 2026年智能工业设计类资格考试智能工业设计师资格试卷
- 2026年汽车工程师《汽车设计技术》真题卷
- 2026年珐琅工艺毕设题目及答案
- 车辆消防安全课件
- 国家安全教育大学生读本-第一章完全准确领会总体国家安全观
- (完整版)《增广贤文》全文
- 《建筑施工土石方工程安全技术规范》JGJ180
- GB/T 19822-2024铝及铝合金硬质阳极氧化膜规范
- TSG+23-2021气瓶安全技术规程
- 重点传染病防治学习通超星课后章节答案期末考试题库2023年
- 机械制图机械制图基础知识课件
- 《光伏发电工程可行性研究报告编制规程》(NB/T32043-201)中文版
- 小岛区块链(区块链、数字资产和通证)
- 校长培训精美课件
- 滁州市珠龙广卫绢云母粉厂滁州市南谯区将军山绢云母矿1万吨-年露天采矿工程项目环境影响报告书
评论
0/150
提交评论