第6章 指针(加动画16:9)_第1页
第6章 指针(加动画16:9)_第2页
第6章 指针(加动画16:9)_第3页
第6章 指针(加动画16:9)_第4页
第6章 指针(加动画16:9)_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

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

文档简介

第6章指针6.3指针变量的运算6.4指针和数组的关系6.5指针在函数中的应用6.6程序案例本章小结目录6.1地址和指针的关系6.2指针的定义和赋值6.1地址和指针的关系计算机中的所有数据都是顺序存放在存储器中的。一般把存储器中的一个字节称为一个内存单元(亦称存储单元),不同数据类型的值所占用的内存单元数亦不同。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址,通常也把这个地址称为指针。6.1地址和指针的关系与指针相关的一些概念(1)存储地址:计算机中数据都存放于从某个特定的地址开始的一个或若干个存储单元中,这个特定的地址即为该数据的存储地址,程序中通过变量名与这个存储地址进行对应。(2)指针变量:是用于存储数据地址的变量,由于地址指明了数据存储的位置,因此指针变量被形象地称为“指针”,该地址中存放的数据也被形象地称为“指针所指向的数据”,如图6-1所示。6.1地址和指针的关系(3)直接访问:指对数据的存取操作通过变量名进行,而没有通过地址进行操作。(4)间接访问:指通过使用指针而不使用变量名访问指针所指向的数据。(5)指针的类型:指针的类型就是指针所指向的数据的类型。例如,有一个整型指针,它所指向的变量就必须是整型变量。(6)指针的长度:是指针变量所占的内存字节数。若地址值是16位,则指针变量的长度是2;若地址值是32位的,则指针变量的长度就是4。6.2指针的定义和赋值指针变量的定义格式如下:指针变量的定义并初始化格式如下:说明:数据类型可以是任意类型,是指针所指向的变量的类型。“*”是一个说明符,用来说明其后的变量是一个指针变量。数据类型*指针变量名;数据类型*指针变量名=&变量名;6.2.1指针变量的定义及初始化6.2指针的定义和赋值没有指向的指针变量的值是随机的。只有被赋值以后,指针变量才有确定的指向,没有初始化的指针变量必须在使用之前进行赋值操作,使其有所指向。例如:inta=5;/*定义了一个整型变量a,a中存储的值是5*/int*p;/*定义一个指向整型变量的指针p,但p没指向任何变量*/int*q=&a;/*定义一个指向整型变量的指针q,并将它指向变量a*/6.2.1指针变量的定义及初始化6.2指针的定义和赋值一个指针变量除了在定义的同时被赋值(初始化)外,也可以在定义后通过不同的“渠道”获得一个确定的地址值,从而指向一个具体的对象。(1)通过取地址运算符“&”获得一个变量的地址值。先定义指针变量,然后通过赋值语句给指针一个初值,例如:

intk,*q;/*定义一个整型变量k和整型指针q,指针q没指向任何变量*/

q=&k;

/*将k的地址赋给指针q,即相当于指针q指向了变量k*/(2)通过数组名给指针变量赋值。

inta[10],*q;/*定义了一个整型数组a和整型指针q*/

q=a;/*将数组名赋值给指针q,相当于指针q指向了数组的首地址*/6.2.2指针变量的赋值6.2指针的定义和赋值(3)通过指针变量获得地址值。intk,*p;/*定义了一个整型变量k和整型指针p,指针p没指向任何变量*/int*q=&k;/*定义指针q并将其指向变量k*/p=q;/*将指针q的值赋给指针p,相当于p和q指向同一个变量k*/(4)通过标准函数获得地址值。通过调用malloc和calloc函数,在内存中开辟动态存储区域,并把所开辟的动态存储区域的地址赋给指针变量。int

