10_第10章指针_第1页
10_第10章指针_第2页
10_第10章指针_第3页
10_第10章指针_第4页
10_第10章指针_第5页
已阅读5页,还剩79页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章指针 10 1地址和指针的概念数据在内存的存放 读取方式 以变量为例 用户在程序设计中定义一个变量 内存区每一个字节有一个编号 地址 编译过程中 1 根据变量类型 分配一定长度的内存空间 2 变量名转换为所分配内存的地址 2 用户存取数据方式 变量名 地址 地址所标志的内存段 1 数据使用前的编译处理过程 数据 一个比方 旅客 变量数据旅客名字 变量名旅馆房间 内存区旅馆房间号 地址查找旅客 旅客名字 房间号码 房间 找到旅客存取数据 变量名 内存地址 内存区 数据 注意 内存单元的地址与内存单元的内容是不同的 内存单元地址 旅馆房间号码内存单元内容 住在房间内的旅客 内存地址 内存用户数据区 内存中存放的数据 3 数据存取举例设程序中已定义三个整型变量i j k 编译时系统将2000和2001两个字节给变量i 2002 2003给j 2004 2005给k 内存分配示意图如下 内存地址 内存用户数据区 printf d i 变量名i 地址2000 取变量值3 送到PRNk i j变量名i 地址2000 取变量值3变量名j 地址2002 取变量值6 相加得9 送到K占用的2004 2005 4 直接访问与间接访问直接访问 在数据存取中 直接得到变量i地址然后按变量i的地址存取变量i的值的方式 间接访问 在数据存放中 变量i的地址不是直接得到 而是存放在另一个变量i pointer中 须先从变量i pointer中获取变量i地址 然后按变量i地址存取变量值i的方式 一个比方 取抽屉A中的东西 直接访问 直接得到钥匙A 打开抽屉A 取出东西 直接获得变量i地址 按变量i地址存取变量的i值 间接访问 钥匙A在抽屉B中 用钥匙B打开抽屉B得到钥匙A 打开抽屉A取得东西 变量i地址放在变量i pointer中 读取变量i pointer值得到变量i的地址 按变量i地址存取i值 间接访问例子过程 根据变量名i pointer获得地址3010 到地址3010读取数据 得到2000 变量i的地址 到2000地址读取数据 得到变量i的值 内存地址 内存用户数据区 5 指针和指针变量指针 一个变量的在内存区中的地址称为指针 通过变量的指针 可以找到变量的存储单元 从而读取其中存放的值 指针变量 专门用来存放指针的变量 称为指针变量 指针变量存放的数据为另一变量的地址 指针 注意 指针与指针变量的区别指针 是一个地址 用于指向存放变量数据的内存单元 指针变量 是一个变量 它的值是指针例如 变量i的地址2000为该变量的指针 变量i pointer是用来存放变量i的指针的 它是一个指针变量 10 2变量的指针和指向变量的指针变量 指针 它首先是一个地址 是指变量在内存中的地址 指针变量 它是一个变量 是一个专门存放变量地址的变量 用来指向另一个变量 为了表示指针变量和它所指向的变量之间的联系 在程序中用 表示 指向 例 i pointer代表指针变量 而 i pointer是i pointer所指向的变量 如下图所示 i pointer i pointer 2000 3 2000 i i pointer与i是等效的 都表示同一变量 该变量存放地址为2000 因此 i 3 i pointer 3两语句作用相同 10 2 1定义一个指针变量 例 inti j int pointer 1 pointer 2 第一条命令定义了两个整型变量i j 第二条命令定义了 两个指针变量pointer 1 pointer 2 它们指向整型变量 两个整型变量 pointer 1 pointer 2 它们与i j为相同类型 被pointer 1 pointer 2两个指针所指向 基类型 指针变量的基类型是指该指针变量可以指向的变量的类型 定义指针变量的一般形式 基类型 指针变量名例 float pointer 3 pointer 3是指向实型变量的指针变量 char pointer 4 pointer 4是指向字符型变量的指针变量 指针变量指向的改变 方法 将一个该指针允许指向的变量的地址赋给该指针 pointer 1 i pointer 1 i pointer 1 i 执行赋值语句之前 执行赋值语句之后 定义指针变量时应注意的两点 1 表明它后面所跟的变量类型是指针型变量 需要指出的 以上例为例 指针变量名为pointer 1 而不是 pointer 1 pointer 1是一个整型变量 2 在定义指针变量时必须指定基类型 因为不同数据类型占用的内存空间大小不同 在进行指针移动和运算时 将导致不同的结果 如 指针值 1 对于基类型为整型 将向后移动两个字节 对于基类型为实型 将向后移动四个字节 例 10 2 2指针变量的引用 WARNING 指针变量中只能存放地址 指针 不能把其它类型的数据赋给指针变量 例 pointer 1为指针变量pointer 1 100为非法赋值 因为100为整行变量 有关的两个运算符 1 取地址运算符 2 指针运算符 或称为 间接访问 运算符 例 a为变量a的地址 p为指针变量p所指向的存储单元 例程说明例 二 指针变量的引用例10 1main inta b int p1 p2 a 100 b 10 p1 间接访问 方式 结果 100 10100 10程序中 p1表示指针变量p1所指向的变量 即a p2表示指针变量p2所指向的变量 即b p1 a a b 100 10 p2 b p1 p2 关于 与 运算符的说明 1 是取地址运算符 如 a b等 是指针运算符 用于定义时表示其后的标识符是指针变量 而在程序中 p则表示指针变量p所指向的变量 即目标变量 2 同优先级 按从右至左方向结合 a 如 inta p1 p2 p1 则 p1 等价于a 但注意 p1 不等价于 p1 a p1 p1 a a 因为 p1 等价于 p1 即先得p1所指向变量的值 再使指针变量p1的值自增 此时p1已不在指向原来的变量了 例10 2main int p1 p2 p a b scanf d d 如输入 5 9 输出 a 5 b 9max 9 min 5 注意 本程序是采用交换变量a和b的地址来实现两个数的比较的 且比较前后a b的值并未发生变化 a b 5 9 b a 9 5 p1 p2 p p p1 p2 a b a b 三 指针变量作为函数的参数指针变量可以作函数的参数 其作用是将一个变量的地址传送到另一个函数中 例10 3swap p1 p2 int p1 p2 intp p p1 p1 p2 p2 p main inta b pointer 1 pointer 2 scanf d d 若输入 5 9 输出为 9 5 本程序采用的是交换a和b的值 而p1和p2的值不变 同例9 2相反 如果把swap函数改成 swap p1 p2 int p1 p2 int p p p1 此句有问题 p1 p2 p2 p 又如 swap intx inty intt t x x y y t P无确定的地址值 它的的值不可预见 p所指向的单元也是不可预见 对 p赋值可能会破坏系统的正常状态 注意参数的传递类型为 值传递 说明 1 不能通过改变形参指针变量的值而使实参指针变量的值改变 2 可以通过改变形参指针变量所指向的变量的值来改变实参指针变量所指向的变量的值 3 如想通过函数调用得到n个要改变的值 可以 1 在主调函数中设n个变量 并用n个指针变量指向它们 2 将指针变量作实参 使n个变量的地址传给所调用的函数形参 3 通过形参指针变量 改变该n个变量的值 4 主调函数中就可以使用这些改变了值的变量 swap p1 p2 int p1 p2 int p p p1 p1 p2 p2 p main inta b pointer 1 pointer 2 scanf d d 本函数中试图通过改变形参指针变量的值来使实参指针变量的值改变 作者原意图是实现这样的结果 C语言中实参变量和形参变量之间的数据传递是单向的 值传递 方式 指针变量作为函数参数也要遵循这一规律 总结 要实现双向传递的地址传递 在被调函数中必须对指针变量的目标变量进行操作 如果只是对指针变量本身进行操作 仍然是单向传递 这点是指针变量作为函数参数的难点和重点 例10 4输入a b c3个整数 按大小顺序输出swap pt1 pt2 int pt1 pt2 intp p pt1 pt1 pt2 pt2 p exchange int q1 q2 q3 if q1 q2 swap q1 q2 if q1 q3 swap q1 q3 if q2 q3 swap q2 q3 main inta b c p1 p2 p3 scanf d d d 10 3数组的指针和指向数组的指针变量 C语言中 指针变量可以指向变量 也可以指向数组和数组元素 数组的指针 数组的起始地址 数组元素的指针 数组元素的地址 一 指向数组的指针变量的定义与赋值指向数组的指针变量的定义同指向变量的指针变量的定义相同 如 inta 10 int p 若 p 的含义是将数组首地址赋给指针变量p 而不是赋给 p 二 通过指针引用数组元素如 inta 10 p p a 则 1 p a 0 的地址 p 1 a 1 的地址 p i a i 的地址 2 p a 0 p 1 a 1 p i a i 说明 1 数组元素在内存中是连续存放的 C语言规定 指针变量p 1指向下一个元素 不是简单的加1 2 p i 表示指向a i 的地址 而a i也表示a i 的地址 故程序中 p i 等价于a i 如 p 2 a 2 3 指向数组的指针变量可以带下标 如 p i p i a数组 p p 1 a 1 p i a i p 9 a 9 a 0 a 1 a i a 9 p i 综上所述 数组元素的引用可以 假定 inta 10 p a 1 下标法 数组名 下标 或指针变量名 下标 a i p i 2 指针法 p i 或 a i 例10 5用三种方法输出数组各元素 1 下标法main inta 10 i for i 0 i 10 i scanf d 注意几点 1 指针变量可以作自增 自减运算 如 p p 而数组名不能作自增 自减运算 如a a等 均不合法 因为数组名是常量 2 注意指针变量的当前值 如 例10 6 main inta 10 i p p a for i 0 i 10 i scanf d p printf n for i 0 i 10 i p printf d p 3 注意指针变量的运算 如 inta 10 i p p a 则 a p 或p 1 表示p指向a 1 此时若执行 p 则取出a 1 元素的值 b 与 同优先级 自右往左结合 如 p 等效于 p 即先取p所指向变量的值 再使p 1 而 p 与 p 的作用不同 前者先取 p的值 后使p 1 后者是先使p 1 再取 p的值 p 表示使目标变量的值加1 而不是指针变量的值加1 e p 等价于a i p 等价于a i 即先使p自增 再作 运算 如 main inta 100 p p a while p a 100 printf d p main inta 100 p p a while p a 100 printf d p p 三 数组名作函数参数 数组名作函数参数时 实际上是将实参数组的首地址传给形参 这样实参数组与形参数组共占同一段内存 使得在调用函数过程中 形参数组中元素值发生变化也就使实参数组的元素值随之而发生变化 如 main intarray 10 f array 10 f arr n intarr n arr 1 实参传递给形参后arr和arry指向同一内存地址 2 将 10 传递给形参n后 界定了形参数组的范围 3 这种 数组名 数组元素个数 的参数形式是常用的 例10 7将数组a中n个整数按相反顺序存放 题意分析 本题的关键是最后交换的两个元素的上下标值的确定 即将第一个元素和最后一个元素对换 将第二个同倒数第二个对换 即两两对换 直到 a n 1 2 与a n int n 1 2 对换为止 其中a n int n 1 2 与a n 1 n 1 2 等效 voidinv x n intx n intt i j m n 1 2 for i 0 i m i j n 1 i t x i x i x j x j t return main staticinti a 10 3 7 9 11 0 6 7 5 4 2 printf Theoriginalarray n for i 0 i 10 i printf d a i printf n inv a 10 printf Thearrayhasbeeninverted n for i 0 i 10 i printf d a i printf n 例10 8从10个数中找出其中最大值和最小值intmax min voidmax min value array n intarray n int p array end array end array n max min array for p array 1 pmax max p elseif p min min p main inti number 10 printf enter10data n for i 0 i 10 i scanf d 等效于 array 0 即array 0 此例也可改用指针变量来传送地址 程序可改为 intmax min voidmax min value array n int array n int p array end array end array n max min array for p array 1 pmax max p elseif p min min p return main inti number 10 p p number printf enter10data n for i 0 i 10 i p scanf d p printf the10data n for p number i 0 i 10 i p printf d p p number max min value p 10 printf nmax d min d n max min for p number p number 10 p 等效于 综上所述 对于实参数组 想在被调函数中改变此数组元素的值 实参与形参的对应关系可以如下 1 二者都用数组名main inta 10 f a 10 f x n intx n 特点 a和x数组共用同一段内存单元 2 实参为数组名 形参用指针变量 main inta 10 f a 10 f x n int x n 特点 实参将数组的首地址传给形参指针变量 通过指针变量指向数组中的任一元素 进而作相应的处理 3 二者都用指针变量 main inta 10 p p a f p 10 f x n int x n 特点 先使p指向a数组 再将p传给x 使x也指向a数组 从而进行处理 4 实参为指针变量 而形参为数组名 main inta 10 p p a f p 10 f x n intx n 特点 利用指针变量将a数组的首地址传给x数组 使两数组共用同一段内存单元 利用x i 值的变化 使a i 的值也发生变化 注意 在上述四种处理方式中 当用指针变量作实参时 必须先使指针变量有确定的值 即指向一个已定义的数组 四 指针与二维数组 1 指针与二维数组一个数组的名字代表该数组的首地址 并可看成是地址常量 这一规定对二维数组或更高维数组同样适用 若有定义 float p d 3 5 则 2 二维数组元素和二维数组元素的地址 假设数组名为a 起始地址设为200inta 3 4 1 3 5 7 9 11 13 15 17 19 21 23 则 a代表整个二维数组的首地址 即第0行的首地址a 1是数组a第1行首地址 208 a 0 a 1 a 2 是二维数组中三个一维数组的名字 地址 是第0行 第1行 第2行的首地址 即 a 0 a 0 a 1 a 1 a 2 a 2a i j是第i行j列的地址 a i j 是该地址存储的值 即a i j 考虑 a 2 3 注意 a i 和 a i 无条件等价a i a i a i a i 0 均表示第i行首地址 a i j a i j a i j都是第i行j列元素的地址 a i j a i j a i j 都是第i行j列元素的值 例 将a矩阵与b矩阵相加 和存入c矩阵 inti j main int p a 3 4 b 3 4 c 3 4 printf Thevalueofa n for i 0 i 3 i for j 0 j 4 j scanf d a i j printf Thevalueofb n for i 0 i 3 i for j 0 j 4 j scanf d b i j matrix a b 0 matrix int x int y int z for i 0 i 3 i for j 0 j 4 j z i 4 j x i 4 j y i 4 j 数组元素在内存中按 行优先 的顺序存放 因此可用x i 4 j表示二维数组各元素的地址 10 4字符串的指针和指向字符串的指针变量 字符串的指针就是字符串的首地址 一 字符串的表示形式1 用字符数组实现例10 16main staticcharstring ILoveChina printf s n string 例中string是数组名 它表示字符数组的首地址 相应的streing i 表示数组中的一个元素 如 string 4 代表第五个元素 即字母v 2 用字符指针实现例10 17main char string ILoveChina printf s n string 例中string是一个指向字符串的指针变量 尽管程序中没有直接定义字符型数组 但实际上 C语言对字符串常量均按字符数组来处理 即在内存中开辟了一个字符数组用来存放字符串常量 另外 char string ILoveChina 等价于以下两条语句 char string string ILoveChina 其含义是将字符串的首地址赋给指针变量string 注意 C语言中对字符串可以进行整体输入和输出 如例10 16 why 而对数值型数组则不能用数组名来输出它的全部元素 只能逐个元素输出 如 inta printf d n a 不行 对字符串的处理可以用下标法也可用指针法 例10 18将字符串a复制到字符串b main chara Iamaboy b 20 for i 0 a i 0 i b i a i b i 0 printf stringais s n a printf stringbis for i 0 b i 0 i printf c b i printf n 运行结果 stringais Iamaboy stringbis Iamaboy 例10 19用指针变量来处理例10 18问题 main chara Iamaboy b 20 p1 p2 inti p1 a p2 b for p1 0 p1 p2 p2 p1 p2 0 printf stringais s n a printf stringbis for i 0 b i 0 i printf c b i printf n 二 字符串指针作函数参数 用字符数组名和指向字符串的指针变量作函数参数 均可以处理字符串 例10 20用函数调用实现字符串的复制 1 用字符数组作函数参数voidcopy string from to charfrom to inti 0 while from i 0 先判断 后赋值 to i from i i to i 0 main chara Iamateacher charb youareastudent printf string a s nstring b s n a b copy string a b printf nstring a s nstring b s n a b 本程序main函数中也可用字符型指针变量 改写如下 main char a Iamateacher char b youareastudent printf string a s nstring b s n a b copy string a b printf nstring a s nstring b s n a b 2 形参用字符指针变量voidcopy string from to char from to for from 0 from to to from to 0 main char a Iamateacher char b youareastudent printf string a s nstring b s n a b copy string a b printf nstring a s nstring b s n a b 3 对copy string函数的简化a voidcopy string from to char from to while to from 0 from to 即先赋值 后判断 故 to 0 语句不要 b voidcopy string from to char from to while to from 0 注意 c voidcopy string from to char from to while from 0 to from to 0 d voidcopy string from to char from to while from to from to 0 e voidcopy string from to char from to while to from f voidcopy string from to char from to for to from 0 for to from 综上所述 用函数调用来处理字符串时 函数参数可以有以下几种情况 实参形参1 数组名数组名2 数组名字符指针变量3 字符指针变量字符指针变量4 字符指针变量数组名 三 字符指针变量与字符数组的区别1 字符数组由若干个元素构成 每一个元素中存放一个字符 而字符指针变量中存放的是字符串的首地址 绝非将字符串放在字符指针变量中 2 赋值方式可以不同 如 charstr Hellow char a Hellow 对指针变量也可以 char a a Hellow 而 charstr 10 str Hellow 合法 不合法 3 数组定义后 在编译时就已分配内存单元 即由确定的值而对指针变量定义后 尽管系统给其分配了内存单元 但在没有明确指向前 其值是不确定的 如 charstr 10 scanf s str 而 char a scanf s a 可改为 char astr 10 a str scanf s a 注意 char a a Hellow 合法 不合法 合法 4 指针变量的值可以改变 而数组名则不行 例10 21main char a IloveChina a a 7 printf s a 运行结果 China 而下面程序则是错的 main staticcharstr IloveChina str str 7 printf s str 可改为 main staticcharstr IloveChina printf s str 7 例10 22 p195 main char a ILOVECHINA inti printf Thesixthcharacteris c n a 5 for i 0 a i 0 i printf c a i 运行结果 ThesixthcharacterisEILOVECHINA 指针变量带下标方式引用字符等价于 a i 5 可用指针变量指向一个格式字符串 用以代替printf函数中的格式控制 如 char format format a d b f n printf format a b 当然也可用字符数组 如 staticcharformat a d b f n printf format a b 由于不能对字符数组整体赋值 所以用指针变量就更方便灵活 char format format a d b f n printf format a b format c c d u n printf format c d 10 5函数的指针和指向函数的指针变量 一 用函数指针变量调用函数函数的指针 函数的入口地址函数的指针变量 指向函数入口地址的指针变量一个已定义的函数在编译时 系统为其分配一个入口地址 并用函数名表示 通过指向函数的指针变量 也可以调用函数 指向函数的指针变量的一般定义形式 数据类型 标识符 其中 数据类型是指函数返回值的类型 如 int p 例10 23求a和b中的大者 main intmax 函数说明语句 inta b c scanf d d main intmax int p inta b c p max scanf d d 可代替 说明 1 C语言中 函数调用可以有两种形式 即函数名调用和函数指针调用 2 p 表示一个指向函数的指针变量 用于存放函数的入口地址 若把某一个函数的入口地址赋给它 它就指向该函数 即在程序中一个函数指针变量可以先后指向不同的函数 3 对于指向函数的指针变量作自增或自减运算均无意义如 int p p p n p 因为p只能指向函数的入口地址 而不能指向函数内的某一条指令 二 用指向函数的指针变量作函数参数 函数指针变量作函数参数时 它是将函数名 即函数的入口地址 传给形参 这种方式的优点在于 多次调用函数 且每次要调用的函数不固定时 只需给出不同的函数名作实参即可 而函数不必作任何修改 这符合结构化程序设计方法的原则 例10 24main intmax min add inta b printf enteraandb scanf d d min intx inty intz if x y z x elsez y return z add intx inty intz z x y return z process intx inty int fun intresult result fun x y printf d n result 说明 1 main函数的第二行不能少intmax min add 因为在用函数指针变量调用函数是用函数名作实参 为保证编译系统正确判别它是函数名 必须作说明 2 本程序如采用函数直接调用 主程序可改为 main inta b z printf enteraandb scanf d d 10 6返回指针值的函数 不讲 10 7指针数组和指向指针的指针 一 指针数组的概念由同一数据类型的指针变量构成的数组叫指针数组 即一个数组的所有元素均为指针型数据 定义格式 类型标识符 数组名 数组长度 如 int p 4 即表示指针数组p有四个元素 每一个元素都是指针变量 且可以指向一个整型变量 指针数组的下标仍从0开始计 例10 28将若干个字符串按字母顺序 由小到大 输出 指针数组 排序后的结果 本例是通过改变指针数组中各元素的值 在不改变字符串位置的情况下 达到排序的目的的 include string h main voidsort voidprint staticchar name Followme BASIC Greatwall FORTRAN Computerdesign intn 5 sort name n print name n voidsort char name intn char temp inti j k for i 0 i0 k j if k i temp name i name i name k name k temp voidprint char name intn inti for i 0 i n i printf s n name i voidprint name n char name intn inti 0 char p p name 0 while i n p name i printf s n p 二 指向指针的指针 定义格式 数据类型 标识符如 char p 表示一个指向字符指针变量的指针变量即 p中只能存放一个指向字符型数据的指针变量的地址 main staticchar name Followme BASIC Greatwall FORTRAN Computerdesign char p inti for i 0 i 5 i p name i printf s n p 运行结果 FollowmeBASICGreatWallFORTRANComputerdesign 表示name i 的地址 说明 指针数组的元素也可以指向整型数据或实型数据例10 30main staticinta 5 1 3 5 7 9 int num 5 运行结果 13579注意 程序中 p是p间接指向的对象的地址 而 p是p间接指向的对象的值 三 指针数组作main函数的形参 命令行的一般形式 命令名参数1参数2 参数n如 file1ChinaBeijingcopyf1 ce file c带参数的main函数的一般形式 main argc argv intargc char argv 其中 argc是命令行中参数的个数 包括命令名 argv是一个指向字符串的指针数组 若输入的命令行为 file1ChinaBeijing

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论