C语言程序设计(下)ppt.ppt_第1页
C语言程序设计(下)ppt.ppt_第2页
C语言程序设计(下)ppt.ppt_第3页
C语言程序设计(下)ppt.ppt_第4页
C语言程序设计(下)ppt.ppt_第5页
已阅读5页,还剩213页未读 继续免费阅读

下载本文档

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

文档简介

C语言程序设计(下),第一、二次课 4学时,第六章 指针,第十一次课 2学时,学习目的 1、通过本章的学习使学生掌握指针的意义及使用。 2、应知数组的指针的意义,数组元素的指针的意义,及使用数组名作函数参数,应会通过指针引用数组元素。,学习重点 1.指针的使用 2、指针和数组的关系,学习难点 1.通过指针引用变量的意义 2、指针和数组的关系,3,指针的基本概念,指针变量的定义与引用,指针与数组,为什么要学习指针? 指针是C语言一个重要的概念也是C语言的重要特色。正确灵活的运用指针可以有效地表示负责的数据结构。能动态的分配内存,方便的使用字符串,有效的而方便的使用数组,在调用函数时能获得一个以上的结果,能直接处理内存单元地址等。而这些是设计系统软件非常必要的,掌握指针可以有效的使程序简洁、紧凑、高效。,6.1 指针的基本概念,6.1.1 指针的概念,1.内存及其地址 “程序存储”就是在程序运行之前将程序和数据存入计算机内存。所以在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元,为了正确地访问这些内存单元,必须为每个内存单元编号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。,6.1 指针的基本概念,6.1.1 指针的概念,main() float x; int y; ,变量的两个物理意义,变量的内容,变量的地址,6.1 指针的基本概念,6.1.1 指针的概念,2.变量地址的获取 变量的存储单元是在编译时(对静态存储变量)或程序运行时(对动态存储变量)分配的,因此变量的地址不能人为确定,而要通过取地址运算符 由&a、&b和&c分别得到变量a、b和c的内存地址。值得注意的是,由于常量和表达式没有用户可操作的内存地址,因此&不能作用到常量或表达式上。,6.1 指针的基本概念,6.1.1 指针的概念,3.指针与指针变量 根据内存单元的编号或地址就可以找到所需的内存单元,通常把这个地址称为指针。,在C语言中,专门存放变量(或其它程序实体)地址的变量是指针变量。指针变量也需要存储单元(存放地址值的整数),它本身也有地址。例如让变量p存放整型变量a的地址(如图所示),这样,由变量p的值(地址,图中为1012)就可以找到变量a,因此称变量p指向变量a,变量p就是指针变量,它存放的地址就称为“指针”。因此,指针就是地址。,6.1 指针的基本概念,6.1.1 指针的概念,4.直接访问方式与间接访问方式 有了指针变量以后,对一般变量的访问即可以通过变量名进行,也可以通过指针变量进行。通过变量名或其地址(如a或&a)访问变量的方式叫直接访问方式;通过指针变量(如p)访问它指向的变量(如a)的方式叫间接访问方式。,6.2 指针变量的定义与引用,6.2.1 指针变量的定义与初始化,指针变量的一般定义形式为: 类型名 *标识符; 其中“标识符”是指针变量名,标识符前加“*”号表示该变量是指针变量,用于存放地址,“类型名”表示该指针变量所指向变量的类型。,6.2 指针变量的定义与引用,6.2.2 指针变量的赋值,通过地址运算“ 这两条语句。,6.2 指针变量的定义与引用,6.2.2 指针变量的赋值,通过其它指针变量赋值 可以通过赋值运算符,把一个指针变量的地址值赋给另一个指针变量,这样两个指针变量均指向同一地址。 用NULL给指针变量赋空值 除了给指针变量赋地址值外,还可以给指针变量赋空值,如 p=NULL;,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)。,6.2 指针变量的定义与引用,6.2.3 指针的运算及引用,2.指向运算和指针变量的引用 (1) 指向运算符* *运算符作用在指针(地址)上,代表该指针所指向的存储单元(及其值),实现间接访问,因此又叫“间接访问运算符”。如: int a=5, *p; p=&a; printf(“%d“,*p); *p的值为5与a等价。 *运算符为单目运算符,与其他的单目运算符具有相同的优先级和结合性(右结合性)。根据*运算符的作用,*运算符和取地址运算符 & 互逆: *(&a)=a &(*p)=p 注意,在定义指针变量时,“*”表示其后是指针变量;在执行部分的表达式中,“*”是指向运算符。 (2) 指针变量的引用 知道了指针变量的作用以及相关的运算符以后,我们就可以引用指针变量了。,6.2 指针变量的定义与引用,6.2.3 指针的运算及引用,【例6-1】请理解下列程序中各语句的含义: #include void main( ) int a=10,*p= ,程序运行结果: *p=10 Enter a:15 a=15 p=13ff7c &p=13ff78 a=5 a=6,6.2 指针变量的定义与引用,6.2.3 指针的运算及引用,【例6-2】输入两个整数i1和i2,利用指针将大数存放到i1中,小数存放到i2中,最后按i1、i2的顺序输出。,按题意,定义两个指针变量p1、p2,将i1、i2的地址分别存入p1、p2,当i1i2时利用指针变量p1、p2交换i1、i2的值然后输出。程序如下:,6.2 指针变量的定义与引用,6.2.3 指针的运算及引用,#include void main( ) int i1, i2, *p1, *p2, t; p1= ,Enter two numbers: 5 10 程序运行结果: i1=10,i2=5,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); 可实现从大到小输出。 第二种情况是:在i1i2的情况下,利用三个指针变量的指向操作交换i1、i2的值。问题是:指针变量p没有存放普通变量的地址,因此也是错误的(运行时有警告)。,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); 可实现从大到小输出。 第二种情况是:在i1i2的情况下,利用三个指针变量的指向操作交换i1、i2的值。问题是:指针变量p没有存放普通变量的地址,因此也是错误的(运行时有警告)。,6.2 指针变量的定义与引用,6.2.4 指针作为函数参数,函数的参数可以是我们在前面学过的简单数据类型,也可以是指针类型。使用指针类型做函数的参数,实际向函数传递的是变量的地址。由于函数中获得了所传递变量的地址,在该地址空间的数据当函数调用结束后被物理地保留下来。,6.2 指针变量的定义与引用,6.2.4 指针作为函数参数,【例6-3】利用指针变量作为函数的参数,用函数的方法再次实现上述功能。 #include void main( ) void chang( ); /* 函数声明 */ int *p1,*p2,a,b,*t; scanf(“%d,%d“, ,6.2 指针变量的定义与引用,6.2.4 指针作为函数参数,void chang(int*pt1,int*pt2) /* 函数实现将两数值调整为由大到小 */ int t; if (*pt1*pt2) t=*pt1;*pt1=*pt2;*pt2=t; /* 交换内存变量的值 */ return; ,由于在调用函数时,实际参数是指针变量,形式参数也是指针变量,实参与形参相结合,传值调用将指针变量传递给形式参数pt1和pt2。但此时传值传递的是变量地址,使得在函数中pt1和pt2具有了p1和p2的值,指向了与调用程序相同的内存变量,并对其在内存存放的数据进行了交换,其效果与例6-2相同。,6.2 指针变量的定义与引用,6.2.5 多级指针的概念,按照上述二级指针的思路,显然可以推广到三级指针、四级指针。使用多级指针变量的要点是: 多级指针变量均用基类型定义,定义几级指针变量要将变量名前放几个“*”号; 各指针变量均应取得低一级指针变量的地址后才能引用; 引用几级指针变量访问最终的普通变量时,变量名前需用几个指向运算符“*”号。,6.2 指针变量的定义与引用,6.2.5 多级指针的概念,【例6-4】运行下面的程序 #include void main( ) int *p1,*p2,*p3,*p4,x=10; p1= ,程序运行结果: x=10,6.3 指针与数组,6.3.1 指针与一维数组,一个数组的元素在内存中是连续存放的,数组第一个元素的地址称数组的首地址。在C语言中,数组名是该数组的首地址。例如有以下定义语句: int a10,*p; 则语句p=a;和p=都是非法的。,6.3 指针与数组,6.3.1 指针与一维数组,1通过一维数组名所代表的地址存取数组元素. 假设已定义一维数组a,由上述可知a+i是元素ai的地址,根据指针运算符“*”的运算规则知 *(a+i) 与元素 ai等价。例如,下述程序段: int a =1, 2, 3, 4, 5, 6, 7, 8, 9, 10; *(a+5)=50; /* 相当于a5=50 ; */ scanf(“%d“, /* 相当于printf(“%dn“, a5) ) */,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, 5, 6, 7, 8, 9, 10, *p=a; *(p+5)=50; /* 相当于a5=50 ; */ scanf(“%d“, /* 相当于printf(“%dn“, a5) ) */,6.3 指针与数组,6.3.1 指针与一维数组,3通过带下标的指针变量存取数组元素 语言中的下标运算符“ ”可以构成表达式,假设p为指针变量,i为整型表达式,则可以把pi看成是表达式,首先按p+i计算地址,然后再存取此地址单元中的值。因此pi与*(p+i)等价。例如,下述程序段: int a =1, 2, 3, 4, 5, 6, 7, 8, 9, 10, *p=a; p5=50; /* 相当于a5=50 ; */ scanf(“%d“, /* 相当于printf(“%dn“, a5) ) */,6.3 指针与数组,6.3.2 指针与二维数组,1.二维数组的地址表示法 C语言规定,二维数组由一维数组扩展形成,即一维数组的每一个元素作为数组名形成一行数组,各行数组的元素个数相同,是二维数组的列数。例如定义了二维数组int a34,它是由一维数组int a3扩展形成,即以a0、a1、a2为数组名(首地址)形成三行一维数组,元素个数均为列数4。因此a0、a1、a2为一级指针常量,指向各行的首列(列指针)。例如0行的a0=&a00指向0行0列。0行有四个元素,它们是a00、a01、a02、a03。 另外a0、a1、a2又是数组名为a的一维数组的三个元素,首地址a=&a0指向的“元素”为一级指针常量,因此a为二级指针常量,指向0行(行指针)。,6.3 指针与数组,6.3.2 指针与二维数组,【例6-5】输出二维数组的有关值,程序编写如下,注意理解各语句的含义。 #include void main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12; printf(“%u,%un“,a, *a); /* 0行首地址和0行0列首地址 */ printf(“%u,%un“,a+1, *a+1); /* 1行首地址和0行1列首地址*/ printf(“%u,%un“,a, /* 1行2列的元素7 */ ,程序运行结果: 1310544,1310544 1310560,1310548 1310544,1310544 1310560,1310560,1310560 7,7,7,6.3 指针与数组,6.3.2 指针与二维数组,2.用于二维数组的指针变量 (1) 指向数组元素的指针变量(一级指针变量):将二维数组当成一维数组访问。,6.3 指针与数组,6.3.2 指针与二维数组,【例6-6】用一级指针变量输出二维数组的全部元素。 #include void main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12,i,j,*p; p=a0; /* 指针变量必须得到首元素地址a0或*a或 ,程序运行结果: 1 2 3 4 5 6 7 8 9 10 11 12,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个元素的整型一维数组,而不是指向一个元素,因此它是二级指针变量(行指针变量),可以移动。指向一维数组的指针变量的一般定义形式为: 类型 (*指针变量名)一维数组元素个数;,6.3 指针与数组,6.3.2 指针与二维数组,【例6-7】输出二维数组任意行任意列的元素值。 定义指向一维数组的指针变量,按照上面的说明表示二维数组任意行任意列的元素,程序如下: #include void 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“, ,程序运行结果:a23=12,Enter arbitrary number of row and column: 2,3,6.3 指针与数组,6.3.3 数组指针作函数的参数,【例6-8】调用函数,实现求解一维数组中的最大元素。 我们首先假设一维数组中下标为0的元素是最大和用指针变量指向该元素。后续元素与该元素一一比较,若找到更大的元素,就替换。sub_max()函数的形式参数为一维数组,实际参数是指向一维数组的指针。,6.3 指针与数组,6.3.3 数组指针作函数的参数,#include void main( ) int sub_max( ); /* 函数声明 */ int n,a10,*ptr=a; /* 定义变量,并使指针指向数组 */ int max; for (n=0;n=9;n+) /* 输入数据 */ scanf(“%d“, ,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()函数内数组元素的表示采用下标法。,6.3 指针与数组,6.3.3 数组指针作函数的参数,#include void main( ) int sub_max( ); int n,a10,*ptr=a; int max; for (n=0;n=9;n+) scanf(“%d“, ,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;,6.3 指针与数组,6.3.3 数组指针作函数的参数,在sub_max()中,形式参数是指针,调用程序的实际参数ptr为指向一维数组a的指针,虚实结合,sub_max()的形式参数b得到ptr的值,指向了内存的一维数组。数组元素采用下标法表示,即一维数组的头指针为b,数组元素可以用bj表示。 程序输入数据:1 3 5 6 89 1 2 56 23 78 程序运行结果:max=89,6.3 指针与数组,6.3.3 数组指针作函数的参数,上述程序的函数中,数组元素还可以用指针表示,int sub_max(b,i) /* 函数定义 */ int *b,i; int temp,j; temp=*b+; for (j=1;j=i-1;j+) if(temp*b) temp=*b+; return temp; ,6.3 指针与数组,6.3.3 数组指针作函数的参数,【例6-8】用指向数组的指针变量实现一维数组的由小到大的冒泡排序。编写三个函数用于输入数据、数据排序、数据输出。,6.3 指针与数组,6.3.3 数组指针作函数的参数,#include #define N 10 void main( ) void input( ); /* 函数声明*/ void sort( ); void output( ); int aN,*p; /* 定义一维数组和指针变量 */ input(a,N); /* 数据输入函数调用,实参a是数组名 */ p=a; /* 指针变量指向数组的首地址 */ sort(p,N); /* 排序,实参p是指针变量 */ output(p,N); /* 输出,实参p是指针变量 */ ,6.3 指针与数组,6.3.3 数组指针作函数的参数,void input(arr,n) /*无需返回值的输入数据函数定义,形参arr是数组*/ int arr ,n; int i; printf(“input data:n“); for (i=0;in;i+) /* 采用传统的下标法 */ scanf(“%d“, ,void sort(ptr,n) /* 冒泡排序,形参ptr是指针变量 */ int*ptr,n; int i,j,t; for (i=0;i*(ptr+j+1) /* 相临两个元素进行比较 */ t=*(ptr+j); *(ptr+j)=*(ptr+j+1); *(ptr+j+1)=t; /*两个元素进行交换*/ ,6.3 指针与数组,6.3.3 数组指针作函数的参数,void output(arr,n) /* 数据输出 */ int arr ,n; int i,*ptr=arr; /* 利用指针指向数组的首地址 */ printf(“outputdata:n“); for(; ptr-arrn; ptr+) /* 输出数组的n个元素 */ printf(“%4d“,*ptr); printf(“n“); ,6.3 指针与数组,6.3.3 数组指针作函数的参数,【例6-10】用指向二维数组的指针作函数的参数,实现对二维数组的按行相加。,#include #define M 3 #define N 4 void main( ) float aMN; float score1,score2,score3,*pa=a0; /* 指针变量pa指向二维数组 */ /*score1,score2,score3分别记录三行的数据相加*/ int i,j; void fun(); for(i=0;iM;i+) /* 二维数组的数据输入 */ for(j=0;jN;j+) scanf(“%f“, /*函数调用,不仅传递数组首地址,也传递变量的地址*/,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行的数据相加 */ if(i=2) *p3=*p3+bij; /* 第2行的数据相加 */ ,6.3 指针与数组,6.3.3 数组指针作函数的参数,程序中与形式参数p1、p2和p3相对应的是实际参数&score1、&score2和&score3,其实际含义为p1=&score1等,即将变量的地址传递给指针变量达到按行相加。,程序输入数据: 1 3 5 9 34 56 78 89 76 65 43 21,程序运行结果: 18.00,257.00,205.00,本次课学习小结,1.指针的基本概念 2.指针变量的定义与引用 3.指针与数组,1.地址与指针变量的概念,地址运算符与间址运算符。 2.一维。二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的定义。通过指针引用以上各类型数据。 3.用指针作函数参数。 4.返回地址值的函数。 5.指针数组,指向指针的指针。,本次课等级考试考点,练习:等级考试真题,一、选择题:(2007年9月份考题) (33)若有定义语句:int a23,*p3; ,则以下语句中正确的是 A)p=a; B)p0=a; C) p0= 答案:C,练习:等级考试真题,二、填空题:(2007年4月份考题) (15) 以下程序的功能是:利用指针指向三个整型变量,并通过指针运算找出三个数中的最大值,输出到屏幕上,请填空: Main() int x,y,z,max,*px,*py,*pz,*pmax; Scanf(“%d%d%d”, ,*pmax=*px,三、填空题:(2007年9月份考题填空题),练习:等级考试真题,(11) 以下程序的输出结果是_. #include #include char *fun(char *t) char *p=t; return(p+strlen(t)/2); main() char *str=“abcdefgh“; str=fun(str); puts(str); ,efgh,练习:,本次课作业: 习题集:第六章 选择题:1、2、3、4 填空题:1、2、3、4、5 改错题:1、2 编程题:1、2,第6章 指针 6.4 指向字符串的指针变量 6.5 指针数组 6.6 指针数组作main函数的形参 6.7 指向指针的指针变量,第十二次课 2学时,学习目的 1.了解字符串的表示形式 2.掌握字符串作函数参数和字符指针变量与字符数组的区别 3.了解指针数组的一般定义形式 4.掌握指针数组的应用 5.了解带参数的main函数的一般形式 6.掌握命令行参数的应用 7.了解指向指针的指针变量的一般定义形式 8.掌握指向指针的指针变量的应用,学习重点 1.指向字符串的指针变量的定义、赋值和使用 2.指针数组 3.指向指针的指针变量,学习难点 1.字符串的指针作函数参数 2.指针数组作函数参数,56,指针,字符串的表示形式,字符串作函数参数,字符指针变量与字符数组的区别,指针数组的一般定义形式,命令行参数的应用,指向指针的指针变量的一般定义形式,指针,指针数组的应用,带参数的main函数的一般形式,指向指针的指针变量的应用,6.4 指向字符串的指针变量 6.4.1 字符串的表示形式,字符串是特殊的常量,它一般被存储在一维的字符数组中并且以0结束。字符串与指针也有着密切的关系。 在C语言程序中,可以采用两种方法来实现访问一个字符串:其中一种方法是采用字符数组,另一种方法是采用字符指针。 在字符串的处理中,使用字符指针比使用字符数组更方便。,程序运行输出结果: Beijing Olympics Beijing Olympics,(1)定义一个字符数组,并且将一个字符串存放在字符数组中, 以空字符0结束。 【例6-11】定义一个字符数组,然后通过下标和数组名引用字符或 字符串。 #include void main( ) char string =“Beijing Olympics“; /*定义字符数组并且初始化*/ int i; for(i=0; stringi!=0; i+) /*逐个选取字符数组中的所有数组元素*/ printf (“%c“, stringi); /*通过下标每次输出一个字符*/ printf(“n“); printf(“%sn”,string); /*从数组名string指向的元素开始,输出 字符串到0为止*/,在【例6-11】中string是存放给定字符串的数组名,它代表字符数组第0号数组元素的地址。 在C语言中规定,数组名代表数组的首地址,也就是数组中第0号数组元素的地址 (即指向该数组第0号数组元素的指针)。 所以将字符串存储在一个数组中以后,就可以通过该数组名对它进行存取。由于string+i是一个地址,则*(string+i)表示其内容,它与代表数组元素的stringi等价。,程序运行输出结果: Beijing Olympics,(2)定义一个字符指针变量,并且将字符指针指向一个字符串常量。 【例6-12】定义一个字符指针,然后通过它引用字符串。 #include void main( ) char *string=“Beijing Olympics”; /* 定义字符指针变 量并且指向一个字符串 */ printf(“%sn“,string); /* 输出字符串 */ ,注意,在对字符指针变量string赋初值为字符串常量时,并不是把整个字符串的内容都赋给该字符指针变量,而仅仅是把该字符串在内存单元的首地址(即第一个字符的地址)赋给该字符指针变量,这样就可以将字符指针指向字符串的第一个字符。 在C语言中,对字符串常量的存放是按静态字符数组处理的。就是说,在内存中分配给字符数组一片连续的存储单元用来存放该字符串常量。一般情况下,每一个字符占用一个字节的存储单元。在内存中,由于字符串的最后被自动填加了一个0,所以使用字符指针变量来处理字符串的时候就很容易判断字符串的终止位置。,对于使用字符指针变量处理字符串的情况,在输出字符串 时要使用“%s”格式符,输出项中要给出字符指针变量名,这 样,计算机就先输出字符指针变量所指向字符串的第一个字 符,然后字符指针变量自动加1而指向字符串的下一个字符,接 着再输出该字符,重复上述操作直到遇到字符串结束标志 0为止。所以,虽然一个数值型数组不能使用数组名来输出该 数组的全部元素,而只能逐个元素进行输出;但是使用字符数 组名或者字符指针变量却可以整体输出一个字符串。 为便于理解,程序可以如下编写: #include void main( ) char string =“Beijing Olympics“; /* 定义字符数组并且初始化 */ char *p=string; /* 定义字符指针变量p并且赋值为字符 串首地址string */ printf(“%sn“, p); /* 输出字符串 */,程序运行输出结果: 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)=*(string1+i); /* 将string1数组中的字符串复制到string2数组 */ *(string2+i)=0; printf(“string1 is:%sn“, string1); printf(“string2 is:“); for(i=0; string2i!=0;i+) printf(“%c“, string2i); /* 输出字符串 */ ,在【例6-13】for循环中,首先判断string1i(此处以( string1+i)的地址形式表示)是否为0。假如不为0,则将string1i的值赋给string2i(此处以*( string 2+i)的地址形式表示),完成一个字符的复制。 ,重复上述操作,将string1数组中字符串全部都复制给string2数组直到string1i(以*( string1+i)的地址形式表示)遇到0为止。 最后要将0复制给string2数组。,程序运行输出结果: 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; /* 定义字符指针变量 */ 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); /* 输出字符串 */ ,在【例6-14】中,首先定义p1和p2是指向字符型数据的指针变量。然后使字符指针变量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。,使用地址传递的方法(即用字符数组名作函数参数或者用指向字符串的指针 变量作函数参数)可以将一个字符串从一个函数传递到另一个函数。 【例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(string1, string2); /*调用函数,实参为字符数组 */ printf(“nstring1 is : %sn “, string1); ,6.4.2 字符串作函数参数,程序运行输出结果: string1 is : computerlanguage,void string_catenate(char from , char to ) /* 字符串连接函数,形参为字符数组 */ int i=0,j=0; while(fromi!=0) i+; /* 将指针移动到字符串的尾部 */ while(toj!=0) fromi=toj; i+, j+; /* 将to数组中字符串连接到from数组中字符串的尾部 */ fromi=0; ,【例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 string2 to string1:n “); string_catenate(string1, string2); /* 调用函数,实参为字符指针变量 */ printf(“nstring1 is : %sn“ , string1); ,程序运行输出结果: string1 is : computerlanguage,void string_catenate(char *from, char *to) /* 字符串连接函数,形参为字符指针变量 */ for( ; *from!=0; from+) ; /* 空循环体,将指针移动到字符串的尾部 */ for( ; *to !=0; from+, to+) *from=*to; /* 将to指向的字符串连接到from指向的字符串的尾部 */ *from= 0; ,数组名、字符指针变量既可以作函数的实参,也可以作函 数的形参,归纳起来有如下几种情况。 表6-2 字符数组名、字符指针变量作函数参数的4种组合,6.4.3 字符指针变量与字符数组 的区别 使用字符数组和字符指针变量都可以实现字符串的存储和运算, 两种方式有相同之处,但也是有区别的。,6.5 指针数组 6.5.1 指针数组的一般定义形式,由若干个指向同类型对象的指针数据可以组成一个数组,称为指针数组。其中每个数组元素都是指针变量。就是说,指针数组的所有数组元素都必须是具有相同存储类型和指向相同数据类型的指针变量,指针数组的每个数组元素的值均为指针。 指针数组的一般定义形式为: 类型名 *数组名数组大小; 例如,int *pa10;,例如,int *pa10; 因为*比 优先级低,所以pa先要与10结合成为pa10的数组形式,它有10个数组元素;然后再与前面的int *结合来表示数组元素的类型是指向整型变量的指针,就是说,每个数组元素都可以指向一个整型变量。或者说,pa是一个指针数组,它有10个数组元素,并且每个数组元素的值都是一个指针,都指向整型的变量。 请注意,不要把定义指针数组与定义指向含有若干数组元素的指针变量相混淆。 int (*pa)10; /* 表示定义一个指向含有10个数组元素的一维数组的指针变量*/,指针数组处理字符串问题(如排序或查找)是指针数组的重要应用之一。 例如,如果对多个字符串进行排序,一种方法是可以利用二维数组来处理。如char dimMN形式,其中M代表行数(即多个字符串的个数),N代表列数(即最长的字符串的长度)。在实际应用中,由于各个字符串的长度通常是不相等的,它们往往都小于N,按照最长的字符串的长度来定义N就会造成该二维数组占用内存单元的存储空间浪费。并且采用一般的排序方法,需要逐个比较字符串以便交换字符串的物理位置(交换是通过字符串复制函数strcpy完成的)。多次的位置交换要耗费大量处理时间又使程序执行速度变慢。,例如,下图表示利用二维数组来处理字符串的时候,按照最长的字符串的长度来定义N会造成该二维数组占用内存单元存储空间的浪费(即0后面的部分存储空间)。,另一种方法是采用指针数组,它可以解决上述问题。 首先定义一些字符串,再把这些字符串的首地址存放在一个字符指针数组中(即把字符指针数组的各个数组元素分别指向各个字符串)。当对字符串排序而需要交换两个字符串时,只要交换字符指针数组中对应两个数组元素的值(为指向对应字符串的首地址)即可,也就是通过改变指针数组中相应数组元素的指向就可以实现排序目的,而不必交换具体的字符串本身,不必移动字符串的物理位置,这样将大大减少时间的开销,能提高运行效率,同时节省了存储空间。,6.5.2 指针数组的应用,【例6-17】将世界十大奇迹文明遗址(埃及金字塔、宙斯神像、法洛斯灯塔、巴比伦空中花园、阿提密斯神殿、罗得斯岛巨像、毛索洛斯墓庙、中国万里长城、亚历山卓港、秦始皇兵马俑)按照英文字母递增方式排序。 世界十大奇迹文明遗址(英文) “Pyramids of Egypt“, “Statue of Zeus“, “Lighthouse of Pharos “, “Hanging Gardens of Babylon“, “Temple of Artemis “, “Colossus of Rhodes“, “Mausolus Tomb Temple “, “Great Wall of China “, “Alexandria Port “, “Qin Shihuang Terracotta Army“;,#include #include void main( ) void bubble_sort(char *name ,int n); void print(char *name ,int n); char *ruins_name =“Pyramids of Egypt“,“Statue of Zeus“, “Lighthouse of Pharos “, “Hanging Gardens of Babylon“, “Temple of Artemis “, “Colossus of Rhodes“, “Mausolus Tomb Temple “, “Great Wall of China “, “Alexandria Port “, “Qin Shihuang Terracotta Army“; int m=10; bubble_sort(ruins_name, m); print(ruins_name, m); ,void bubble_sort(name, n) /* 冒泡法排序 */ char *name ; int n ; char *temp; int i,j; for(i=0;i0) temp=namej; namej=namej+1; namej+1=temp; /*交换字符串的地址*/ void print(name, n) /* 将排序后的字符串进行输出 */ char *name ; int n; int i; for(i=0;in;i+) printf(“%sn“,namei); ,在程序的main主函数中,定义了字符指针数组ruins_name并作了初始化赋值,使得每个数组元素的初值分别为各个字符串的首地址。 函数bubble_sort使用冒泡法来完成排序,其形参n为字符串的个数,另一形参name为指针数组,接受实参传递过来的ruins_name指针数组的首地址(即指向待排序各字符串的数组的指针),所以实参指针数组ruins_name和形参指针数组name就共占同一段内存单元,这样对形参指针数组name中元素排序后,就相当于对实参指针数组ruin

温馨提示

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

评论

0/150

提交评论