*p1;/*定义一个指向整型变量的指针p1,但p1没指向任何变量*/p1=(int*)malloc(sizeof(int));/*动态开辟一个整型变量空间,并将p1指向该变量空间*/6.2.2指针变量的赋值6.2指针的定义和赋值(5)给指针变量赋NULL值。int*p;p=NULL;/*指针p被赋为空指针,即不指向任何变量*/(6)把函数的入口地址赋予指向函数的指针变量。例如:int(*pf)();/*定义一个指向函数的指针,后面会有详细介绍*/pf=f;/*将指针pf指向函数f,其中f为函数名*/6.2.2指针变量的赋值6.3指针变量的运算*运算符作用在指针(地址)上,代表该指针所指向的存储单元(及其值),实现间接访问,因此又叫“间接访问运算符”。例如:inta=5;/*定义了一个整型变量a,a中存储的值是5*/int*p=&a;/*定义一个指向整型变量的指针p,并将它指向变量a*/*p的值为5,与a等价。*运算符为单目运算符,与其他的单目运算符具有相同的优先级和结合性(右结合性)。根据*运算符的作用,*去处符和取地址去处符&互逆。即:*(&a)==a&(*p)==p6.3.1*运算符和&运算符6.3指针变量的运算指针变量有赋值运算,指针有指向运算。有意义的指针运算还包括算术运算和关系运算。不过,参与算术运算和关系运算的指针是有一定限制的,通常在指针代表一些连续的存储单元的情况下才有实际意义。1.指针的算术运算四种可以应用于指针的算术运算符:++(自增)、--(自减)、+(加)、-(减)。6.3.2指针的算术运算和关系运算6.3指针变量的运算(1)指针的自增或自减运算。作用是使指针指向下一个或前一个同类型的数据。(2)指针变量加上或减去一个正整数n。作用是将该指针移到当前位置之后或之前第n个数据的位置。(3)两个指针变量的减法运算。作用是求两个指针位置相差的变量个数,结果是一个整数。例如:charstr[10]=”HelloBaby!”/*定义一个字符数组str并将字符串HelloBaby!存入*/char*p=str,*q;/*定义指针p和q,并将p指向字符数组首地址,即指向字符H*/这里应说明的是,并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量。即指针p指向字符数组的首地址,指向字符H。6.3.2指针的算术运算和关系运算6.3指针变量的运算2.指针的关系运算在两个指向相同类型变量的指针之间可以进行各种关系运算,用来表示它们指向的地址位置之间的关系。关系运算符有:>、>=、<、<=、!=、==,可以对两个指针进行大小(地址值高低)的比较。指向后方的指针大于指向前方的指针;如果两个指针相等,则表明它们指向同一个数据。例如,上面例子中的指针p和q,若有条件q>p,则结果为真。在进行一些指针运算之前,常常需要先检查指针是否为空,再确定能否进行之后的数据访问操作。常用的判断指针p是否为空的语句为:if(p==NULL) {…}

或 if(!p){…}6.3.2指针的算术运算和关系运算6.3指针变量的运算【案例6-1】指针的赋值及运算示例。打开源程序程序运行结果6.4指针和数组的关系在C语言中,一维数组的数组名实际上就是指向数组下标为0的元素的指针。例如,若有如下定义:int a[5]={1,2,3,4,5},*p;p=a;则数组a中的元素与数组名a及指针p的关系,如图6-2所示。图6-2一维数组元素与元素地址关系示意图6.4.1指针与一维数组6.4指针和数组的关系指向一维数组首元素的任何指针也可以像一维数组名那样使用。由于指针p和数组名a均是指向数组a的首元素的指针,即p和a是完全等价的。因此,访问数组a中下标为i的元素,可以使用如下四种表示形式:a[i]、p[i]、*(a+i)、*(p+i)。提示:数组名特点对于数组名a来说,在C语言中认为是指针常量而不是变量,所以不能改变a的值,若写成“a++”是错误的。6.4.1指针与一维数组6.4指针和数组的关系【案例6-2】使用数组名和指针来访问一维数组中的每个元素。打开源程序程序运行结果6.4指针和数组的关系在C语言中,没有字符串类型,是通过字符型数组作为字符串的存储空间的。数组名就是指针,那么任何指向字符型数组首元素的指针都可以代表存储于该处的字符串。因为字符数组中存放字符串,使用很广泛,所以也可使用指针对字符数组进行访问,使字符串的各种操作更加方便。在字符串处理过程中,若指针p已指向某个字符串,如果判断字符串是否到尾部,一般采用语句:while(*p!='\0')………来进行判断。字符串的操作通常可以进行字符串的拷贝、比较等。所以使用两个指针分别指向两个字符串,拷贝字符串或比较对应位置字符是否相同,读者应熟练掌握指针在字符数组中的使用。6.4.2指针与字符数组6.4指针和数组的关系【案例6-3】使用指针来访问一维字符数组。打开源程序程序运行结果6.4指针和数组的关系1.指向二维数组的行指针因为二维数组其实可以看成是由几个一维数组构造而成,就相当于几个队列构成一个方阵。例如,有一个m行n列的二维数组,可以看成是由m个长度为n个元素的一维数组构成。前面讲的普通指针只能指向该二维数组中的每个元素,若要想将一种指针指向二维数组的每一行,就得定义另一种类型的指针,二维数组的行指针,也称为指向一维数组的指针。二维数组的行指针定义如下:

