资源描述
C程序设计 讲师:徐红波 Email: 第 10章 指针 指针是 C语言中的一个重要概念 , 也是 C语言的一 个重要特色 。 正确而灵活地运用它 , 可以有效地表示 复杂的数据结构;能动态分配内存;方便地使用字符 串;有效而方便地使用数组;在调用函数时能获得 1 个以上的结果;能直接处理内存单元地址等 , 这对设 计系统软件是非常必要的 。 掌握指针的应用 , 可以使 程序简洁 、 紧凑 、 高效 。 每一个学习和使用 C语言的 人 , 都应当深入地学习和掌握指针 。 可以说 , 不掌握 指针就是没有掌握 C的精华 。 10.1 地址和指针的概念 变量的属性:名、值和地址 变量的访问方式:直接访问、间接访问 变量的地址称为该变量的“指针” 指针变量是存放地址的变量 10.2 变量的指针和指向变量的指针变量 变量的指针就是变量的地址。存放变量地址的变量 是指针变量,它用来指向另一个变量。为了表示指针变 量和它所指向的变量之间的联系,在程序中用“ *”符 号表示“指向”。如果已定义 i_pointer为指针变量,则 (*i_pointer)是 i_pointer所指向的变量。 10.2.1 定义一个指针变量 C语言规定所有变量在使用前必须定义,指定其类 型,并按此分配内存单元。指针变量不同于整型变量和 其他类型的变量,它是用来专门存放地址的,必须将它 定义为“指针类型”。 定义指针变量的一般形式为 基类型 * 指针变量名 ; 可以用赋值语句使一个指针变量得到另一个变量的 地址,从而使它指向一个该变量。 在定义指针变量时要注意两点: (1)指针变量前面的“ *”表示该变量的类型为指针型变 量 (2)在定义指针变量时必须指定基类型 10.2.2 指针变量的引用 指针变量中只能存放地址 (指针 ),不要将一个整数 (或其他非地址类型的数据 )赋给一个指针变量。 有两个有关的运算符: (1) int * pointer_1, * pointer_2; a=100; b=10; pointer_1= pointer_2= printf(“%d, %dn”, a, b); printf(“%d, %dn”, *pointer_1, *pointer_2); 对“ (1) scanf(“%d, %d”, p1= p2= if(ab) p1= p2= printf(“a=%d, b=%dnn”, a, b); printf(“max=%d, min=%dn”, *p1, *p2); 10.2.3 指针变量作为函数参数 函数的参数不仅可以是整型、浮点型、字符型等数 据,还可以是指针类型。它的作用是将一个变量的地址 传送到另一个函数中。 例 10.3题目要求同例 10.2,即对输入的两 个整数按大小顺序输出 #include void main() void s * p1, int * p2); int a, b; int * pointer_1, *pointer_2; scanf(“%d, %d”, pointer_1= pointer_2= if(ab) s, pointer_2); printf(“n%d, %dn”,a, b); void s * p1, int * p2) int temp; temp=*p1; *p1=*p2; *p2=temp; 例 10.4输入 a、 b、 c这 3个整数,按大小顺 序输出 void main() int a,b,c,*p1,*p2,*p3; scanf(“%d,%d,%d”, p1=p2=pe= exchange(p1,p2,p3); printf(“n%d,%d,%dn”,a,b,c); void exchange(int *q1,int *q2,int * q3) if(*q1*q2) s); if(*q1*q3) s); if(*q2*q3) s); void s *pt1,int * pt2) int temp; temp=*pt1; *pt1=*pt2; *pt2=temp; 10.3 数组与指针 一个变量有地址,一个数组包含若干元素,每个 数组元素都在内存中占用存储单元,它们都有相应的 地址。指针变量既然可以指向变量,当然也可以指向 数组元素 (把某一元素的地址放到一个指针变量中 )。 所谓数组元素的指针就是数组元素的地址。 引用数组元素可以用下标法 (如 a3),也可以用指 针法,即通过指向数组元素的指针找到所需的元素。 使用指针法能使目标程序质量高 (占内存少,运行速度 快 )。 10.3.1 指向数组元素的指针 定义一个指向数组元素的指针变量的方法,与以前 介绍的指向变量的指针变量相同。 例如: int a10; int * p; p= p=a; 10.3.2 通过指针引用数组元素 假设 p已定义为一个指向整型数据的指针变量,并 已给它赋了一个整型数组元素的地址,使它指向某一 个数组元素。如果有以下赋值语句: *p=1; 表示将 1赋给 p当前所指向的数组元素。 如果 p的初值为 p=a; for(i=0; i10; i+) scanf(“%d”, p+); printf(“n”); for(i=0; i10; i+, p+) printf(“%d “, *p); printf(“n”); 10.3.3 用数组名作函数参数 如果一个实参数组,要想在函数中改变此数组中的元素的 值,实参与形参的对应关系有以下 4种情况 (1)形参和实参都用数组名 (2)实参用数组名,形参用指针变量 (3)实参形参都用指针变量 (4)实参为指针变量,形参为数组名 例 10.7将数组 a中 n个整数按相反顺序存放 例 10.8用实参指针改写例 10.7 例 10.9用选择法对 10个整数按由大到小顺序排序 10.3.4 多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指 向多维数组中的元素。但在概念上和使用上,多维数 组的指针比一维数组的指针要复杂一些。 1、多维数组元素的地址 int a34=1,3,5,7,9,11,13,15,17,19,21,23; a是一个数组名。 A数组包含三行,即 3个元素: a0、 a1、 a2。而每一个元素又是一个一维数组,它包含 4 个元素 (即 4个列元素 )。例如, a0所代表的一维数组又 包含 4个元素: a00、 a01、 a02、 a03。可以 认为二维数组是“数组的数组”,即二维数组 a是由 3个 一维数组所组成的。 例 10.10输出二维数组有关的值 2、指向多维数组元素的指针变量 (1)指向数组元素的指针变量 例 10.11用指针变量输出二维数组元素的值 (2)指向由 m个元素组成的一维数组的指针变量 例 10.12输出二维数组任一行任一列的值 3、用指向数组的指针作函数参数 一维数组名可以作为函数参数传递,多维数组名也可作函数 参数传递。在用指针变量作形参以接受实参数组名传递来的地址 时,有两种方法 : 1、用指向变量的指针变量 2、用指向一维数组的指针变量 例 10.13有一个班, 3个学生,各学 4门课,计算总平均分数以及 第 n个学生的成绩 例 10.14在上题基础上,查找有一门以上课程不及格的学生,输 出他们的全部课程的成绩 10.4 字符串与指针 10.4.1 字符串的表示形式 在 C程序中,可以用两种方法访问一个字符串 (1)用字符数组存放一个字符串,然后输出该字符串。 例 10.15定义一个字符数组,对它初始化,然后输出该字符 串 (2)用字符指针指向一个字符串 例 10.16定义字符指针 例 10.17将字符串 a赋值为字符串 b 例 10.18用指针变量来处理例 10.17问题 10.4.2 字符指针作函数参数 将一个字符串从一个函数传递到另一个函数,可以 用地址传递的方法,即用字符数组名作参数,也可以用 指向字符的指针变量作参数。在被调用的函数中可以改 变字符串的内容,在主调函数中可以得到改变了的字符 串。 例 10.19用函数调用实现字符串的复制 (1)用字符数组作参数 (2)形参用字符指针变量 10.4.3 对使用字符指针变量和字符数组的讨论 虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们 两者之间是有区别的,不应混为一谈,主要有以下几点。 (1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中 存放的是地址,决不是将字符串放到字符指针变量中。 (2)赋值方式。 (3)对字符指针变量赋初值。 (4)如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。 而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个 字符变量的地址,也就是说,该指针变量可以指向一个字符型数据,但如果 未对它赋予一个地址值,则它并未具体指向一个确定的字符数据。 (5)指针变量的值是可以改变的。 例 10.20改变指针变量的值 例 10.21用带下标的字符指针变量引用字符串中的字符 (6)用指针变量指向一个格式字符串,可以用它代替 printf函数中的格式字符串。 10.5 指向函数的指针 10.5.1 用函数指针变量调用函数 可以用指针变量指向整型变量、字符串、数组,也 可以指向一个函数。一个函数在编译时被分配给一个入 口地址。这个函数的入口地址就称为函数的指针。可以 用一个指针变量指向函数,然后通过该指针变量调用此 函数。 例 10.22求 a和 b中的大者 说明: (1)指向函数的指针变量的一般定义形式为 数据类型 (*指针变量名 ) (函数参数表列 ); (2)函数的调用可以通过函数名调用,也可以通过函数指针调用 (即用指向函数的指针表量调用 )。 (3)“int (*p)(int,int);”表示定义一个指向函数的指针变量 p,它不是 固定指向哪一个函数的,而是表示定义了这样一个类型的变量, 它是专门用来存放函数的入口地址的。 (4)在给函数指针变量赋值时,只需给出函数名而不必给出参数。 (5)用函数指针变量调用函数时,只需将 (*p)代替函数名即可,在 (*p)之后的括号中根据需要写上实参。 (6)对指向函数的指针变量,像 p+n、 p+等运算是无意义的。 10.5.2 用指向函数的指针作函数参数 函数指针变量通常的用途之一是把指针作为参数传 递到其他函数。函数的参数可以是变量、指向变量的指 针变量、数组名、指向数组的指针变量等。函数的指针 也可以作为参数,以实现函数地址的传递,这样就能够 在被调用的函数中使用实参函数。 例 10.23设一个函数 process,在调用它的时候,每次实 现不同的功能。输入 a和 b两个数,第一调用 process时找 出 a和 b中大者,第二次找出其中小者,第三次求 a与 b之 和 10.6 返回指针值的函数 一个函数可以返回一个整型值、字符值、实型值等,也可以 返回指针型的数据,即地址。其概念与以前类似,只是返回的值 的类型是指针类型而已。 这种返回指针值的函数,一般定义形式为 类型名 * 函数名 (参数表列 ); 例 10.24有若干个学生的成绩 (每个学生有 4门课程 ),要求在用户 输入学生序号后,能输出该学生的全部成绩。用指针函数来实现 例 10.25对上例中的学生,找出其中不及格课程的学生及其学生 号 10.7 指针数组和指向指针的指针 10.7.1 指针数组的概念 一个数组,若其元素均为指针类型数据,称为指针 数组,也就是说,指针数组中的每一个元素都相当于一 个指针变量。一维指针数组的定义形式为 类型名 * 数组名 数组长度 ; 例如: int * p4; 例 10.26将若干字符串按字母顺序输出 10.7.2 指向指针的指针 在掌握了指针数组的概念的基础上,下面介绍指向 指针数据的指针变量,简称为指向指针的指针。 例 10.27使用指向指针的指针 例 10.28指针数组的元素指向整型数据 10.7.3 指针数组作 main函数的形参 指针数组的一个重要应用是作为 main函数的形参。 在以往的程序中, main函数的第一行一般写成以下形式: void main() 括号中是空的。实际上, main函数可以有参数,例 如: void main(int argc, char * argv) 10.8 有关指针的数据类型和指针运算的小结 10.8.1 有关指针的数据类型的小结 定义 含义 int i; 定义整型变量 i int * p; p为指向整型数据的指针变量 int an; 定义整型数组 a,它有 n个元素 int * pn; 定义指针数组 p,它由 n个指向整型数据的指针元素组成 int (*p)n; p为指向含 n个元素的一维数组的指针变量 int f(); f为返回整型函数值的函数 int * p(); p为返回一个指针的函数,该指针指向整型数据 int (*p)(); p为指向函数的指针,该函数返回一个整型值 int * p; p是一个指针变量,它指向一个指向整型数据的指针变量 10.8.2 指针运算小结 (1)指针变量加 (减 )一个整数 (2)指针变量赋值 (3)指针变量可以有空值,即该指针变量不指向任何变量 (4)两个指针变量可以相减 (5)两个指针变量比较 10.8.3 void指针类型 ANSI新标准增加了一个“ void”指针变量,即可定义 一个指针变量,但不指定它是指向哪一种类型数据的。 ANSI C标准规定用动态存储分配函数时返回 void指针, 它可以用来指向一个抽象的类型的数据,在将它的值赋 给另一指针变量时要进行强制类型转换使之适合于被赋 值的变量的类型。 小结 在本章中介绍了指针的基本概念和初步应用。应该说明,指 针是 C语言中重要的概念,是 C的一个特色。使用指针的优点 : (1) 提高程序效率; (2)在调用函数时变量改变了的值能够为主调函数 使用,即可以从函数调用得到多个可改变的值; (3)可以动态存储 分配。 但是同时应该看到,指针使用实在太灵活,对熟练的程序员 来说,可以利用它编写出颇有特色的、质量优良的程序,实现许 多用其他高级语言难以实现的功能,但也十分容易出错,而且这 种错误往往比较隐蔽。由于指针运用的错误可能会使整个程序遭 受破坏,比如由于未对指针变量 p赋值就向 *p赋值,就可能破坏 了有用的单元的内容。有人说指针是有利有弊的工具,如果使用 指针不当,会出现隐蔽的、难以发现和排除的故障。因此,使用 指针要十分小心谨慎,要多上机调试程序,以弄清一些细节,并 积累经验。 此课件下载可自行编辑修改,供参考! 感谢您的支持,我们努力做得更好!
展开阅读全文