c语言程序设计 指针 .ppt,C语言程序设计 指针.ppt

253b171540df25e1b84436cbe50dfc72.gifC语言程序设计 指针.ppt

第6章 指 针,C 语言程序设计,北京科技大学 计算机系,2018/8/156.1 概述6.2 指针和指针变量6.3 指针与数组6.4 指针和函数6.5 动态存储分配,第6章 指针,2018/8/15,6.1概述,为什么要引入指针的概念 指针可以有效地表示复杂数据结构,如队列、栈、链表等。 指针能象汇编语言一样处理内存地址,为动态内存分配提供支持。 指针可实现对数组和字符串的方便使用,提高某些子程序的效率。,6.1概述,关于指针的原则 学习原则 一定要学会 其实通常的应用很简单 使用原则 永远要清楚每个指针指向了哪里 永远要清楚指针的指向位置是什么,2018/8/15,2018/8/15,main int a5;int b;float x3.5;,变量的两个物理意义,变量的内容,变量的地址,6.2 指针和指针变量535.0,变量的内容,变量的内容,变量的地址,变量的地址,6.2.1 基本概念,变量的地址和变量的内容,变量的地址 变量所分配存储空间的首地址 变量的内容 变量在所分配的存储空间中存放的数据,2018/8/15,2018/8/15,main int a,b;float x35;a5;ba3;,1001 1002 1003 1004 1015 1016 1017 1018,ab利用变量名存取数据的方式称为“直接存取”方式。,直接存取和间接存取,8,2018/8/15,C 语言还提供了对内存单元的“间接存取”方式,5,1001,3,main int a5,b3,*p;p ,变量的地址称为变量的指针 存放地址的变量称为指针变量 p指向c,c为p所指向的目标变量。,直接存取和间接存取,8,指针的类型和指针所指向的类型,int a5,b; float x; int *pi; float *pf;pi指针的类型int * pf指针的类型float * pi所指向的类型int pf所指向的类型float,2018/8/15,2018/8/15,void main float x, *p1NULL;float *p2 ,2000,6.2 指针和指针变量,6.2.2 指针变量的定义,NULL,指针变量初始化,数据类型 * 指针变量名,2012,2020,6.2 指针和指针变量,说明 当把一个变量的地址作为初值赋给指针时,该变量必须先给以定义,且该变量的数据类型必须与指针的数据类型一致 也可把一个已初始化的指针值作为初值赋予另一指针 也可通过初始化定义某种类型的空指针,2018/8/15,6.2.2 指针变量的定义,2018/8/15,6.2 指针和指针变量,取地址运算,间接存取运算* *指针变量或目标变量的地址 int i, *p; p ,6.2.3 指针的基本运算,pa指针变量 *pa指针pa的目标变量 ,p,b2000;,判断正确,指针变量只 存放地址,一个指针变量不能指向与其类型不同的变量,应在类型相同的指针变量之间赋值,这是正确的,设 int *c, a20, *b,不能给指针赋非地址值,2018/8/15,方法1目标变量值不变,改变指针变量的 指向求解。 void main int a,b,*p1,*p2,*p;p1,【例6.1】输入a、b两个整数, 使用指针变量按大小顺序输出 这两个整数。6 8 a6,b8 max8,min66.2.3 指针的基本运算续,2018/8/15,方法2利用指针变量直接改变目标变量的值。 void main int a,b,t,*p1,*p2;p1 ,6 8 a8,b6 max8,min66,6.2.3 指针的基本运算,2018/8/15,指针的算术运算,6.2.3 指针的基本运算,void main int a10,20,30,40,50,60,70,80,90,100;int i,*ptr,*p1,*p2;ptra; for i0;i10;i *ptr; ptr; p1p2a; p15; p2;printfaun”,a;printf“p1u,*p1dn,p1,*p1;printf“p2u,*p2dn”,p2,*p2;printfp1-p2dn”,p1-p2; printf“*p12d,*p12dn”,*p12,*p12; ,指针加减运算要点 两个指针变量不能做加法运算。 只有当指针变量指向数组时,并且只有当运算结果仍指向同一数组中的元素时,指针的加减运算才有意义。 指针加减运算的结果不以字节为单位,而是以数据类型的大小(即sizeof类型)为单位。 只有当两个指针变量指向同一数组时,进行指针相减才有实际意义。 *p1n与*p1n是两个不同的概念。,ptr,31,21,11,41,51,61,71,81,91,1012018/8/15,指针的关系运算, 指向同一数组的两个指针可以进行关系运算 指针与一个整型数据比较是没有意义的,不同类型指针变量之间的比较是非法的。 NULL可以与任何类型指针进行、的运算,用于判断指针是否为空指针。,6.2.3 指针的基本运算,6.2 指针与指针变量,2018/8/15,6.2.4 指针作为函数参数,【例6.3】从键盘任意输入两个整数,编程将其交换后再重新输出。,2018/8/15void swapint *p1,int *p2 int temp;printf“调用中交换前 *p1d,*p2dn”,*p1,*p2;temp*p1;*p1*p2;*p2 temp;printf“调用中交换后*p1d,*p2dn”,*p1,*p2; ,void main int x1, x2;scanf“dd”, void swapint x,int y int temp;printf“调用中交换前 xd,ydn”,x,y;temp x;x y;y temp;printf“调用中交换后xd,ydn”,x,y; ,void main int x1, x2;scanf“dd”, ,方法 1,方法 2,编写函数实现两数的互换,Not WorkWhy,20 10 1 x120,x210 调用中交换前x20,y10 调用中交换后x10,y20 2 x120,x210,20 10 1 x120,x210 调用中交换前*p120,*p210 调用中交换后*p110,*p220 2 x110,x220,2018/8/15,主调函数,被调函数,void main int x1,x2;scanf“dd”, ,void swapint x, int y int temp;printf“调用中交换前xd,ydn”,x,y;tempx; xy; ytemp;printf“调用中交换后xd,ydn“,x,y; ,20,20,x1,x2,实 参,形 参,10,10,方法 1,x,y,2018/8/15,主调函数,被调函数,main int x1,x2;scanf“dd”, ,void swapint *p1, int *p2 int temp;printf“调用中交换前*p1d,*p2dn“,*p1,*p2;temp*p1; *p1*p2; *p2temp;printf“调用中交换后*p1d,*p2dn“,*p1,*p2; ,printf“调用中交换前*p1d,*p2dn“,*p1,*p2;pp1; p1p2; p2p; printf“调用中交换后*p1d,*p2dn“,*p1,*p2; ,void main int x1,x2;scanf“dd”, ,方法 3,编写函数实现两数的互换10 1 x120,x210 调用中交换前*p120,*p210 调用中交换后*p110,*p220 2 x120,x210,Not Work tooWhy,2018/8/15,主调函数,被调函数,main int x1,x2;scanf“dd”, ,void swapint *p1,int *p2 int *p;printf“调用中交换前 *p1d,*p2dn”,*p1,*p2;pp1; p1p2; p2p;printf“调用中交换后*p1d,*p2dn“,*p1,*p2; ,,a0,a4,a,2018/8/15,用p表示数组元素下标法 p0,p1, ,p9 指针法*p0,*p1, ,*p92. 通过指针引用数组元素,例如int a10,*p;p a;或 p ,a,6.3.1 指针与一维数组,2018/8/15,【例6.4】用指针变量引用数组元素,完成给数组元素赋值并输出数组元素。 include void main int *p,b5,i;pb; /* 建立指针和数组关联 */for i0;i5;i*pi;pb; /* 注意要把指针重新指向数组首地址 */for i0;i5;iprintf“bddt“,i,*p;printf“n“; ,6.3.1 指针与一维数组续,运行结果 b00 b11 b22 b33 b44,6.3.1 指针与一维数组(续),使用指针法访问数组元素需注意几个问题 作为数组名的指针常量值不可改变,而指针是地址变量,其值可以改变。 利用指针变量访问数组元素,要考虑数组越界问题。 在数组元素的下标表示法中如果采用指针变量,其下标可以出现负值。 在指针变量运算中需要特别注意单目运算符的右结合性。,2018/8/15,6.3.1 指针与一维数组2018/8/15,3. 数组名与函数参数,【例6.5】从键盘输入5个整数,找出其中的最大数(用函数实现),并输出。include define N 10 int max1int p , int n /*形参为数组名*/ int i,max;maxp0;fori1; in; i /* 求最大值 */ifmaxpi maxpi;returnmax; /* 返回最大值 */ int max2int *p, int n /* 形参为指针 */ int i,max,*q;qp; max*q;for; qpn;q /* 求最大值 */ifmax*q max*q;returnmax; /* 返回最大值 */ ,2018/8/15void main int i,aN;int max; /* mean 函数定义在前,可不予声明 */fori0; iN; i /* 输入数组 */scanf“d“, /* 输出结果 */ ,2018/8/15,运行情况 12 45 56 23 89 75 64 62 31 10 Max89,6.3.1 指针与一维数组2018/8/15,3. 数组名与函数参数,【例6.6】求已知数组中的最小值元素,并将它和该数组最前面的元素交换。int minint a , int n int i,m0; fori1;iai mi; /* 记下比am小的元素下标 */return m; /* 返回最小值元素下标值*/ void swapint *a, int m int i,t; tam; /* t暂存最小值元素值 */am a0; a0t; /* 最小值元素放最前面 */ ,2018/8/15include define N 10 int minint a , int n; void swapint *a, int m; void main int i,aN,m;fori0; iN;i /* 输入数组元素值 */scanf“d“, ,2018/8/15,运行情况如下 5 12 4 1 45 8 89 62 54 1 5 12 4 55 45 8 89 62 54,6.3.1 指针与一维数组,2018/8/15,3. 数组名与函数参数,【例6.7】使用选择排序法对10个整数从大到小排序。,*xi指向定位位置,*xk指向当前最小值,*xj将顺序指向参加比较的元素,最小值不在定位位置include void sortint *x,int n /* 定义选择排序法的函数 */ int i,j,k,t;for i0;i*xk kj;ifki t*xi; *xi*xk;*xkt; void main int i,*p,a103,7,9,11,0,6,7,5,4,2;pa; /* 指针p与数组a关联 */sortp,10; /* 调用sort函数,传递数组地址 */whilepa10 /* 输出排序后的数组元素值 */printf“d “,*p;printf“n“; ,2018/8/15,运行情况如下 11 9 7 7 6 5 4 3 2 0,2018/8/15, 二维数组的地址例如int a34; 二维数组名a是数组的首地址。 二维数组a包含三个行元素a0、a1、a2a0、a1、a2是一维数组名,也是一维数组的首地址。 a0指向a0 a1指向a1,a2指向a2 所以*a0a0 、*a1a1、*a2a2 所以*a0、a0、*a1、a1、*a2、a2都是列地址。,6.3.2 指针与二维数组,2018/8/15, 二维数组元素的地址,aij的地址可以用以下3种方式表示int *p,i,j;pa0;for i0;i3;i forj0;j4;j /*指针表示法输出元素aij */printf“4d“,**aij; printf“n“; printf“n“; for i0;i3;i forj0;j4;j /* 行数组表示法输出元素 aij */printf“4d“,*aij; printf“n“; ,6.3.2 指针与二维数组,例6.8输出二维数组元素。printf“n“; for i0;i3;i forj0;j4;j /*列数组表示法输出元素aij */printf“4d“,*aij; printf“n“; printf“n“; for i0;i3;i forj0;j4;j /* 指针直接表示法输出元素aij */printf“4d“,*p; printf“n“; ,2018/8/15,运行情况如下 1 2 3 4 12 13 14 21 22 23 242 3 4 12 13 14 21 22 23 242 3 4 12 13 14 21 22 23 242 3 4 12 13 14 21 22 23 24,2018/8/15,6.3 指针与数组,6.3.3 指向字符串的指针变量,1. 用字符指针指向字符串,字符串的两种表示方式字符数组表示方式,字符串存放在一维数组中,引用时用数组名。字符指针变量表示方式,字符指针变量存放字符串的首地址,引用时用指针变量名。,6.3.3 指向字符串的指针变量,对字符指针变量的赋值形式 在定义字符指针时直接赋值,例如char *cp“C Language“; 在定义字符指针后赋值,例如char *cp;cp“ C Language“; 将字符数组首地址赋值给字符指针,使该字符指针指向该字符串的首地址,例如char str“C Language“, *cp;cpstr;,2018/8/15,2018/8/15include void main char s20;char *cp;int k;cps; /* cp指向s数组的首地址 */printf“Please character string n“;getss;fork0;*cpk0;k*cpk3; /* 把ASCII码值加3*/printf“sn“,cp;,运行情况如下 Please character string language odqjxdjh,【例6.9】简单的字符串加密就是将原字符所对应的ASCII码值加或减一个整数,形成一个新的字符。,6.3.3 指向字符串的指针变量,2018/8/15,2. 用字符串指针处理字符串,【例6.10】在输入的字符串中查找有无u字符。,include void main char *cp,ps20;printf“Please a string“;scanf“s“,ps; /* 输入字符串 */cpps; /* 循环前让cp指向字符串 */while *cp0 /* 当cp未移向串尾且未找到时继续循环查找 */ if *cpu printf“The character c is d-thn“,u, cp-ps1; /* 位置从1算起 */break;cp; /* 顺序移动指针cp */if *cp0 /* 循环结束后如未找到,此时cp应指向字符串尾标志0 */printf“The character c is not foundn“, u ;,第一次运行情况Please a stringLanguage The character u is 5-th,第二次运行情况 Enter a character program The character u is not found,6.3.3 指向字符串的指针变量,2018/8/15,2. 用字符串指针处理字符串,【例6.11】将字符串逆序排列后输出。,include include void main char str80,*p,*q, t;printf“Enter a string“;scanf“s“,str; /* 输入要处理的字符串 */forpstr,qpstrlenstr-1;pq;p,q /* 双向移动指针并交换相应元素 */ t*p;*p*q;*qt; printf“The reversed string is sn“,str; /* 输出逆序后的字符串 */,运行情况 Enter a string language The reversed string is egaugnal,6.3.3 指向字符串的指针变量,2018/8/15,3. 字符指针作为函数参数,【例6.12】形参用字符指针实现字符串间的拷贝。,include void strcopy char *s1, char *s2 ; void main char *str1“C program“, str220;strcopystr1,str2; /* 分别以字符指针和字符数组名为实参 */printf“The first stringis sn“,str2;strcopy“FORTRAN language“,str2;/* 分别以串常量为实参和数组名为实参 */printf“The second string is sn“,str2; void strcopy char *s1, char *s2 /* 自定义求字符串拷贝函数strcopy */ for;*s10;s1,s2*s2*s1;*s20;,运行情况 The first string is C program The second string is FORTRAN language,2018/8/15,指针数组定义的一般形式数据类型 *指针数组名元素个数;在这个定义中由于“ ”比“*”的优先级高,所以数组名先与“元素个数”结合,形成数组的定义形式,“*”表示数组中每个元素是指针类型,“数据类型标识符”说明指针的目标变量的数据类型。例如int *p3;char *cp5;,6.3 指针与数组,6.3.4 指针数组,1. 指针数组的概念,指针数组就是数组中的每个元素均为 指针类型,2018/8/15,6.3.4 指针数组,2. 指针数组初始化,例如 char c8“Fortran“,“COBOL“,“BASIC“,“Pascal“; char *cp4c0,c1,c2,c3; int a, b, c, x23; int *ip3,6.3.4 指针数组,include void main int a331,2,3,4,5,6,7,8,9,*pa3,i,j;fori0;i3;ipaiai; /* 让指针数组元素分别指向三个一维数组 */fori0;i3;i /* 按行输出二维数组元素 */ forj0;j3;jprintf“addd “,i,j,*paij;printf“n“;,2018/8/15,【例6.13】指针数组与二维数组之间的关系。,运行情况如下 a001 a012 a023 a104 a115 a126 a207 a218 a229,2018/8/15,void main int i,flag;char *p5 “C language“,“Basic“,“Pascal“,“ Visual C“,“FORTRAN“; char str20;printf“Enter a string“; /* 输入要查找的字符串 */getsstr;fori0;i5;i /* 逐个查找 */if strcmppi,str0 /* 若找到则令flag-1,退出循环 */ flag-1; break; if flag-1 /* 找到后flag应为-1*/printf“s is founded.n“,str;else printf“s is not founded.n“,str; ,3. 字符指针数组和多个字符串的处理,利用字符指针数组处理长度不等的字符串, 可节省存储空间。,6.3.4 指针数组,【例6.14】从键盘输入一个字符串,查找该字符串是否在已存在的字符串数组中。,第一次运行情况如下 Enter a string Visual c Visual c is not founded.,第二次运行情况如下 Enter a name FORTRAN FORTRAN is founded.,2018/8/15,include /* strcmp 库函数的要求 */ char *maxstrchar *ps ,int n/* 定义字符指针型函数maxstr ,形参ps是字符型指针数组*/ char *max;int i;maxps0;fori1;in;i /* 使max指向最大字符串 */if strcmpmax,psi0 maxpsi;return max; /* 返回指针max值 */,3. 字符指针数组和多个字符串的处理,6.3.4 指针数组,【例6.15】编写从多个字符串中找出最大字符串的函数。,2018/8/15,如果一个指针的目标变量是一个指针类型变量,则此指针为指向指针的指针变量,也称为多级指针变量。,二级指针变量定义的一般形式数据类型 指针变量名;“数据类型”是最终目标变量的类型。例如int a, *pa, ppa;,6.3 指针与数组,6.3.5 多级指针,1. 二级指针变量的定义,如果指针变量中保存的是另一个指针变量的地址,这样的指针变量就称为指向指针的指针 多级指针 实质就是多级间接寻址(Multiple Indirection),2018/8/15,6.3 指针与数组,6.3.5 多级指针,2. 二级指针变量初始化,例如int a, *pa, ppa;char *pname3, ppnamepname;,、*pa,、ppa,、*ppa,2018/8/15,6.3 指针与数组,6.3.5 多级指针,include void main float x6.6;float pp,*p;p,【例6.16】二级指针的应用。,运行情况如下 X 6.60 6.60 6.60,2018/8/15,6.4 指针与函数,6.4.1 指针型函数,1. 指针型函数定义形式,指针型函数定义的一般形式函数数据类型 *函数名(形式参数表) 其中函数名前的“*”表示函数的返回值是一个指针类型,“函数数据类型”是指针所指向的目标变量的类型。,如果一个函数的返回值是指针,则称此函数为指针型函数。,2018/8/15,6.4.1 指针型函数,【例6.17】运用指针型函数来找出两个数中的最大值。,include int *max int *i , int *j /* 定义指针型函数,其形参为两个指针变量 */ if *i*j return i ;else return j ; void main int a,b,*p;printf“Enter two integer numbers“;scanf“dd“, ,运行情况如下 Enter two integer numbers12 2 max12,2018/8/15,2. 指针型函数定义时应注意的问题, 指针函数中return的返回值必须是与函数类型一致的指针。 返回值必须是外部或静态存储类别的变量指针或数组指针,以保证主调函数能正确使用数据。,6.4.1 指针型函数,6.4 指针和函数,函数指针的定义形式数据类型 * 函数指针变量名; 其中“*函数指针变量名”必须用圆括号括起来。在定义中“*函数指针变量名”右侧的括号“ ”表示指针变量所指向的目标是一个函数,不能省略;“数据类型”用于定义指针变量所指向的函数的类型。,2018/8/15,6.4.2 用函数指针调用函数,1. 函数指针的定义和赋值,int *pf ; /* 定义int型函数指针pf */int funint x ; /* 声明int型函数fun */pffun; /* 给函数指针pf赋值,使pf指向指针型函数fun */,6.4 指针和函数,函数指针的定义形式数据类型 * 函数指针变量名; 其中“*函数指针变量名”必须用圆括号括起来。在定义中“*函数指针变量名”右侧的括号“ ”表示指针变量所指向的目标是一个函数,不能省略;“数据类型”用于定义指针变量所指向的函数的类型。,2018/8/15,6.4.2 用函数指针调用函数,1. 函数指针的定义和赋值,int *pf ; /* 定义int型函数指针pf */int funint x ; /* 声明int型函数fun */pffun; /* 给函数指针pf赋值,使pf指向指针型函数fun */,6.4.2 用函数指针调用函数,说明 通过改变指针变量的内容,一个指针变量可以先后指向同类型的不同函数,实现对不同函数的调用。 和数据指针一样,程序中不能使用指向不定的函数指针。 在给函数指针赋值时,只须给出函数名而不必给出参数,2018/8/15,1. 函数指针的定义和赋值,6.4.2 用函数指针调用函数,用函数指针变量调用函数的一般形式为(* 函数指针变量名)(实参表); 其中“*函数指针变量名”必须用圆括号括起来,表示间接调用指针变量所指向的函数;右侧括号中为传递到被调用函数的实参。,2018/8/15,2. 函数指针的使用,例如,若有函数int f1int x,int y 和int f2char ch,则int *fs ;fsf1; /* fs指向函数f1 */x*fsa,b; /* 相当于xf1a,b; */fsf2; /* 改变fs内容,使fs指向函数f2 */y*fsstr; /* 相当于yf2str; */,6.4.2 用函数指针调用函数,运用函数指针变量调用函数时应注意的问题 函数指针变量中应存有被调函数的首地址; 调用时“*函数指针变量名”必须用圆括号括起来,表示对函数指针做间接存取运算。它的作用等价于用函数名调用函数,此外实参表也应与函数的形参表一一对应。,2018/8/15,2. 函数指针的使用,6.4.2 用函数指针调用函数,include void main int arr_addint arr,int n;int a341,3,5,7,9,11,13,15,17,19,21,23;int *p,total1,total2;int *pt ; /*定义一个指向函数的指针*/ptarr_add; pa0;total1arr_addp,12; /*用原函数名调用函数*/total2*ptp,12; /*用指向函数的指针调用函数,将函数入口地址赋给指针*/printf“totaldntotal2dn“,total1,total2; ,2018/8/15,2. 函数指针的使用,【例6.18】用指向函数的指针调用函数以求二维数组中全部元素之和。,arr_addint arr ,int n int i,sum0;fori0;in;isumsumarri;returnsum; ,运行情况如下 total1144 total2144,6.4.2 用函数指针调用函数,用函数指针变量调用函数的一般形式为(* 函数指针变量名)(实参表); 其中“*函数指针变量名”必须用圆括号括起来,表示间接调用指针变量所指向的函数;右侧括号中为传递到被调用函数的实参。,2018/8/15,2. 函数指针的使用,6.4 指针和函数,2018/8/15,6.4.3 用指向函数的指针作函数参数【例6.19】写一程序,如输入1,程序就求数组元素的最大值,输入2就求数组元素的最小值,输入3就求数组元素值之和。void processint *x,int n,int *fun /* 形参fun为函数指针 */ int result;result*funx,n; /* 以函数指针fun实现同类型相关函数的调用 */printf“dn“,result; arr_maxint x ,int n int maxx0,k;fork1;kn;kif maxxk maxxk;return max;,

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值