类型名(*指针名)[常量表达式];6.4.3指针与二维数组6.4指针和数组的关系其中的类型名为指针所指向数组元素的类型,指针名为合法的标识符,中括号中的常量表达式为该一维数组中的元素个数,即二维数组每一行中的元素个数。例如:charstr[3][10];/*定义了一个3行10列的二维数组str*/char(*p)[10];/*定义了一个指向有10个字符型元素的一维数组的指针p*/p=str;/*指针p指向了二维数组str的首地址*/6.4.3指针与二维数组6.4指针和数组的关系6.4.3指针与二维数组在使用二维数组的行指针来表示数组中每个元素时,可以使用与数组名相同的方法,即可以使用str[i][j]、*(*(str+i)+j),也可以使用p[i][j]、*(*(p+i)+j)的方式来表示二维数组中的每个元素。提示:二维数组的行指针注意事项将一个二维数组的行指针指向一个二维数组,访问二维数组中的每一行,即指针是一个指向一维数组的指针,因此,要保证二维数组中任一行中的元素个数应与定义时声明的指针所指的一维数组元素个数相同。例如上面二维数组为10列,则下面的指针p定义时的中括号中的值也必须为10。6.4指针和数组的关系2.指向二维数组的行指针的运算及应用假设有如下语句:int a[3][5];/*定义了一个3行5列的二维数组a*/int(*pa)[5];/*定义了一个指向有5个元素的一维数组的指针pa*/pa=a;/*指针pa指向了二维数组a的首地址*/那么pa+1指向什么地址空间?(1)语句int(*pa)[5];声明了一个指向有5个整数元素的一维数组的指针。a是一个3*5的二维整型数组,将数组名a赋值给指针pa,使指针pa指向二维数组a下标为0的第1行。(2)算术运算:pa是一个指向有5个整型元素的一维数组的指针,因此这个1的单位应该是5*sizeof(int)=10个字节,所以若pa=pa+1;,则pa指向数组a的下一行行首。6.4.3指针与二维数组6.4指针和数组的关系3.普通指针、二维数组的行指针与二维数组的关系当行指针pa指向二维数组的首地址时,则*pa表示第一行的首地址,pa+1为第二行首地址……当使用行指针表示二维数组的每个元素时,每行的第j个元素地址为*pa+j,该元素可以表示成*(*(pa+i)+j)。若有普通指针p指向该二维数组a,则将指针p指向该数组的某一行,只能写成p=a[i];或是p=*(pa+i),因为普通指针p比行指针pa低一个级别。则有p+1为该行第2个元素地址,p+2为该行第3个元素地址……,如图6-3所示。图6-3普通指针、二维数组的行指针与二维数组关系示意图6.4.3指针与二维数组6.4指针和数组的关系【案例6-4】使用普通指针和二维数组的行指针访问二维数组示例。打开源程序程序运行结果6.4指针和数组的关系数组是一组具有相同数据类型的数据的有序集合。指针也是一种数据,可不可以也作为数组中的元素呢,形成一个数据元素类型为指针的数组呢?答案是可以,指针数组就是数组元素为指针的数组。(1)指针数组的定义格式如下:例如语句:int*px[5];/*定义一个元素个数为5个的整型指针数组px,每个元素都可以指向一个整型变量*/

