━━指针与函数、指针与堆内存.ppt

上传人:sh****n 文档编号:8631588 上传时间:2020-03-30 格式:PPT 页数:32 大小:376.81KB
返回 下载 相关 举报
━━指针与函数、指针与堆内存.ppt_第1页
第1页 / 共32页
━━指针与函数、指针与堆内存.ppt_第2页
第2页 / 共32页
━━指针与函数、指针与堆内存.ppt_第3页
第3页 / 共32页
点击查看更多>>
资源描述
C 程序设计 第4章 3 指针与函数 指针与堆内存 主要内容 指针作为函数参数指针作为函数返回值指向函数的指针C 的四个内存区域动态存储分配堆内存new与delete运算符动态存储分配的几点说明使用new和delete的几点说明常指针指向常量的指针类型标识符的定义 指针作为函数参数 作用 指针作为函数参数 可以使主调函数与被调函数之间共享变量或对象 以实现函数之间数据的双向传递 地址传递 若某函数的一个形参定义为指针类型 则调用该函数时其对应的实参可以是 相同类型的变量 或对象 的地址 相同类型的指针变量 相同类型的数组名 由于实参是一个地址 将该地址传递给了对应的形参指针变量 此时形参指针变量与实参指针指向的是同一个内存区域的变量 或对象 因此若在被调函数中修改了形参指针变量所指向的数据 也就修改了主调函数中实参指针所指向的数据 例 值传递 引用传递 地址传递 函数的参数三种传递方式的比较 includevoidswap1 intp1 intp2 inttemp p1 p1 p2 p2 temp voidswap2 int 例 形参为指针类型 实参可以是相同类型的数组名 includevoidsort1 int p intn 对p指针所指向的n个元素的数组按升序排序 inti j t for i 0 i p j t p i p i p j p j t voidsort2 int p intn 对p指针所指向的n个元素的数组按升序排序 inti j t for i 0 ip j t p i p i p j p j t voidsort3 intp intn 对n个元素的p数组按升序排序 inti j t for i 0 ip j t p i p i p j p j t voidmain inta 6 43 81 32 11 63 10 intb 6 43 81 32 11 63 10 intc 6 43 81 32 11 63 10 intd 6 43 81 32 11 63 10 inti sort1 a 6 for i 0 i 6 i cout a i t cout endl sort2 b 6 for i 0 i 6 i cout b i t cout endl sort3 c 6 for i 0 i 6 i cout c i t cout endl int point d sort2 point 6 for i 0 i 6 i cout d i t cout endl 运行 1132436381101132436381101132436381101132436381 例 设计通用的两矩阵相乘的函数 分析 a为m n矩阵 b为n p矩阵 a乘以b得到c矩阵 则c为m p的矩阵 k n 1矩阵相乘公式 cij aik bkjk 0 includevoidmatrixmul float pa float pb float pc intm intn intp inti j k floatt for i 0 i m i for j 0 j p j t 0 for k 0 k n k t pa i n k pb k p j pc i p j t voidmain floata 2 3 1 2 3 4 5 6 floatb 3 5 1 2 3 4 5 6 7 8 9 6 5 4 3 2 1 floatc 2 5 matrixmul a b c 2 3 5 inti j for i 0 i 2 i for j 0 j 5 j cout c i j t cout endl 运行 28282828206467707356 例 求二维数组的平均值 includefloataverage1 float p intn 形参p为元素指针 floatsum 0 inti for i 0 i n i sum p returnsum n floataverage2 floatp 5 intn 形参p为二维数组 floatsum 0 inti j for i 0 i n i for j 0 j 5 j sum p i j returnsum n 5 floataverage3 float p 5 intn 形参p为行指针 floatsum 0 inti j for i 0 i n i for j 0 j 5 j sum p j p returnsum n 5 voidmain floata 3 5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cout 平均值 average1 a 15 endl cout 平均值 average2 a 3 endl cout 平均值 average3 a 3 endl 运行 平均值 8平均值 8平均值 8 指针作为函数返回值 作用 任一函数 利用return语句可以返回一个值 当函数的返回值为指针时 返回的必须是一个指向已定义数据的指针 且只能返回全局变量或静态变量的指针 不能返回局部变量的指针 返回值为指针的函数的定义 类型 函数名 形参列表 函数体 例 实现字符串逆序的函数 includechar flip char p char p1 p2 temp p1 p2 p while p2 p2 2 while p1 p2 temp p2 p2 p1 p1 temp returnp voidmain chars 100 cout 请输入一行字符 cin getline s 100 cout 逆序后 flip s endl cout 逆序后 s endl 运行 请输入一行字符 123456ABCDEFGH 逆序后 HGFEDCBA654321逆序后 HGFEDCBA654321 例 用递归函数实现字符串的逆序 include 用递归函数实现字符串的逆序char flip1 char p intn 对从p所指的字符开始的后面n个字符实现逆序 chart if n 1 t p 0 p 0 p n 1 p n 1 t flip1 p 1 n 2 returnp 用递归函数实现字符串的逆序输出voidflip2 char p inti 对p所指的字符串从第i个字符开始的字符串逆序输出 if p i 0 flip2 p i 1 cout p i voidmain chars 100 p s intn 0 cout 请输入一行字符 cin getline s 100 while p n flip1 s n cout 逆序后s s endl cout 还原后s flip1 s n endl cout 逆序输出 flip2 s 0 cout endl 运行 请输入一行字符 123456ABCDEFGH 逆序后s HGFEDCBA654321还原后s 123456ABCDEFGH逆序输出 HGFEDCBA654321 例 实现字符串拷贝的函数 includechar copy char to char from char p to while to from returnp voidmain chars1 20 s2 20 cout 请输入一行字符 cin getline s1 20 cout 拷贝前s2 s2 endl copy s2 s1 cout 第1次拷贝后 s2 endl copy s2 ABCDEFG cout 第2次拷贝后 s2 endl 运行 请输入一行字符 123456 拷贝前s2 烫烫烫烫烫烫烫烫烫烫123456第1次拷贝后 123456第2次拷贝后 ABCDEFG 例 实现字符串拼接的函数 includechar stringcat char to char from char p to while to to while to from returnp voidmain chars1 20 s2 20 cout 请输入第一个字符串 cin getline s1 20 cout 请输入第二个字符串 cin getline s2 20 cout 拼接前 s1 s1 ts2 s2 endl stringcat s1 s2 cout 拼接后 s1 s1 ts2 s2 endl 运行 请输入第一个字符串 123456 请输入第二个字符串 ABCDEFG 拼接前 s1 123456s2 ABCDEFG拼接后 s1 123456ABCDEFGs2 ABCDEFG 指向函数的指针 函数的指针 函数的代码存储在内存中 其起始地址称为函数的入口地址 其函数名代表该函数的入口地址 可以定义一个指向函数的指针变量来指向它 即将函数名赋给该指针变量 这样就可以通过该指针变量来调用该函数 指向函数的指针变量的定义 返回值类型 指针变量名 形参列表表 对指向函数的指针变量的赋值 指针变量 函数名注意 指向函数的指针变量只能指向与其具有相同返回值类型且相同参数 参数类型 个数 顺序均一致 的这一类函数 通过指向函数的指针变量来调用函数 格式1 指针变量 实参列表 格式2 指针变量 实参列表 指向函数的指针 例 floats1 intx inty floats2 inta intb ints3 inta intb floatc float f1 int int int f2 int int float f1 s1 这样f1 3 5 就等价于s1 3 5 f1 s2 这样f1 3 5 就等价于s2 3 5 f1 s3 f2 s3 这样f2 3 5 7 就等价于s3 3 5 7 指向函数的指针常用来作为函数的参数 那么在调用该函数时 其对应的实参只要是与该形参指针变量同类型的函数名即可 这样在多次调用该函数的过程中 可实现再调用不同功能的函数 由对应的实参确定 从而大大增加程序的灵活性 例 分别实现两个操作数的加 减 乘 除运算的函数 includefloatadd floatx floaty cout a c b switch c case p add break case p sub break case p mul break case p div break default cout 运算式输入错误 n return cout p a b endl 也可写成 p a b 例 分别实现求一维数组的各元素和 最大元素 各元素平均值的函数 includefloatsum float p intn floats 0 for inti 0 im m p p returnm floatave float p intn returnsum p n n voidprocess float p intn float fp float int cout fp p n endl voidmain floatx 8 2 8 5 7 6 3 9 4 cout 元素和 process x 8 sum cout 最大值 process x 8 max cout 平均值 process x 8 ave 运行 元素和 44最大值 9平均值 5 5 例 用梯形法求下列三个定积分的近似值 area1 42 1 x2 dxarea2 2 51x 1 x2 dxarea3 31 x x2 1 sinx x2 dx分析 用梯形法求定积分area baf x dx的近似值的通用公式为 i n 1area f a f b 2 f a i h hi 1其中 a和b分别为积分的下限和上限 n为积分区间的分隔数 h b a n h为积分步长 f x 为被积函数 include includefloatf1 floatx return 1 x x floatf2 floatx returnx 1 x x floatf3 floatx return x x x 1 sin x x x floatjifen float f float floata floatb intn floaty h y f a f b 2 h b a n for inti 1 i n i y f a i h return y h voidmain cout 第一个积分值 cout jifen f1 2 4 1000 endl cout 第二个积分值 cout jifen f2 1 2 5 1000 endl cout 第三个积分值 cout jifen f3 1 3 1000 endl 运行 第一个积分值 20 6667第二个积分值 0 643927第三个积分值 1 98498 C 的四个内存区域 C 的四个内存区域 代码区 存放程序代码 静态数据区 存放全局变量或对象 存放static局部变量或对象 全局变量或对象在程序开始运行时在该区分配 static局部变量或对象在程序运行过程中第一次进入其作用域时在该区分配 该区的变量或对象直到程序运行结束才被释放 局部数据区 栈区 存放auto局部变量或对象 auto局部变量或对象在程序运行到其作用域时在栈区分配 但怎样分配在编译时就已经确定 auto局部变量或对象在离开其作用域时即被释放 动态存储区 自由存储区 堆区 存放程序运行过程中由new运算符动态创建的变量或对象 动态创建的变量或对象在编译时无法为其预定存储空间 系统根据运行时的具体要求在该区分配 该区的变量或对象需要使用delete运算符才能将其释放 动态存储分配 静态存储分配 通常程序中定义的变量或对象 编译器在编译时就可根据该变量或对象的类型知道其所需内存空间的大小 即怎样分配在编译时就已经能够确定 从而在适当的时候为它们分配确定的内存空间 这种内存分配称为静态存储分配 动态存储分配 有些变量或对象只有在程序运行过程中才能确定其大小 这样编译器在编译时就无法为它们预定内存空间 只能在程序运行过程中 系统根据运行时的具体要求进行内存分配 称为动态存储分配 动态存储分配是在自由存储区 堆区 中进行 堆内存 关于堆内存 堆区是由操作系统直接管理的内存区域 它是 公共的区域 而且 面积 比较大 它的 生命周期 也不是由编译系统控制的 而是由编程的人来控制的 在许多的应用中 堆内存的使用都是必不可少的 必须通过指针 才可以使用堆内存 堆内存的分配与释放 在程序运行过程中 遇到一个需要动态分配的变量或对象时 必须向系统申请取得堆内存中的一块所需大小的内存空间 用于存放该变量或对象 当不再使用该变量或对象时 必须结束它的生命期 需要显式释放其所占用的内存空间 C 中 取得和释放堆内存中的空间 分别通过new和delete运算符来完成 new用来动态分配内存空间 delete用来将动态分配得到的内存空间归还给系统 释放 new与delete运算符 new运算符 动态申请堆空间格式1 指针变量 new类型名 格式2 指针变量 new类型名 初始值 功能 动态创建一个指定类型的变量或对象 若创建成功 堆空间申请成功 new运算返回新分配堆空间的首地址 若创建失败 堆空间申请失败 new运算返回0或NULL 空指针 delete运算符 动态释放堆空间格式 delete指针 功能 释放由new运算动态创建的变量或对象 指针的值必须是new运算所分配堆空间的首地址 即new运算的返回值 new与delete运算符 new运算符 动态创建一维数组格式 指针变量 new类型名 下标表达式 功能 动态创建一个指定类型的一维数组 数组元素的个数为下标表达式的值 若创建成功 堆空间申请成功 new运算返回新分配一维数组空间的首地址 若创建失败 堆空间申请失败 new运算返回0或NULL 空指针 注意 动态为数组分配堆空间时 不能同时进行初始化 delete运算符 动态释放一维数组格式 delete 指针 功能 释放由new运算动态创建的一维数组 指针的值必须是new运算所分配一维数组空间的首地址 且前面必须加上一对方括号 注意 若delete中的方括号 不写 只是释放一维数组中一个元素的空间 例 动态创建变量 includevoidmain int p newint 100 coutvoidmain int p newint 6 cout p i for i 0 i 6 i cout p i t cout endl delete p 运行 请输入六个整数 563491 563491 运行 100200 new与delete运算符 new运算符 动态创建二维数组格式 指针变量 new类型名 下标表达式1 下标表达式2 功能 动态创建一个指定类型的二维数组 数组元素的个数为各维下标表达式值的乘积 若创建成功 堆空间申请成功 new运算返回新分配二维数组空间的首地址 若创建失败 堆空间申请失败 new运算返回0或NULL 空指针 注意 new运算创建二维数组时 必须将返回的地址赋给行指针变量 若要赋给元素指针变量 必须进行类型强制转换 delete运算符 动态释放二维数组格式 delete 指针 功能 释放由new运算动态创建的二维数组 指针的值必须是new运算所分配二维数组空间的首地址 且前面必须加上一对方括号 注意 若delete中的方括号 不写 只是释放二维数组中的一行元素的空间 例 动态创建二维数组 includevoidmain float p1 3 newfloat 2 3 inti j cout p1 i j for i 0 i p2 i for i 0 i 6 i cout p2 i t if i 1 3 0 cout endl delete p1 delete p2 运行 请输入六个整数 563491 563491请输入六个整数 563491 563491 动态存储分配的几点说明 动态分配失败 动态分配是在堆内存中进行 但堆区资源有限 动态分配可能失败 这时new运算返回一个空指针 0或NULL 表示发生异常 堆区资源不足 分配失败 指针删除与堆空间释放 delete指针p 其实际含义是删除指针p所指向的变量或对象 即释放p所指向的堆空间 而不是删除指针p本身 释放该堆空间后 指针p就成了空悬指针 即指针p未指向一个有效的地址 而空悬指针是程序错误的一个根源 此时最好将指针p置空 0或NULL 动态数组的撤消 delete 指针p 注意 不可缺少 否则回收不彻底 若释放由new创建的一维数组 而delete中又少了 由于指针p指向的是一维数组的首元素 是元素地址 此时只回收了首元素所占的堆空间 若释放由new创建的二维数组 而delete中又少了 由于指针p指向的是二维数组的首行 是行地址 此时只回收了首行元素所占的堆空间 动态存储分配的几点说明 内存泄漏与重复释放 new和delete是配对使用的 若new返回的指针值丢失 其所分配的堆空间将无法回收 称为内存泄漏 程序执行结束后 这部分空间将从系统中丢失 必须重新启动计算机才能找回 对同一个堆空间重复释放也是危险的 因为可能在第一次释放后 该空间已经分配给其它变量或对象 再次释放会使新的变量或对象丢失 动态分配的变量或对象的生存期 非动态分配的变量或对象 在定义时都要用标识符命名 称命名变量或对象 auto局部的命名变量或对象其生存期在作用域内 全局和static局部的命名变量或对象在程序运行结束才被自动释放 动态分配的变量或对象没有名字 对其访问只能通过指针来间接进行 称无名变量或对象 其生存期不依赖于建立它的作用域 例如在被调函数中动态分配的变量或对象 只要不被delete释放 在返回主调函数后仍可使用 但前提是其起始地址必须从被调函数中带出 否则将无法访问 使用new和delete的几点说明 使用new动态分配的存储空间 若不赋初值 其初值不确定 若new动态分配的空间较大 通常需要判断其返回的指针值是否为0或NULL 若为0或NULL 表示动态分配失败 此时应终止程序执行或进行出错处理 例 int p 200 newint 100 200 if p 0 exit 0 或if p NULL exit 0 用new为数组动态分配堆空间 不能同时初始化 例 int p newint 5 1 3 5 7 9 必须妥善保存new动态分配空间的指针值 以便其后用delete来归还该动态分配的空间 一旦delete释放了指针所指向的堆空间 就不能再对其赋值 否则可能出现不可预测的错误 常指针 常指针变量的声明 类型 const指针变量名 地址 注意 const的位置写在星号和指针变量名之间 且声明时必须同时进行初始化 指针变量本身的值不能被改变 但可以通过常指针变量来改变所指向的变量的值 例 常指针变量 includevoidmain chars1 ABC s2 123 char constname s1 name是常指针变量cout name endl 输出 ABC name 1 正确 可通过常指针变量来改变所指向的变量的值cout name endl 输出 1BCname s2 错误 常指针变量name本身的值不能被改变 指向常量的指针 指向常量的指针变量的声明 const类型 指针变量名 地址 const的位置写在类型的前面 不能通过这种指针变量来改变所指向的变量的值 但该指针变量本身的值可以被改变 即可以指向其它的变量 例 指向常量的指针 includevoidmain char p1 ABCD p1 2 编译和连接都通过 但运行出错 因为 ABCD 是字符串常量chars1 XYZ s2 123 constchar p2 s1 p2是指向常量的指针 p2 1 编译错误 不能通过p2来改变所指向的变量 s1 1 正确cout p2 编译错误 不能通过p2来改变所指向的数据cin s2 正确cout s2 endl 类型标识符的定义 类型标识符 为了增加程序的可读性和可移植性 可对C 中的基本数据类型名 或已定义的构造数据类型名 再重新定义一个新的类型标识名 经定义后 该标识符可以替代原来的类型名来使用 格式 typedef旧数据类型名新类型标识名 例 类型标识符的定义 includevoidmain typedefintinteger typedefchar string inta 5 integerb 8 cout a a tb b endl char s1 ABCDEFG cout s1 t void s1 endl strings2 s1 cout s2 t void s2 endl 运行 a 8b 8ABCDEFG0 x00426020ABCDEFG0 x00426020
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!