《补充内容:C语言指针详解-精品文档资料整理.ppt》由会员分享,可在线阅读,更多相关《补充内容:C语言指针详解-精品文档资料整理.ppt(50页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 指针指针本章主要内容:本章主要内容:1.指针的基本概念指针的基本概念2.各种类型的指针:各种类型的指针:数组的指针、字符串的指针、数组的指针、字符串的指针、函数的指针、指针的指针等函数的指针、指针的指针等指针的优点:指针的优点:(1)可有效地表示复杂的数据结构;)可有效地表示复杂的数据结构;(2)动态分配内存;)动态分配内存;(3)方便地使用字符串,数组;)方便地使用字符串,数组;(4)直接处理内存地址等。)直接处理内存地址等。指针的缺点:指针的缺点:概念繁杂,使用时较灵活,不易掌握。概念繁杂,使用时较灵活,不易掌握。7.1 地址和指针的概念地址和指针的概念 在计算机中,在计算机中,所有的数
2、据都是存放在存储器中的所有的数据都是存放在存储器中的。一般把一般把存储器中的一个字节存储器中的一个字节称为称为一个内存单元一个内存单元,不不同的数据类型所占用的内存单元数不等同的数据类型所占用的内存单元数不等,如整型量,如整型量占占2个单元,字符量占个单元,字符量占1个单元等。个单元等。为了正确地访问这些内存单元,为了正确地访问这些内存单元,必须为每个内存单必须为每个内存单元编上号。元编上号。根据一个内存单元的编号即可准确地找根据一个内存单元的编号即可准确地找到该内存单元。到该内存单元。内存单元的编号也叫做地址内存单元的编号也叫做地址。既然既然根据内存单元的编号或地址就可以找到所需的内存根据内
3、存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个单元,所以通常也把这个地址称为指针地址称为指针。变量与地址变量与地址程序中程序中:short i;float k;内存中每个字节有一个编号内存中每个字节有一个编号-地址地址.2000200120022005内存内存02003ik变量是一块存储空间变量的地址就是指针7.1 地址和指针的概念地址和指针的概念 一、关于内存一、关于内存内存单元的内存单元的指针指针和内存单元的和内存单元的内容内容是是两个不同的两个不同的概念概念。对于一个内存单元来说,单元的地址即为指针,对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。
4、其中存放的数据才是该单元的内容。在语言中,在语言中,允许用一个变量来存放指针,这种允许用一个变量来存放指针,这种变量称为指针变量。因此,变量称为指针变量。因此,一个一个指针变量指针变量的值就的值就是某个内存单元的是某个内存单元的地址地址或称为某内存单元的或称为某内存单元的指针指针。二、关于变量的访问二、关于变量的访问 1.直接访问:根据变量名直接访问变量。直接访问:根据变量名直接访问变量。int i;i=3;printf(%d,i);2.间接访问:将变量的地址存放于另一变量间接访问:将变量的地址存放于另一变量问题问题:如何获得一个变量的地址如何获得一个变量的地址?如何保存一个变量的地址如何保存
5、一个变量的地址?如何获得一个变量的地址如何获得一个变量的地址?&取地址运算符。取地址运算符。int a;则则&a获得获得变量的地址变量的地址如何保存一个变量的地址如何保存一个变量的地址?将变量的地址放在另一个将变量的地址放在另一个(变量)(变量)中中三、若干术语三、若干术语 1.指针指针:一个变量的地址,称为该变量的指针。:一个变量的地址,称为该变量的指针。2.指针变量指针变量:专门用来存放另一变量的地址(指:专门用来存放另一变量的地址(指 针)的变量,称为指针变量。针)的变量,称为指针变量。3.指向指向:指针变量:指针变量指向指向变量。变量。a&aptpt指向指向a7.2 变量的指针和指向变
6、量的指针变量变量的指针和指向变量的指针变量一、指针变量的定义一、指针变量的定义一般形式:一般形式:类型标识符类型标识符 *标识符;标识符;例如:例如:float*pf;int*p1,*p2;说明:说明:(1)定义时,标识符前面的定义时,标识符前面的*表示该变量为指针变量,上例中表示该变量为指针变量,上例中 变量名为变量名为p1,p2。(2)类型标识符指出类型标识符指出p1、p2所指向的变量的类型。所指向的变量的类型。二、指针变量的引用二、指针变量的引用两个相关运算符:两个相关运算符:1&取地址运算符。取地址运算符。例例:int a,*pt;若若:pt=&a apt2*指针运算符指针运算符(间接
7、访问运算符间接访问运算符)*pt为指针变量为指针变量pt所指向的变量所指向的变量.*pt等价于等价于a *pt=10;相当于相当于a=10 pt指向指向a例:例:main()int a,b;int*pointer_1,*pointer_2;a=100;b=10;pointer_1=&a;pointer_2=&b;printf(%d,%dn,a,b);printf(%d,%dn,*pointer_1,*pointer_2);abpointer_1pointer_210010&a&b例:输入两个整数例:输入两个整数a,b,按大小顺序输出。,按大小顺序输出。main()int a,b,*p1,*p2
8、,*p;scanf(%d%d,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(a=%d,b=%d,a,b);printf(max=%d,min=%d,*p1,*p2);abp1p234&bp&a&a&b&a注意:注意:1、指针变量必须先赋值,再使用、指针变量必须先赋值,再使用,只能保存地址只能保存地址例如:例如:int*p,*p1,a=10;*p=20;printf(%d,*p1);3、&和和*运算符互为逆运算运算符互为逆运算若:若:int a=10,*pt=&a;则则:&a、pt、&*pt是等价的是等价的 则则:*&a、*pt、a 是等价的是等
9、价的2、一个指针变量只能指向同一类型的变量。、一个指针变量只能指向同一类型的变量。int a,*p;float f;p=&f;三、指针变量作为函数参数三、指针变量作为函数参数 实参实参形参:传去的是地址值,分占不同空间。形参:传去的是地址值,分占不同空间。1、指针变量作形参,在函数内部可以改变函数外部、指针变量作形参,在函数内部可以改变函数外部变量的值变量的值例:输入两个整数,从大到小输出。例:输入两个整数,从大到小输出。void swap(int*,int*);main()int a,b;int*p1,*p2;scanf(%d,%d,&a,&b);p1=&a;p2=&b;if(ab)swap
10、(p1,p2);printf(%d,%d,a,b);void swap(int*q1,int*q2)int q;q=*q1;*q1=*q2;*q2=q;abp1p2q1q2&a&b34&a&bq343 2、指针变量作形参,可以用来保存函数的返回值、指针变量作形参,可以用来保存函数的返回值 (输出型形参)(输出型形参)例:写一个函数,功能是求出一维整型数组中的最例:写一个函数,功能是求出一维整型数组中的最大值和最小值。大值和最小值。void maxmin(int a,int n,int*pmax,int*pmin)int i;*pmax=*pmin=a0;for(i=1;i*pmax)*pmax
11、=ai;if(ai*pmin)*pmin=ai;void main()int a10=0,9,-5,4,23,87,34,2,65,-45;int max,min;maxmin(a,10,&max,&min);printf(max=%d,min=%dn,max,min);课上练习课上练习看程序写结果:看程序写结果:void ast(int x,int y,int*cp,int*dp)*cp=x+y;*dp=x-y;void main()int a,b,c,d;a=4;b=3;ast(a,b,&c,&d);printf(%d,%dn,c,d);答案:答案:7,17.3 数组的指针和指向数组的指针
12、变量数组的指针和指向数组的指针变量一个变量有地址,一个数组包含若干元素,一个变量有地址,一个数组包含若干元素,每个每个数组元素数组元素都在内存中占用存储单元,都在内存中占用存储单元,它们都有它们都有相应的地址相应的地址。指针变量既然可以。指针变量既然可以指向变量,当然也可以指向数组元素(把指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。某一元素的地址放到一个指针变量中)。所谓所谓数组元素的指针数组元素的指针就是就是数组元素的地址数组元素的地址。一、指向数组元素的指针一、指向数组元素的指针1.定义:定义:int a10,*p;注意注意:如果数组为如果数组为int型,则指针
13、变量的基类型型,则指针变量的基类型 亦应为亦应为int型型。2.赋值:赋值:p=&a0;把把0元素的地址元素的地址赋给指针变量。赋给指针变量。也就是使指向也就是使指向数组的第号元素,数组的第号元素,如图如图:说明:说明:c语言规定数组名(语言规定数组名(不包括形参数组名不包括形参数组名),代表数),代表数组中首元素(下标为组中首元素(下标为0的元素)的地址。的元素)的地址。p=&a0;则:等价于则:等价于p=a;注意:注意:数组名数组名a不代表整个数组,上述不代表整个数组,上述p=a;的作用的作用是把是把a数组数组的首元素的地址赋给指针变量的首元素的地址赋给指针变量p,而,而不是把数组不是把数
14、组a各元素各元素的值赋给的值赋给p;在定义指针变量时可以对它赋予初值:在定义指针变量时可以对它赋予初值:int*p=&a0;或或int*p=a;等效于下面两行:等效于下面两行:int*p;p=&a0;或或 p=a;/*不是不是*p=&a0;*/习题集第七单元习题集第七单元 一、一、8,9,10,36二、通过指针引用数组元素二、通过指针引用数组元素 int a10,*p;若若p=a;则则*p=1 等价于等价于 a0=1 p+1含义是什么含义是什么?C中规定:若中规定:若p=&a0,则则p+1指向下一个元素,不是简单的指向下一个元素,不是简单的 加加1。a 0a 1a 2a 3a 9.pp+1p+
15、9 因此,如果因此,如果int a10,*p;p=a;则有以下关系:则有以下关系:(1)p+i a+i&ai。(2)*(p+i)*(a+i)ai。(3)指向数组元素的指针变量也可带下标:指向数组元素的指针变量也可带下标:pi *(p+i)。即有即有*(p+i)*(a+i)ai pi 例:输出数组中全部元素。例:输出数组中全部元素。(设设a数组,整型,数组,整型,10个元素个元素)(1)下标法下标法void main()int a10;int i;for(i=0;i10;i+)scanf(%d,&ai);printf(n);for(i=0;i10;i+)printf(%3d,ai);(2)用数组
16、名计算数组元素地址用数组名计算数组元素地址法法void main()int a10;int i;for(i=0;i10;i+)scanf(%d,a+i);printf(n);for(i=0;i10;i+)printf(%3d,*(a+i);(3)用指针变量法)用指针变量法1:main()int *p,i,a10;p=&a0;for(i=0;i10;i+)scanf(%d,p+i);printf(n);p=&a0;for(i=0;i10;i+)printf(%3d,*(p+i);/p=a;/p=a;用指针变量法用指针变量法2main()int *p,i,a10;p=a;for(i=0;i10;i
17、+)scanf(%d,p+);printf(n);for(p=a;p(a+10);p+)printf(%3d,*p);pa0a1a2a935-412p 在使用指针变量时应注意的几个问题:在使用指针变量时应注意的几个问题:1.数组名是数组的首地址,因此数组名是数组的首地址,因此 p=&a0 与与 p=a 等价等价。2指针变量可以实现使本身的值改变,数组名不可以。指针变量可以实现使本身的值改变,数组名不可以。例例:p+正确正确 a+不正确不正确 3要注意指针变量的当前值,指针变量可以指到数组后的内存要注意指针变量的当前值,指针变量可以指到数组后的内存单元。即单元。即指针变量的越界问题指针变量的越界
18、问题 4注意指针变量的运算,若先使注意指针变量的运算,若先使p指向数组指向数组a(即即p=a),则,则 (1)p+(或或p+=1)指向下一个元素。指向下一个元素。(2)*p+等价于等价于*(p+)先得到先得到p指向的变量的值,指向的变量的值,p再加再加1。(3)*(p+)与与*(+p)作用不同,前者先取作用不同,前者先取*p,后使,后使p加加1;后者相反。后者相反。(4)(*p)+表示表示p所指向的元素值加所指向的元素值加1。(5)若若p当前指向当前指向a数组第数组第i个元素,则:个元素,则:*(p-)相当于相当于ai-,先取,先取p值作值作*运算,再使运算,再使p自减;自减;*(+p)相当于
19、相当于a+i,先使,先使p自加,再作自加,再作*运算;运算;*(-p)相当于相当于a-i,先使,先使p自减,再作自减,再作*运算。运算。void main()int a10,b10,i;int*pa,*pb;pa=a;pb=b;for(i=0;i10;i+)scanf(%d,pb+);pb=b;/*必不可少,否则出现越界必不可少,否则出现越界*/for(i=0;i10;i+)*pa=*pb;pa+;pb+;pa=a;/*必不可少,否则出现越界必不可少,否则出现越界*/for(i=0;i10;i+)printf(%5d,*pa+);例例:编程实现把整型数组编程实现把整型数组b中的所有元素拷贝到数
20、组中的所有元素拷贝到数组a中。中。二、数组名作函数参数二、数组名作函数参数内容回顾:内容回顾:数组名做函数参数,当发生函数调用时实参传递给形参是什么?数组名做函数参数,当发生函数调用时实参传递给形参是什么?int sum(int arr,int n)int s=0,i;for(i=0;in;i+)s+=ai;return s;void main()int array5=1,2,3,4,5,i,s;s=sum(array,5);printf(sum=%dn,s);实参传递给形参是实参传递给形参是实参数组的首地址实参数组的首地址实际上,形参数组名就是一个实际上,形参数组名就是一个指针变量指针变量
21、int sum(int arr,int n)等价于等价于 int sum(int*arr,int n)a0a1a2a3a937911067542a4a5a6a7a8a a数组数组xp2X+mp1234759void inv(int*x,int n)例例7.7:将数组:将数组a中中n个整数按相反顺序存放。个整数按相反顺序存放。void inv(int x,int n)void inv(int*x,int n)int temp,*p1,*p2,m;m=n/2;p1=x;p2=x+n-1;for(;p1x+m;p1+,p2-)temp=*p1;*p1=*p2;*p2=temp;void main()
22、int a5=1,2,3,4,5;int i;inv(a,5);for(i=0;i5;i+)printf(%4d,ai);如果有一个实参数组,想在函数中改变此如果有一个实参数组,想在函数中改变此数组,实参与形参的对应关系有以下几类情况数组,实参与形参的对应关系有以下几类情况:形参实参数组名指针变量数组名指针变量数组名数组名指针变量指针变量例例7.9:用选择法对:用选择法对10个整数排序。个整数排序。void sort(int x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;jxk)k=j;if(k!=i)t=xi;xi=xk;xk=t;mai
23、n()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);p=a;sort(p,10);for(p=a,i=0;i10;i+)printf(%d,*p+);(1)形参用形参用数组名数组名,实参用实参用指针变量指针变量sort(a,10);也行也行(2)形参用形参用指针变量指针变量,实参用实参用数组名数组名void sort(int*x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;j*(x+k)k=j;if(k!=i)t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;main()int i,a1
24、0;for(i=0;i10;i+)scanf(%d,&ai);sort(a,10);for(i=0;i10;i+)printf(%3d,ai);指针变量与一维数组的关系指针变量与一维数组的关系intint *p *p 与与 intint q10 q10 数组名是数组名是指针指针(地址)(地址)常量常量p=q;p=q;p+ip+i 是是qiqi 的地址的地址数组元素的表示方法数组元素的表示方法:下标法下标法和和指针法指针法,即若即若p=q,p=q,则则 pipi qiqi *(*(p+ip+i)*(*(q+iq+i)形参数组形参数组实质上是实质上是指针变量指针变量,即即intint q q in
25、tint*q*q系统只给系统只给p p分配能保存一个指针值的内存区分配能保存一个指针值的内存区(一般一般4 4字字节);而给节);而给q q分配分配4*104*10字节的内存区字节的内存区1、使用指针访问二维数组方法一、使用指针访问二维数组方法一:指向指向数组元素数组元素的指针变量。的指针变量。例:用指针变量输出二维数组元素的值。例:用指针变量输出二维数组元素的值。main()int a23=2,3,6,7,8,5;int*p;p=&a00;for(i=0;i6;i+)printf(%3d,*p+);三、二维数组和指针三、二维数组和指针a00 5 8 7 6 3 2a01a02a10a11a1
26、2p例:用指针变量输出数组元素例:用指针变量输出数组元素aij的值。的值。main()int a23=2,3,6,7,8,5;int i,j,*p;p=&a00;scanf(%d%d,&i,&j);printf(%3d,*(p+i*3+j);其中其中3是二维数组的是二维数组的列数列数如果有如下定义如果有如下定义:int a45;int*p;p=&a00;问题问题:p+11是哪个数据元素的地址。是哪个数据元素的地址。答案:答案:&a21总结:总结:p+i是是&ai/5i%5其中其中5是二维数组的列数是二维数组的列数习题集第七单元习题集第七单元 二、二、4main()int a45=1,4,2,3
27、,7,6,9,10,8,-1,-2,-6,-4,4,2,7,6,9,11,14;int i,j;for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);sort(&a00,4*5);for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);例例:将一个二维数组将一个二维数组a45a45进行按行全排序进行按行全排序void sort(int*p,int n)int i,j,t,k;for(i=0;in-1;i+)k=i;for(j=i+1;j=n-1;j+)if(*(p+k)*(p+j)k=j;
28、if(k!=i)t=*(p+i);*(p+i)=*(p+k);*(p+k)=t;a00a01a02a03a04a10a11a12a13a14 .a32a33a34.sort(&a00,4*5);pint a34=6,9,0,16,8,-1,2,7,3,48,-5,12;aa+0a+1a+2a0a1a2690168-127348-512(1)二维数组的地址)二维数组的地址 P2422、使用指针访问二维数组方法二使用指针访问二维数组方法二:指向由指向由m个整数组成的一维数组的指针变量。个整数组成的一维数组的指针变量。a代表的是首行代表的是首行(即第即第0行行)的首地址的首地址a+1代表的是第代表的
29、是第1行的首地址行的首地址a+2代表的是第代表的是第2行的首地址行的首地址200020042016202020322036a00a01a10a11a20a21a02a03a12a13a22a23a0a1a2a数组数组a包含三个元素包含三个元素 a0,a1,a2数组名数组名a是首元素的地址是首元素的地址 a就是就是&a0;a0,a1,a2是是一维数组名一维数组名,C语言又规定了数组名代表数组首语言又规定了数组名代表数组首元素地址,因此,元素地址,因此,a0代表一维数组代表一维数组a0中第中第0列列元素的地址,即元素的地址,即&a00a1代表一维数组代表一维数组a1中第中第0列列元素的地址,即元素
30、的地址,即&a10a2代表一维数组代表一维数组a2中第中第0列列元素的地址,即元素的地址,即&a201)a+i&ai 第第i行的地址行的地址 *(a+i)ai 是是ai元素元素3)ai+j&aij aij的地址的地址 即即:*(a+i)+j&aij4)aij元素可以表示为:元素可以表示为:*(ai+j)*(*(a+i)+j)aij2)ai元素元素本身又是一个本身又是一个一维数组一维数组,ai相当于一相当于一维数组名维数组名,即,即ai中保存一个地址,是中保存一个地址,是ai0的的地址,即地址,即&ai03)ai&ai0(2)指向指向由由m个整数组成的一维数组个整数组成的一维数组的指针变量的指针
31、变量填空:填空:int a34;_ p=a;答案:答案:int*p;正确答案:正确答案:int (*p)4;p称为指向一维数组的指针称为指向一维数组的指针是指向由是指向由4个整数组成的一维数个整数组成的一维数组的指针。组的指针。p是是a0的地址的地址是二维数组是二维数组a中第中第0行的地址行的地址习题集第七单元习题集第七单元 一、一、6,23例:输出二维数组任一行任一列的元素的值。例:输出二维数组任一行任一列的元素的值。main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;int(*p)4;int i,j;p=a;scanf(i=%d,j=%d,&i,&j)
32、;printf(a%d,%d=%dn,i,j,*(*(p+i)+j);(3)多维数组的指针作函数参数。多维数组的指针作函数参数。例例:求二维数组求二维数组a45a45每列最大值每列最大值a+0a+1a+2a+3b 2 12 3 27 -4 3 7 33 2 5 1 6 12 3 15 4 8 10 9 14 2 12 3 27 -43 4123327515 void colum_max(int(*a)5,int*b)int i,j;for(j=0;j5;j+)*(b+j)=*(*(a+0)+j);/*a0j*/for(i=1;i4;i+)if(*(b+j)*(*(a+i)+j)*(b+j)=*(*(a+i)+j);main()int a45,b5;int i,j;for(i=0;i4;i+)for(j=0;j5;j+)scanf(%d,&aij);colum_max(a,b);for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);for(j=0;j5;j+)printf(%4d,bj);printf(n);打印原二维数组打印原二维数组打印每列最大值打印每列最大值