类型名*指针数组名[常量表达式];6.4.4指针数组6.4指针和数组的关系(2)初始化。指针数组可以在定义的同时被初始化,一般用来保存指向字符串的指针。例如语句:char*lesson[3]={"DataStructure","ComputerDesign","CLanguage"};/*定义字符型指针数组lesson并初始化,其三个元素分别指向一个字符串的首地址*/指针数组lesson有3个元素,每个元素都是一个字符指针,存放的是字符串的首地址。其中元素lesson[0]指向字符串"DataStructure",lesson[1]指向字符串"ComputerDesign",lesson[2]指向字符串"CLanguage"。lesson数组中的元素指向如图6-4所示。图6-4字符指针数组lesson的元素指向字符串示意图6.4.4指针数组6.4指针和数组的关系(3)赋值。指针数组的赋值与普通数组相同,但要注意所赋予的值应该是地址值,而且所赋地址的类型要与指针数组的类型相同。例如:inti;inta=10,b=20,c=30;/*定义三个整型变量a、b和c并分别赋初值*/int*p[3]={&a,&b,&c};/*定义整型指针数组p,p的三个元素指向上面定义的三个整型变量*/for(i=0;i<3;i++)printf("%5d",*p[i]);/*使用指针数组p输出a、b和c值*/该程序段的内存示意如图6-5所示。图6-5整型指针数组p中的元素指向整型变量示意图6.4.4指针数组6.4指针和数组的关系如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,又称为二级指针。在前面的内容中已经介绍过,通过指针访问变量称为间接访问。由于指针变量直接指向变量,所以也称为单级间访。而如果通过指向指针的指针变量来访问最终变量则构成了二级或多级间访。C语言程序设计中,对间接访问的级数并未明确限制,但是间接访问级数太多时不仅不容易理解,也更容易出错,因此,一般很少超过二级间访。6.4.5指向指针的指针——二级指针6.4指针和数组的关系指向指针的指针变量(二级指针)的定义格式如下:例如:int**pp,*p,i;/*定义一个二级指针pp,一级指针p和整型变量i*/p=&i;/*将指针p指向变量i*/pp=&p;/*将二级指针pp指向普通变量p*/表示pp是一个二级指针变量,它指向另一个指针变量p,而指针变量p指向一个整型变量i,指针和变量之间的关系如图6-6所示。

类型名**指针名;6.4.5指向指针的指针——二级指针6.4指针和数组的关系普通指针、二级指针和变量关系如图6-6所示。图6-6普通指针、二级指针和变量关系示意图若使用二级指针pp为变量i赋值,可使用如下语句:**pp=5;/*通过二级指针pp为变量i赋值为5*/6.4指针和数组的关系【案例6-5】指针数组和二级指针的示例。打开源程序程序运行结果6.5指针在函数中的应用指针与函数的关系主要表现在三个方面:函数的参数是指针、函数的返回值是指针和指向函数的指针(函数指针)。在函数应用中,函数的参数不仅可以是整型、实型、字符型、数组等数据,也可以是指针类型,以实现将地址传送到另一函数中参与操作。当函数的形参为指针类型时,调用函数时将实参变量的地址传递给形参(此时形参应是一个指针),则相当于形参指针指向实参变量,那么对形参所指对象的改变,也会改变实参的值。下面通过一个案例来了解函数的参数为指针的使用方法。6.5.1函数的参数是指针6.5指针在函数中的应用【案例6-6】编写函数实现交换两个变量的值,要求函数中参数为指针。打开源程序程序运行结果6.5指针在函数中的应用所谓函数类型,是指函数返回值的类型。函数可以返回一个整型、浮点型和字符型变量,也可以返回一个指针类型的变量。定义指针型函数的一般形式为:即在函数名前面加一个“*”,就表示该函数返回值为一个指针类型。返回值是指针的函数定义和使用方法与普通函数一样,只是返回语句return中返回的是一个指针变量。

