版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C语言程序设计(下)第一、二次课 4学时第1页,共218页。第六章 指针第十一次课 2学时第2页,共218页。学习目的1、通过本章的学习使学生掌握指针的意义及使用。2、应知数组的指针的意义,数组元素的指针的意义,及使用数组名作函数参数,应会通过指针引用数组元素。学习重点1.指针的使用2、指针和数组的关系学习难点1.通过指针引用变量的意义2、指针和数组的关系3第3页,共218页。指针的基本概念指针变量的定义与引用指针与数组第4页,共218页。 为什么要学习指针? 指针是C语言一个重要的概念也是C语言的重要特色。正确灵活的运用指针可以有效地表示负责的数据结构。能动态的分配内存,方便的使用字符串,有
2、效的而方便的使用数组,在调用函数时能获得一个以上的结果,能直接处理内存单元地址等。而这些是设计系统软件非常必要的,掌握指针可以有效的使程序简洁、紧凑、高效。第5页,共218页。6.1 指针的基本概念6.1.1 指针的概念 1.内存及其地址“程序存储”就是在程序运行之前将程序和数据存入计算机内存。所以在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元,为了正确地访问这些内存单元,必须为每个内存单元编号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。第6页,共218页。6.1 指针的基本概念6.1.1 指针的概念 main()float
3、 x; int y; 变量的两个物理意义 200020012002200320042005xy变量的内容变量的地址第7页,共218页。6.1 指针的基本概念6.1.1 指针的概念 2.变量地址的获取 变量的存储单元是在编译时(对静态存储变量)或程序运行时(对动态存储变量)分配的,因此变量的地址不能人为确定,而要通过取地址运算符&获取。例如在如下的程序段中:int a; float b; char c;scanf(%d%f%c,&a,&b,&c);由&a、&b和&c分别得到变量a、b和c的内存地址。值得注意的是,由于常量和表达式没有用户可操作的内存地址,因此&不能作用到常量或表达式上。 第8页,
4、共218页。6.1 指针的基本概念6.1.1 指针的概念 3.指针与指针变量 根据内存单元的编号或地址就可以找到所需的内存单元,通常把这个地址称为指针。在C语言中,专门存放变量(或其它程序实体)地址的变量是指针变量。指针变量也需要存储单元(存放地址值的整数),它本身也有地址。例如让变量p存放整型变量a的地址(如图所示),这样,由变量p的值(地址,图中为1012)就可以找到变量a,因此称变量p指向变量a,变量p就是指针变量,它存放的地址就称为“指针”。因此,指针就是地址。第9页,共218页。6.1 指针的基本概念6.1.1 指针的概念 4.直接访问方式与间接访问方式有了指针变量以后,对一般变量的
5、访问即可以通过变量名进行,也可以通过指针变量进行。通过变量名或其地址(如a或&a)访问变量的方式叫直接访问方式;通过指针变量(如p)访问它指向的变量(如a)的方式叫间接访问方式。 第10页,共218页。6.2 指针变量的定义与引用6.2.1 指针变量的定义与初始化指针变量的一般定义形式为: 类型名 *标识符;其中“标识符”是指针变量名,标识符前加“*”号表示该变量是指针变量,用于存放地址,“类型名”表示该指针变量所指向变量的类型。第11页,共218页。6.2 指针变量的定义与引用6.2.2 指针变量的赋值 通过地址运算“&”赋值地址运算符“&”是单目运算符,运算对象放在地址运算符“&”的右边,
6、用于求出运算对象的地址。通过地址运算“&”可把一个变量的地址赋给指针变量。指针变量的初始化 与动态变量的初值一样,在定义了一个(动态的)指针变量之后,其初值也是一个不确定的值。可以在定义变量时给指针变量赋初值,如float f, *p=&f; 则把变量f的地址赋值给指针变量p,此语句相当于 float f, *p; p=&f; 这两条语句。第12页,共218页。6.2 指针变量的定义与引用6.2.2 指针变量的赋值通过其它指针变量赋值可以通过赋值运算符,把一个指针变量的地址值赋给另一个指针变量,这样两个指针变量均指向同一地址。用NULL给指针变量赋空值除了给指针变量赋地址值外,还可以给指针变量
7、赋空值,如 p=NULL;第13页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用1.指针变量的赋值运算在函数的执行部分给指针变量赋地址值有以下几种情况。(1) 赋给同类型普通变量求地址运算得到的地址值。如:int k=10,*p,*q;q=&k;这时scanf(%d,&k);与scanf(%d,q);作用相同。(2) 通过已有地址值的指针变量赋值。 (3) 通过标准函数获得地址值。(4) 给指针变量赋“空”值,如:p=NULL;这样做的目的是:让指针变量存有确定的地址值又不指向任何变量(类似于给数值型变量赋初值0)。第14页,共218页。6.2 指针变量的定义与引用6.
8、2.3 指针的运算及引用2.指向运算和指针变量的引用(1) 指向运算符*运算符作用在指针(地址)上,代表该指针所指向的存储单元(及其值),实现间接访问,因此又叫“间接访问运算符”。如:int a=5, *p;p=&a;printf(%d,*p);*p的值为5与a等价。*运算符为单目运算符,与其他的单目运算符具有相同的优先级和结合性(右结合性)。根据*运算符的作用,*运算符和取地址运算符 & 互逆:*(&a)=a &(*p)=p注意,在定义指针变量时,“*”表示其后是指针变量;在执行部分的表达式中,“*”是指向运算符。(2) 指针变量的引用知道了指针变量的作用以及相关的运算符以后,我们就可以引用
9、指针变量了。 第15页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用【例6-1】请理解下列程序中各语句的含义:#includevoid main( )int a=10,*p=&a; printf(*p=%dn,*p); /* 打印指针变量p所指向的变量a的值10 */ printf(Enter a: ); scanf(%d,p); /* 对指针变量p所指向的变量a的地址读入整数 */ printf(a=%dn,a); printf(p=%xn,p); /* 输出指针变量p存储的变量a的地址 */ printf(&p=%xn,&p); /* 输出指针变量p自身的地址 */
10、 *p=5; /* 把5赋给p所指向的存储单元,相当于a=5;*/ printf(a=%dn,a); (*p)+; /* 使指针变量p所指向的存储单元的值自增,相当于a+; */ printf(a=%dn,a);程序运行结果:*p=10Enter a:15a=15p=13ff7c&p=13ff78a=5a=6第16页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用【例6-2】输入两个整数i1和i2,利用指针将大数存放到i1中,小数存放到i2中,最后按i1、i2的顺序输出。按题意,定义两个指针变量p1、p2,将i1、i2的地址分别存入p1、p2,当i1i2时利用指针变量p1
11、、p2交换i1、i2的值然后输出。程序如下:第17页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用#includevoid main( )int i1, i2, *p1, *p2, t; p1=&i1; p2=&i2; printf(Enter two numbers:n); scanf(%d%d,p1,p2); /* 利用指针变量输入i1、i2的值 */ if(i1i2)t=*p1;*p1=*p2;*p2=t; /* 利用指针变量的指向操作交换i1、i2的值*/ printf(i1=%d,i2=%dn,i1, i2);Enter two numbers:5 10程序运
12、行结果:i1=10,i2=5 第18页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用【思考】如果将变量定义改为int i1, i2, *p1, *p2, *p;交换i1、i2值的语句改为:if(i1i2)p=p1; p1=p2; p2=p;或者if(i1i2)*p=*p1; *p1=*p2; *p2=*p;将会怎样? 【分析】第一种情况是:在i1i2的情况下,利用临时指针变量p交换指针变量p1、p2存放的地址值,而i1、i2的值没有改变,因此题目的要求没有实现(如图6-5所示)。但如果同时将输出语句改为:printf(max=%d,min=%dn,*p1, *p2);
13、可实现从大到小输出。第二种情况是:在i1i2的情况下,利用三个指针变量的指向操作交换i1、i2的值。问题是:指针变量p没有存放普通变量的地址,因此也是错误的(运行时有警告)。第19页,共218页。6.2 指针变量的定义与引用6.2.3 指针的运算及引用【思考】如果将变量定义改为int i1, i2, *p1, *p2, *p;交换i1、i2值的语句改为:if(i1i2)p=p1; p1=p2; p2=p;或者if(i1i2)*p=*p1; *p1=*p2; *p2=*p;将会怎样? 【分析】第一种情况是:在i1i2的情况下,利用临时指针变量p交换指针变量p1、p2存放的地址值,而i1、i2的值
14、没有改变,因此题目的要求没有实现(如图6-5所示)。但如果同时将输出语句改为:printf(max=%d,min=%dn,*p1, *p2); 可实现从大到小输出。第二种情况是:在i1i2的情况下,利用三个指针变量的指向操作交换i1、i2的值。问题是:指针变量p没有存放普通变量的地址,因此也是错误的(运行时有警告)。第20页,共218页。6.2 指针变量的定义与引用6.2.4 指针作为函数参数函数的参数可以是我们在前面学过的简单数据类型,也可以是指针类型。使用指针类型做函数的参数,实际向函数传递的是变量的地址。由于函数中获得了所传递变量的地址,在该地址空间的数据当函数调用结束后被物理地保留下来
15、。第21页,共218页。6.2 指针变量的定义与引用6.2.4 指针作为函数参数【例6-3】利用指针变量作为函数的参数,用函数的方法再次实现上述功能。#includevoid main( )void chang( ); /* 函数声明 */int*p1,*p2,a,b,*t;scanf(%d,%d,&a,&b);p1=&a;p2=&b;chang(p1,p2); /* 调用函数 */printf(%d,%dn,*p1,*p2);return 0;第22页,共218页。6.2 指针变量的定义与引用6.2.4 指针作为函数参数void chang(int*pt1,int*pt2) /* 函数实现将
16、两数值调整为由大到小 */int t;if (*pt1*pt2)t=*pt1;*pt1=*pt2;*pt2=t; /* 交换内存变量的值 */return;由于在调用函数时,实际参数是指针变量,形式参数也是指针变量,实参与形参相结合,传值调用将指针变量传递给形式参数pt1和pt2。但此时传值传递的是变量地址,使得在函数中pt1和pt2具有了p1和p2的值,指向了与调用程序相同的内存变量,并对其在内存存放的数据进行了交换,其效果与例6-2相同。第23页,共218页。6.2 指针变量的定义与引用6.2.5 多级指针的概念按照上述二级指针的思路,显然可以推广到三级指针、四级指针。使用多级指针变量的要
17、点是: 多级指针变量均用基类型定义,定义几级指针变量要将变量名前放几个“*”号; 各指针变量均应取得低一级指针变量的地址后才能引用; 引用几级指针变量访问最终的普通变量时,变量名前需用几个指向运算符“*”号。第24页,共218页。6.2 指针变量的定义与引用6.2.5 多级指针的概念【例6-4】运行下面的程序#includevoid main( )int *p1,*p2,*p3,*p4,x=10;p1=&x;p2=&p1;p3=&p2;p4=&p3;printf(x=%dn,*p4);程序运行结果:x=10第25页,共218页。6.3 指针与数组6.3.1 指针与一维数组一个数组的元素在内存中
18、是连续存放的,数组第一个元素的地址称数组的首地址。在C语言中,数组名是该数组的首地址。例如有以下定义语句: int a10,*p;则语句p=a;和p=&a0;是等价的,都表示指针变量p指向a数组的首地址。数组首地址的值在语言中是一个地址常量,是不能改变的。因此,语句 a=p; 或a+;都是非法的。 第26页,共218页。6.3 指针与数组6.3.1 指针与一维数组1通过一维数组名所代表的地址存取数组元素. 假设已定义一维数组a,由上述可知a+i是元素ai的地址,根据指针运算符“*”的运算规则知 *(a+i) 与元素 ai等价。例如,下述程序段: int a =1, 2, 3, 4, 5, 6,
19、 7, 8, 9, 10; *(a+5)=50; /* 相当于a5=50 ; */ scanf(%d, &a8); /* 相当于scanf(%d, a+8 ); */ printf(%dn, *(a+5) ); /* 相当于printf(%dn, a5) ) */ 第27页,共218页。6.3 指针与数组6.3.1 指针与一维数组2通过指针运算符“*”存取数组元素 设有如下程序段: int a10,*p; p=a;即p指向a数组的首地址,由上述可知p+i是元素ai的地址,根据指针运算符“*”的运算规则知 *(p+i) 与元素 ai等价。例如,下述程序段: int a =1, 2, 3, 4,
20、5, 6, 7, 8, 9, 10, *p=a; *(p+5)=50; /* 相当于a5=50 ; */ scanf(%d, &a8); /* 相当于scanf(%d, p+8 ); */ printf(%dn, *(p+5) ); /* 相当于printf(%dn, a5) ) */第28页,共218页。6.3 指针与数组6.3.1 指针与一维数组3通过带下标的指针变量存取数组元素语言中的下标运算符“ ”可以构成表达式,假设p为指针变量,i为整型表达式,则可以把pi看成是表达式,首先按p+i计算地址,然后再存取此地址单元中的值。因此pi与*(p+i)等价。例如,下述程序段: int a =1
21、, 2, 3, 4, 5, 6, 7, 8, 9, 10, *p=a; p5=50; /* 相当于a5=50 ; */ scanf(%d, &a8); /* 相当于scanf(%d, &p8 ); */ printf(%dn, p5 ); /* 相当于printf(%dn, a5) ) */第29页,共218页。6.3 指针与数组6.3.2 指针与二维数组1.二维数组的地址表示法C语言规定,二维数组由一维数组扩展形成,即一维数组的每一个元素作为数组名形成一行数组,各行数组的元素个数相同,是二维数组的列数。例如定义了二维数组int a34,它是由一维数组int a3扩展形成,即以a0、a1、a2
22、为数组名(首地址)形成三行一维数组,元素个数均为列数4。因此a0、a1、a2为一级指针常量,指向各行的首列(列指针)。例如0行的a0=&a00指向0行0列。0行有四个元素,它们是a00、a01、a02、a03。另外a0、a1、a2又是数组名为a的一维数组的三个元素,首地址a=&a0指向的“元素”为一级指针常量,因此a为二级指针常量,指向0行(行指针)。 第30页,共218页。6.3 指针与数组6.3.2 指针与二维数组【例6-5】输出二维数组的有关值,程序编写如下,注意理解各语句的含义。#includevoid main( )int a34=1,2,3,4,5,6,7,8,9,10,11,12
23、;printf(%u,%un,a, *a); /* 0行首地址和0行0列首地址 */printf(%u,%un,a+1, *a+1); /* 1行首地址和0行1列首地址*/printf(%u,%un,a, &a0); /* 0行首地址 */printf(%u,%u,%un,*(a+1), a1, &a10); /* 1行0列首地址 */printf(%d,%d,%dn,*(*(a+1)+2), *(a1+2), a12); /* 1行2列的元素7 */程序运行结果:1310544,13105441310560,13105481310544,13105441310560,1310560,1310
24、5607,7,7 第31页,共218页。6.3 指针与数组6.3.2 指针与二维数组2.用于二维数组的指针变量(1) 指向数组元素的指针变量(一级指针变量):将二维数组当成一维数组访问。第32页,共218页。6.3 指针与数组6.3.2 指针与二维数组【例6-6】用一级指针变量输出二维数组的全部元素。#includevoid main( )int a34=1,2,3,4,5,6,7,8,9,10,11,12,i,j,*p;p=a0; /* 指针变量必须得到首元素地址a0或*a或&a00 */for(i=0; i3; i+) for(j=0; j4; j+) printf(%3d, *(p+4*
25、i+j);printf(n);程序运行结果: 1 2 3 4 5 6 7 8 9 10 11 12第33页,共218页。6.3 指针与数组6.3.2 指针与二维数组(2) 指向一维数组的指针变量(行指针变量)二维数组名(设为a)以及a+1、a+2等均为行指针(二级指针)常量,分别指向由一行元素组成的行一维数组,但它们不能移动(例如不能由a+使a得到地址a+1)。但是如果有定义:int a34, (*prt)4; prt=a;考虑其中的(*prt)4,因为( )和 的优先级相同,*prt表示prt应为指针变量,它指向一个含有4个元素的整型一维数组,而不是指向一个元素,因此它是二级指针变量(行指针
26、变量),可以移动。指向一维数组的指针变量的一般定义形式为:类型 (*指针变量名)一维数组元素个数; 第34页,共218页。6.3 指针与数组6.3.2 指针与二维数组【例6-7】输出二维数组任意行任意列的元素值。定义指向一维数组的指针变量,按照上面的说明表示二维数组任意行任意列的元素,程序如下:#includevoid main( )int a34=1,2,3,4,5,6,7,8,9,10,11,12;int (*p)4=a, row, col;printf(Enter arbitrary number of row and column:n);scanf(%d,%d, &row, &col)
27、;printf(a%d%d=%dn, row, col ,*(*(p+row)+col);程序运行结果:a23=12Enter arbitrary number of row and column:2,3第35页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数【例6-8】调用函数,实现求解一维数组中的最大元素。我们首先假设一维数组中下标为0的元素是最大和用指针变量指向该元素。后续元素与该元素一一比较,若找到更大的元素,就替换。sub_max()函数的形式参数为一维数组,实际参数是指向一维数组的指针。 第36页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数#in
28、clude void main( )intsub_max( ); /* 函数声明 */intn,a10,*ptr=a; /* 定义变量,并使指针指向数组 */intmax;for (n=0;n=9;n+) /* 输入数据 */scanf(%d,&an);max=sub_max(ptr,10); /* 函数调用,其实参是指针 */printf(max=%dn,max);int sub_max(b,i) /* 函数定义,其形参为数组 */intb ,i; inttemp,j;temp=b0;for (j=1;j=9;j+)if(tempbj)temp=bj;return temp;第37页,共21
29、8页。6.3 指针与数组6.3.3 数组指针作函数的参数程序的main()函数部分,定义数组a共有10个元素,由于将其首地址传给了ptr,则指针变量ptr就指向了数组,调用sub_max()函数,再将此地址传递给sub_max()函数的形式参数b,这样一来,b数组在内存与a数组具有相同地址,即在内存完全重合。在sub_max()函数中对数组b的操作,与操作数组a意义相同。main()函数完成数据的输入,调用sub_max()函数并输出运行结果。sub_max()函数完成对数组元素找最大的过程。在sub_max()函数内数组元素的表示采用下标法。第38页,共218页。6.3 指针与数组6.3.3
30、 数组指针作函数的参数#include void main( )int sub_max( );int n,a10,*ptr=a;int max;for (n=0;n=9;n+)scanf(%d,&an);max=sub_max(ptr,10);printf(max=%dn,max);int sub_max(b,i) /* 形式参数为指针变量 */int*b,i; int temp,j;temp=b0; /* 数组元素指针的下标法表示 */for(j=1;j=i-1;j+)if(tempbj)temp=bj;return temp;第39页,共218页。6.3 指针与数组6.3.3 数组指针作函
31、数的参数在sub_max()中,形式参数是指针,调用程序的实际参数ptr为指向一维数组a的指针,虚实结合,sub_max()的形式参数b得到ptr的值,指向了内存的一维数组。数组元素采用下标法表示,即一维数组的头指针为b,数组元素可以用bj表示。程序输入数据:1 3 5 6 89 1 2 56 23 78程序运行结果:max=89第40页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数上述程序的函数中,数组元素还可以用指针表示int sub_max(b,i) /* 函数定义 */int*b,i;inttemp,j;temp=*b+;for (j=1;j=i-1;j+)if(te
32、mp*b) temp=*b+; return temp; 第41页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数【例6-8】用指向数组的指针变量实现一维数组的由小到大的冒泡排序。编写三个函数用于输入数据、数据排序、数据输出。第42页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数#include #define N10void main( )void input( ); /* 函数声明*/void sort( );void output( );intaN,*p; /* 定义一维数组和指针变量 */input(a,N); /* 数据输入函数调用,实参a是数组名
33、*/p=a; /* 指针变量指向数组的首地址 */sort(p,N); /* 排序,实参p是指针变量 */output(p,N); /* 输出,实参p是指针变量 */ 第43页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数void input(arr,n) /*无需返回值的输入数据函数定义,形参arr是数组*/int arr ,n;inti;printf(input data:n);for (i=0;in;i+) /* 采用传统的下标法 */scanf(%d,&arri);void sort(ptr,n) /* 冒泡排序,形参ptr是指针变量 */int*ptr,n;inti
34、,j,t;for (i=0;in-1;i+)for (j=0;j*(ptr+j+1) /* 相临两个元素进行比较 */t=*(ptr+j);*(ptr+j)=*(ptr+j+1); *(ptr+j+1)=t; /*两个元素进行交换*/ 第44页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数void output(arr,n) /* 数据输出 */int arr ,n;inti,*ptr=arr; /* 利用指针指向数组的首地址 */printf(outputdata:n);for(; ptr-arrn; ptr+) /* 输出数组的n个元素 */printf(%4d,*ptr
35、);printf(n);第45页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数【例6-10】用指向二维数组的指针作函数的参数,实现对二维数组的按行相加。#include #defineM3#defineN4void main( )floataMN;floatscore1,score2,score3,*pa=a0;/* 指针变量pa指向二维数组 */*score1,score2,score3分别记录三行的数据相加*/inti,j;void fun();for(i=0;iM;i+) /* 二维数组的数据输入 */for(j=0;jN;j+)scanf(%f,&aij);fun(p
36、a,&score1,&score2,&score3); /*函数调用,不仅传递数组首地址,也传递变量的地址*/ 第46页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数printf(%.2f,%.2f,%.2fn,score1,score2,score3);void fun(b,p1,p2,p3)float b N,*p1,*p2,*p3;int i,j;*p1=*p2=*p3=0;for(i=0;iM;i+)for(j=0;jN;j+) if(i=0) *p1=*p1+bij; /* 第0行的数据相加 */if(i=1) *p2=*p2+bij; /* 第1行的数据相加 */
37、if(i=2) *p3=*p3+bij; /* 第2行的数据相加 */第47页,共218页。6.3 指针与数组6.3.3 数组指针作函数的参数程序中与形式参数p1、p2和p3相对应的是实际参数&score1、&score2和&score3,其实际含义为p1=&score1等,即将变量的地址传递给指针变量达到按行相加。程序输入数据:1 3 5 934 56 78 89 76 65 43 21程序运行结果:18.00,257.00,205.00第48页,共218页。本次课学习小结1.指针的基本概念2.指针变量的定义与引用3.指针与数组第49页,共218页。 1.地址与指针变量的概念,地址运算符与间
38、址运算符。 2.一维。二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的定义。通过指针引用以上各类型数据。 3.用指针作函数参数。 4.返回地址值的函数。 5.指针数组,指向指针的指针。本次课等级考试考点第50页,共218页。练习:等级考试真题一、选择题:(2007年9月份考题)(33)若有定义语句:int a23,*p3; ,则以下语句中正确的是A)p=a; B)p0=a; C) p0=&a12; D)p1=&a;答案:C第51页,共218页。练习:等级考试真题二、填空题:(2007年4月份考题)(15) 以下程序的功能是:利用指针指向三个整型变量,并通过指针运算找出
39、三个数中的最大值,输出到屏幕上,请填空:Main()int x,y,z,max,*px,*py,*pz,*pmax;Scanf(“%d%d%d”,&x,&y,&z);Px=&x;Py=&y;Pz=&z;Pmax=&max;_ If(*pmax*py)*pmax=*py;If(*pmax*pz)*pmax=*pz;Printf(“max=%dn”,max);*pmax=*px第52页,共218页。三、填空题:(2007年9月份考题填空题) 练习:等级考试真题(11) 以下程序的输出结果是_.#include #include char *fun(char *t) char *p=t;return
40、(p+strlen(t)/2);main() char *str=abcdefgh;str=fun(str);puts(str);efgh第53页,共218页。练习:本次课作业:习题集:第六章 选择题:1、2、3、4填空题:1、2、3、4、5改错题:1、2编程题:1、2第54页,共218页。 第6章 指针 6.4指向字符串的指针变量 6.5 指针数组 6.6 指针数组作main函数的形参 6.7 指向指针的指针变量 第十二次课 2学时第55页,共218页。学习目的1.了解字符串的表示形式 2.掌握字符串作函数参数和字符指针变量与字符数组的区别 3.了解指针数组的一般定义形式 4.掌握指针数组的
41、应用 5.了解带参数的main函数的一般形式 6.掌握命令行参数的应用 7.了解指向指针的指针变量的一般定义形式 8.掌握指向指针的指针变量的应用 学习重点1.指向字符串的指针变量的定义、赋值和使用2.指针数组 3.指向指针的指针变量学习难点1.字符串的指针作函数参数2.指针数组作函数参数 56指针第56页,共218页。 字符串的表示形式 字符串作函数参数 字符指针变量与字符数组的区别 指针数组的一般定义形式 命令行参数的应用 指向指针的指针变量的一般定义形式 指针 指针数组的应用 带参数的main函数的一般形式 指向指针的指针变量的应用 第57页,共218页。 6.4指向字符串的指针变量6.
42、4.1 字符串的表示形式字符串是特殊的常量,它一般被存储在一维的字符数组中并且以0结束。字符串与指针也有着密切的关系。在C语言程序中,可以采用两种方法来实现访问一个字符串:其中一种方法是采用字符数组,另一种方法是采用字符指针。在字符串的处理中,使用字符指针比使用字符数组更方便。 第58页,共218页。程序运行输出结果:Beijing Olympics Beijing Olympics(1)定义一个字符数组,并且将一个字符串存放在字符数组中,以空字符0结束。【例6-11】定义一个字符数组,然后通过下标和数组名引用字符或字符串。 #include void main( )char string =
43、Beijing Olympics; /*定义字符数组并且初始化*/ int i; for(i=0; stringi!=0; i+) /*逐个选取字符数组中的所有数组元素*/ printf (%c, stringi); /*通过下标每次输出一个字符*/ printf(n); printf(“%sn”,string); /*从数组名string指向的元素开始,输出 字符串到0为止*/第59页,共218页。在【例6-11】中string是存放给定字符串的数组名,它代表字符数组第0号数组元素的地址。在C语言中规定,数组名代表数组的首地址,也就是数组中第0号数组元素的地址(即指向该数组第0号数组元素的指
44、针)。 所以将字符串存储在一个数组中以后,就可以通过该数组名对它进行存取。由于string+i是一个地址,则*(string+i)表示其内容,它与代表数组元素的stringi等价。第60页,共218页。程序运行输出结果:Beijing Olympics (2)定义一个字符指针变量,并且将字符指针指向一个字符串常量。 【例6-12】定义一个字符指针,然后通过它引用字符串。 #include void main( ) char *string=“Beijing Olympics”; /* 定义字符指针变 量并且指向一个字符串 */ printf(%sn,string); /* 输出字符串 */ 第
45、61页,共218页。注意,在对字符指针变量string赋初值为字符串常量时,并不是把整个字符串的内容都赋给该字符指针变量,而仅仅是把该字符串在内存单元的首地址(即第一个字符的地址)赋给该字符指针变量,这样就可以将字符指针指向字符串的第一个字符。在C语言中,对字符串常量的存放是按静态字符数组处理的。就是说,在内存中分配给字符数组一片连续的存储单元用来存放该字符串常量。一般情况下,每一个字符占用一个字节的存储单元。在内存中,由于字符串的最后被自动填加了一个0,所以使用字符指针变量来处理字符串的时候就很容易判断字符串的终止位置。第62页,共218页。 对于使用字符指针变量处理字符串的情况,在输出字符
46、串时要使用“%s”格式符,输出项中要给出字符指针变量名,这样,计算机就先输出字符指针变量所指向字符串的第一个字符,然后字符指针变量自动加1而指向字符串的下一个字符,接着再输出该字符,重复上述操作直到遇到字符串结束标志0为止。所以,虽然一个数值型数组不能使用数组名来输出该数组的全部元素,而只能逐个元素进行输出;但是使用字符数组名或者字符指针变量却可以整体输出一个字符串。 为便于理解,程序可以如下编写:#include void main( ) char string =Beijing Olympics; /* 定义字符数组并且初始化 */ char *p=string; /* 定义字符指针变量p
47、并且赋值为字符 串首地址string */ printf(%sn, p); /* 输出字符串 */ 第63页,共218页。程序运行输出结果:string1 is: I am a tearcher. string2 is: I am a tearcher.【例6-13】使用字符数组名的方法计算数组元素地址,完成字符串的复制。#include void main( ) char string1 =I am a tearcher., string220; /* 定义字符数组并且初始化 */ int i; for(i=0; *(string1+i)!=0; i+) *(string2+i)=*(str
48、ing1+i); /* 将string1数组中的字符串复制到string2数组 */ *(string2+i)=0; printf(string1 is:%sn, string1); printf(string2 is:); for(i=0; string2i!=0;i+) printf(%c, string2i); /* 输出字符串 */ 第64页,共218页。在【例6-13】for循环中,首先判断string1i(此处以( string1+i)的地址形式表示)是否为0。假如不为0,则将string1i的值赋给string2i(此处以*( string 2+i)的地址形式表示),完成一个字符
49、的复制。 ,重复上述操作,将string1数组中字符串全部都复制给string2数组直到string1i(以*( string1+i)的地址形式表示)遇到0为止。最后要将0复制给string2数组。第65页,共218页。程序运行输出结果:string1 is: I am a tearcher. string2 is: I am a tearcher.【例6-14】使用字符指针变量的方法,完成字符串的复制。#include void main( ) char string1 =I am a teacher., string220; /* 定义字符数组并且初始化 */ char *p1,*p2;
50、/* 定义字符指针变量 */ int i; p1=string1; /* p1指向字符数组ch1的首地址 */ p2=string2; for( ; *p1!=0; p1+,p2+) *p2=*p1; /* 将p1指向的字符串复制到p2指向的字符串 */ *p2=0; printf(string1 is:%sn, string1); printf(string2 is:); for(i=0; string2i!=0;i+) printf(%c, string2i); /* 输出字符串 */ 第66页,共218页。在【例6-14】中,首先定义p1和p2是指向字符型数据的指针变量。然后使字符指针变
51、量p1和p2分别指向字符数组string1和string2的首地址。在for循环中,首先判断*p1是否为0。假如不为0,则进行*p2=*p1,它的功能是将数组string1中字符串的第一个字符赋给数组string2中的第一个数组元素。然后再利用p1+和p2+使p1和p2都加1而分别指向各自的下一个数组元素,这样就保证p1和p2同步移动,重复上述操作,将string1数组中字符串全部都复制给string2数组,直到*p1的值遇到0为止。最后,需要将0复制给*p2。第67页,共218页。使用地址传递的方法(即用字符数组名作函数参数或者用指向字符串的指针变量作函数参数)可以将一个字符串从一个函数传递
52、到另一个函数。【例6-15】实参、形参都用字符数组名作函数参数,完成字符串的连接。 #include void main( ) void string_catenate(char from , char to ); /* 字符串连接函数的原型声明 */ char string1 =computer; /* 定义字符数组并且初始化 */ char string2 =language; printf(string1=%sn string2=%sn, string1, string2); printf(catenat string2 to string1:n ); string_catenate(s
53、tring1, string2); /*调用函数,实参为字符数组 */ printf(nstring1 is : %sn , string1); 6.4.2 字符串作函数参数第68页,共218页。程序运行输出结果:string1 is : computerlanguagevoid string_catenate(char from , char to ) /* 字符串连接函数,形参为字符数组 */ int i=0,j=0; while(fromi!=0) i+; /* 将指针移动到字符串的尾部 */ while(toj!=0) fromi=toj; i+, j+; /* 将to数组中字符串连接
54、到from数组中字符串的尾部 */ fromi=0; 第69页,共218页。【例6-16】实参、形参都用字符指针变量作函数参数,完成字符串的连接。 #include void main( ) void string_catenate(char *from, char *to); /* 字符串连接函数的原型声明 */ char *string1=computer ; /* 定义字符指针变量并且指向一个字符串 */ char *string2=language; printf(string1=%sn string2=%sn, string1, string2); printf(catenat st
55、ring2 to string1:n ); string_catenate(string1, string2); /* 调用函数,实参为字符指针变量 */ printf(nstring1 is : %sn , string1); 第70页,共218页。程序运行输出结果:string1 is : computerlanguage void string_catenate(char *from, char *to) /* 字符串连接函数,形参为字符指针变量 */ for( ; *from!=0; from+) ; /* 空循环体,将指针移动到字符串的尾部 */ for( ; *to !=0; fr
56、om+, to+) *from=*to; /* 将to指向的字符串连接到from指向的字符串的尾部 */ *from= 0; 第71页,共218页。数组名、字符指针变量既可以作函数的实参,也可以作函数的形参,归纳起来有如下几种情况。表6-2 字符数组名、字符指针变量作函数参数的4种组合实参形参数组名数组名数组名字符指针变量字符指针变量数组名字符指针变量字符指针变量第72页,共218页。6.4.3 字符指针变量与字符数组 的区别 使用字符数组和字符指针变量都可以实现字符串的存储和运算,两种方式有相同之处,但也是有区别的。比较的项目字符数组字符指针变量存放的内容由若干个数组元素组成,每个数组元素中
57、存放一个字符存放地址(如字符串中第1个字符的地址) 存储空间 字符串长度加1,一个字符占用1个字节 一般使用2个字节存放 第73页,共218页。比较的项目字符数组字符指针变量初始化 可以初始化char a =Hi!; 可以初始化 char *p=Hi!; 赋值 不能用字符串整体给字符数组赋值,只能对字符数组单个元素赋值 能用字符串整体对字符指针赋值(为字符串中第1个字符的地址)char *p;p=Hi!; 地址值 有确定地址,定义数组后在编译时分配内存单元 定义字符指针变量时分配内存单元,但是它没有确定的值,没有指向具体的字符数据第74页,共218页。比较的项目字符数组字符指针变量可变性 数组
58、名为常量,其值不可变字符指针变量为变量,其值可变,可以参加运算运算效率数组元素下标的计算需要转换为指针后计算, 如,ai要转换为*(a+i),效率较低直接使用指针计算,效率较高 第75页,共218页。 6.5 指针数组 6.5.1 指针数组的一般定义形式由若干个指向同类型对象的指针数据可以组成一个数组,称为指针数组。其中每个数组元素都是指针变量。就是说,指针数组的所有数组元素都必须是具有相同存储类型和指向相同数据类型的指针变量,指针数组的每个数组元素的值均为指针。指针数组的一般定义形式为:类型名 *数组名数组大小; 例如,int *pa10;第76页,共218页。例如,int *pa10; 因
59、为*比 优先级低,所以pa先要与10结合成为pa10的数组形式,它有10个数组元素;然后再与前面的int *结合来表示数组元素的类型是指向整型变量的指针,就是说,每个数组元素都可以指向一个整型变量。或者说,pa是一个指针数组,它有10个数组元素,并且每个数组元素的值都是一个指针,都指向整型的变量。请注意,不要把定义指针数组与定义指向含有若干数组元素的指针变量相混淆。 int (*pa)10; /* 表示定义一个指向含有10个数组元素的一维数组的指针变量*/ 第77页,共218页。指针数组处理字符串问题(如排序或查找)是指针数组的重要应用之一。例如,如果对多个字符串进行排序,一种方法是可以利用二
60、维数组来处理。如char dimMN形式,其中M代表行数(即多个字符串的个数),N代表列数(即最长的字符串的长度)。在实际应用中,由于各个字符串的长度通常是不相等的,它们往往都小于N,按照最长的字符串的长度来定义N就会造成该二维数组占用内存单元的存储空间浪费。并且采用一般的排序方法,需要逐个比较字符串以便交换字符串的物理位置(交换是通过字符串复制函数strcpy完成的)。多次的位置交换要耗费大量处理时间又使程序执行速度变慢。第78页,共218页。例如,下图表示利用二维数组来处理字符串的时候,按照最长的字符串的长度来定义N会造成该二维数组占用内存单元存储空间的浪费(即0后面的部分存储空间)。 P
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度平菇香菇线上线下销售渠道拓展合同
- 2025年度二手房买卖合同交易手续办理指南
- 2025年度文化创意产业项目合作开发合同4篇
- 2025年度宁夏粮食和物资储备局粮食储备库安全管理合同4篇
- 二零二五年度高品质木箱纸箱租赁经营合同3篇
- 二零二五年停薪留职员工绩效管理合同
- 二零二五年度床上用品电商平台合作推广合同2篇
- 江苏省村卫生室人员合理用药培训
- 二零二五年度民政局认证离婚协议书范本
- 二零二五年度林地使用权租赁合同范例3篇
- 《榜样9》观后感心得体会四
- 2023事业单位笔试《公共基础知识》备考题库(含答案)
- 化学-广东省广州市2024-2025学年高一上学期期末检测卷(一)试题和答案
- 2025四川中烟招聘高频重点提升(共500题)附带答案详解
- EHS工程师招聘笔试题与参考答案(某大型央企)2024年
- 营销策划 -丽亭酒店品牌年度传播规划方案
- 2025年中国蛋糕行业市场规模及发展前景研究报告(智研咨询发布)
- 润滑油过滤培训
- 护理组长年底述职报告
- 浙江省绍兴市2023-2024学年高一上学期期末考试物理试题(含答案)
- 2013年6月22日下午湖北省公务员国家安全局面试真题
评论
0/150
提交评论