函数类型*函数名(形参表)

{函数体

}6.5.2函数的返回值是指针6.5指针在函数中的应用【案例6-7】设计一个函数,在一个字符串中查找一个指定的字符。如果指定字符在字符串中,返回串中指定字符出现的第一个地址;否则,返回NULL值。要求使用指针函数实现在一个字符串中查找一个指定的字符。打开源程序程序运行结果6.5指针在函数中的应用6.5.3指向函数的指针C语言中的每一个函数经过编译后,其目标代码在内存中连续存放,该代码的首地址就是函数执行时的入口地址。在C语言中,函数名本身就代表着该函数的入口地址。通过这个入口地址可以找到该函数,该入口地址称为函数的指针。C语言中可以定义一个指针变量,使它的值等于函数的入口地址,即指针是指向这个函数的,通过这个指针变量就可以调用此函数。这个指针变量称为指向函数的指针,又称为函数指针。6.5.2函数的返回值是指针6.5指针在函数中的应用函数指针的定义格式。因为这个指针是指向函数的,所以它的定义是与某个函数原型声明相关的。指向该函数的函数指针变量应该定义为:即将函数原型声明中的函数名改为(*指针变量名)即可。例如,若有一个函数原型声明为:ints;intsum(inta,intb);/*声明一个函数sum,该函数有两个整型形参a和b*/int(*p)(inta,intb);/*定义一个函数指针p,p可指向具有两个整型形参的函数*/p=sum;/*指针p指向sum函数首地址*/s=(*p)(2,6);/*使用指针p调用sum函数,两实参分别为2和6*/

函数类型(*指针变量名)(形参表);6.5.2函数的返回值是指针6.5指针在函数中的应用【案例6-8】通过指向函数的指针调用所指向的函数示例。打开源程序程序运行结果6.5指针在函数中的应用我们之前学习中定义的main函数,其参数表都是空的,那么main函数可以带参数吗?程序运行时参数又如何传递给main函数呢?由不带参数的main函数所生成的可执行文件,在执行时只能输入可执行文件名(即命令名),而不能输入参数;而在实际应用中,经常希望执行程序时,能够由带参数的命令行向程序提供所需要的信息,这就需要在程序中定义带参数的main函数。2023/9/226.5.4带参数的main函数6.5指针在函数中的应用(1)命令行参数。所谓“命令行”,是指在DOS提示符下输入的命令名(.exe文件)及其参数,其中的参数称为命令行参数。带参数的命令行一般具有如下格式:命令名和参数以及参数和参数之间都由空格隔开,这些参数是通过命令行传递到程序中。(2)带参数的main函数。main函数通常是不带参数的,若带参数可以带两个参数,函数的参数表格式如下:第一个形参agrc是一个整型变量,存放的是命令行中命令名与参数的总个数。第二个形参agrv是一个指针数组,其元素可以指向带参数的命令行中命令名与参数所代表的字符串。

命令名参数1 参数2 …参数n;

main(intargc,char*argv[]);6.5.4带参数的main函数6.5指针在函数中的应用【案例6-9】编写一个程序,显示带参数的命令行中的命令名和参数。打开源程序程序运行结果6.6程序案例【案例6-10】输入一行字符(不超过100个),统计其中大写字母、小写字母、数字、空格及其他字符的个数。打开源程序程序运行结果6.6.1典型案例——用指针实现统计字符串中各种字符的个数6.6程序案例【案例6-11】求出形参ss所指字符串数组中最长字符串的长度,其余字符串左边用字符*补齐,使其与最长的字符串等长。字符串数

温馨提示

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

评论

0/150

提交评论