1 / 37

《 C 语言程序设计》

《 C 语言程序设计》. 第 8 讲. 第 8 章 指针. 目标要求. 掌握指针的概念、定义。 掌握指针变量的使用。 掌握指针在函数中的运用。 掌握指针的运算。 掌握指针在数组中的运用。. 第 8 章 指针. 讲课提纲. 概述 指针的定义 指针变量作函数参数 指针在数组中的运用 指针其他用法 典型实例剖析 小结 课后作业. 第 8 章 指针. 8.2 指针的定义. 8.2.1 地址的概念 8.2.2 指针的定义 8.2.3 指针变量的操作 8.2.4 指针用法小结. 第 8 章 指针.

nelly
Télécharger la présentation

《 C 语言程序设计》

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 《 C语言程序设计》 第 8 讲

  2. 第8章指针 目标要求 • 掌握指针的概念、定义。 • 掌握指针变量的使用。 • 掌握指针在函数中的运用。 • 掌握指针的运算。 • 掌握指针在数组中的运用。

  3. 第8章指针 讲课提纲 • 概述 • 指针的定义 • 指针变量作函数参数 • 指针在数组中的运用 • 指针其他用法 • 典型实例剖析 • 小结 • 课后作业

  4. 第8章指针 8.2 指针的定义 8.2.1 地址的概念 8.2.2 指针的定义 8.2.3 指针变量的操作 8.2.4 指针用法小结

  5. 第8章指针 8.1 概述 指针的本质就是地址,指针变量是一种专门用来在存储器中存储地址的特殊变量。在第6章函数中,已提到访问某个数其实质是先找到存放这个数的存储单元(地址),然后再找到这个地址中所存储的数。有了指针这一概念后,就可以先使指针变量指向某个变量的地址,然后通过对指针的操作实现对这个变量的操作。这种操作尤其对数组、结构体等复杂数据类型时非常简便。引入指针后: • 可以使程序简洁化、紧凑化和高效化。 • 为函数之间提供了简洁而便利的参数传递方法。 • 可以实现动态分配存储空间。 • 可以使程序员浏览整个内存空间从而能够改变内存中的数据。

  6. 第8章指针 8.2.1 地址的概念 计算机中的地址与我们现实生活中的地址非常相似。例如,在一幢学生宿舍里,每1个房间都有1个编号,以便于别人访问该房间里居住的同学;在计算机的内存中,每1个存储单元(1个字节的存储空间)同样也有1个编号,以便于计算机访问该内存单元中的数据,这个编号就是存储单元的地址。在内存单元中存储的数据就像房间里居住的学生,通过房间门牌号码可以找到该房间居住的学生,同样,通过内存单元的地址可以实现对存储在该单元中数据的读写操作。

  7. 第8章指针 8.2.2 指针的定义 • 指针的定义格式: 既然指针变量是一种特殊的变量,因此在使用之前也必须先定义。指针的定义格式如下: 指针类型 *指针变量名; • 对指针定义作以下说明: • 指针类型是指指针所指向变量中存放数据的类型。 • 指针变量名是指针的名字,它遵循标识符的命名规则。 • “*”符号可以靠近定义中任何1个部分,甚至也可以独立地放在中间,在这里“*”主要起一个标识作用,用于说明定义的变量为指针变量。

  8. 第8章指针 8.2.2 指针的定义 • 应用举例: • 定义1个指向整型变量的指针变量p: int *p; • 定义1个指向实型变量的指针变量q: float *q; • 定义1个指向字符型变量的指针变量point: char *point; • 此外,我们还可以同时定义多个相同类型的指针,例如: int *p,*q;

  9. 第8章指针 8.2.3 指针变量的操作 (1)取地址运算符“&” (2)将变量地址赋给指针 (3)取内容运算符“*” (4)除了给指针赋1个确定的地址外还可以为1个指针赋1个“空”值,这时该指针并没有指向1个确定的地址,例如: • p=NULL; • 或者: • p=’\0’; • 或者: • p=0;

  10. 第8章指针 8.2.3 指针变量的操作 (5)在C语言中,虽然在定义1个变量后系统就为该变量在内存中分配了一定大小的存储空间。但究竟此单元的地址是多少,用户是很难知道的。其实,在实际的操作中,通常并不需要知道1个变量在内存中的地址编号是多少,在程序中只需用相应的表达式表示出1个变量的地址即可,例如使用语句: “p=&a;q=&b;”

  11. 第8章指针 8.2.4 指针用法小结 • 指针变量的值就是它所指向的目标变量的地址值,换言之,指针变量所存储的不是1个普通的数据值,而是1个变量的地址值。指针变量是一种特殊的变量,它首先具有变量的基本属性,要求指针变量在使用之前必须先定义。 • 指针类型通常是指指针指向的目标变量的类型,即要处理数据的类型。不过习惯上将指针指向变量的类型称为指针的数据类型。 • 指针是一种功能强大同时又具有潜在危险的工具,在使用时务必小心。其中必须注意的1个重要问题就是指针必须在定向后才能使用,否则会出现严重错误。指针定向是指在定义1个指针变量后将其指向1个特定的变量。

  12. 第8章指针 8.2.4 指针用法小结 • 1个未被定向的指针可以随机指向内存中的1个空间,使用未定向的指针可能导致对不可预知的数据空间中数据的改写,甚至导致系统崩溃。可以通过给指针变量赋初值的方法为指针定向。 • 尽管指针可以指向不同数据类型的变量,但是各种指针变量自身所占的存储空间的大小都是相同的。这是因为指针存储的是地址量,而任何变量的地址都是使用1个存储单元的地址来表示(1个字节),大于1个字节长度的变量的地址使用首地址表示。因此,指针的数据长度仅仅与计算机硬件有关,而与指向的数据类型无关。这是指针变量特殊性的表现。 • 指针变量特殊性的另1个表现是并不是任何数据都可以赋给指针作为初始值,只能是1个与其类型相符的常量或变量地址,因此可以使用的数据只是1个非常有限的数据集合

  13. 第8章指针 8.3 指针变量作函数参数 • 函数的参数不仅可以是整型、字符型和实型等基本数据类型的变量,还可以是指针类型。使用指针作为函数的参数更能体现函数的特点,增加程序设计的灵活性,增强函数的功能。使用指针作为函数参数实质上是采用地址传递的方式,将1个变量的地址传到另一函数中。 • 和基本函数调用一样,指针应该在使用之前先定义,否则应在使用之前加以声明,否则在执行程序时系统要出现错误提示,程序不能编译通过。 • 不能企图通过改变指针形参的值而使指针实参的值改变,也就是说不能通过修改形参的指向来改变实参指针的指向。C语言中实参变量和形参变量之间的传递是单向的“值传递”方式,指针变量作函数参数也要遵循这一原则。虽然在调用函数时不能改变实参指针变量的值,但可改变实参指针变量所指变量的值,这正是指针参数的优势所在。

  14. 第8章指针 8.4 指针在数组中的运用 • 指针变量不仅可以指向基本类型的变量,也可以指向数组中的元素,在讲述相关内容之前,我们先回顾一下有关数组的定义及其概念。数组实质上是一组变量的有序集合,具有以下特点: • 同1数组中的每个元素的数据类型相同。 • 数组在内存中占有一段连续的存储空间。 • 数组下标是从0开始的自然数。 • 数组名代表数组的首地址,也就是第1个数组元素的地址。

  15. 第8章指针 8.4 指针在数组中的运用 使用指针指向数组 • 例如: • int a[10]; • int *p; • p=a; a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] p

  16. 第8章指针 8.4 指针在数组中的运用 用法说明 • 数组的数据类型应和指针变量的数据类型一致,否则将出现语法错误。 • 语句“p=a;”的作用是把数组a的首地址赋给指针变量p,而不是把数组a的各个元素的值赋给p,a不代表整个数组,而是代表该数组的首地址。因此,以下几种形式的语句是和语句“p=a;”是等效的: p=a+0; 或者:p=&a[0]; • 当然,如果要使指针变量p指向数组中的第3个元素可用以下的几种语句: p=a+2; 或者:p=&a[2]; • 其余类推!

  17. 第8章指针 8.4 指针在数组中的运用 • 与其他变量一样,指针变量也可以在定义的同时完成赋值,程序段“int a[10]; int *p; p=a;”可以等效于下面的程序段: int a[10]; int *p=&a[0]; 或者: int a[10]; int *p=a ;

  18. 第8章指针 8.4 指针在数组中的运用 使用指针访问所指向数组中的元素 • 指针的加减运算。 • 如果用户想要控制指针变量指向数组中其它元素,可以用指针变量的加减运算,它有两种基本形式(其中p代表指针变量,i是1个自然数): • p+i(p-i):获得指针当前指向位置之后(前)i个元素的地址,以实现对该元素的访问,注意此时指针的指向并未改变。 • p++(p--):将指针从当前指向位置后移(前移)1个元素的位置。注意此时指针的指向已经发生改变。

  19. 第8章指针 8.4 指针在数组中的运用 使用指针访问所指向数组中的元素 特别注意:p+i(p-i)不是简单地将p值加(减)i。对于不同的数据类型,它们的含义是不同的。例如:char型指针变量移1个位置是1个字节;int型指针变量移1个位置是2个字节;实型指针变量移1个位置是4个字节。所以,如果指针移动i个存储单元时,它所经过的字节数为: p+i*d 其中,d是一种类型数据对应的存储空间的长度。对于字符型数据“d=1”;对于整型数据“d=2”;对实型数据“d= 4”。

  20. 第8章指针 8.4 指针在数组中的运用 使用指针访问所指向数组中的元素 • 综上所述,“p+i”和“a+i”就是a[i]的地址,或者说它指向数组a的第“i+1”个元素,这里需要强调的是a代表数组的首地址,“a+i”也是地址,“p+i”的计算方法与之相同。所以,“a+4”和“p+4”的值即是&a[4],它们都指向元素a[4]。 • 简单地说,指针加上(或减去)1个整数i就是获得指针当前指向元素前面(或后面)i个元素的地址,这个结论无论指针指向何种类型的数据都成立。

  21. 第8章指针 8.4 指针在数组中的运用 使用指针访问数组元素 • 当指针指向某一数组元素后,通过取内容运算“*”即可获得该指针所指向的数组元素的值。一般地,“*(p+i)”或“*(a+i)”是“p+i”或“a+i”所指向的元素的值,即a[i]。 • 例如,“*(p+5)”或“*(a+5)”就是a[5]。实际上,在编译时,对于“*(a+i)”的处理就是按数组首地址加相对位移量得到要找的元素的地址,然后找出该单元中的内容,假设数组a的首地址为1006,数组为整型,则a[7]单元的地址为1006+7*2 =1020。

  22. 第8章指针 8.4 指针在数组中的运用 • 指向数组的指针变量也可以带下标,如对于以下程序段: int p[10],*x; x=p; 则x[i]也是正确的,它与p[i]是等价的。

  23. 第8章指针 8.4 指针在数组中的运用 使用指针处理字符串。 • 在第7章数组中,我们讲过可以对一个数组赋字符串,其形式如下: char string[]= “I Love China !”; 同样可以对指针做同样的操作,其形式如下: char *string=“I Love China !”; 这两种形式是等效的,系统都是默认数组或指针变量是存放字符串的首地址,它们的存储形式也是相同的,只不过是“一个实质,两种表述而已”。

  24. 第8章指针 8.5 指针其他用法 • 指向指针的指针 指向指针的指针的基本形式如下: ** 指针变量名 • 指向二维数组的指针变量 若有以下程序段: int a[10][10]; int m,n; 并且0≤m≤9,0≤n≤0,则元素a[m][n]可以有以下几种表示方法: • a[m][n] • *(a[m]+n) • *(*(a+m)+n) • (*(a+m))[n] • *(&a[0][0]+10*m+n)

  25. 第8章指针 8.6 典型实例剖析 • 有一个数列为:2/1、3/2、5/3、8/5、13/8、21/13……编写程序求这个数列的前20项之和。 • #include<stdio.h> • void add(int *p,int *q, float *g ) • { • int r; • *g=*g+(float)*q/(*p); /*求某项的值并实现数据的累加*/ • r=*p; /*把前项的分母保存*/ • *p=*q; /*把前项的分子赋给后项的分母*/ • *q=r+*p; /*把前项分母与分子的和赋给新项的分子*/ • }

  26. 第8章指针 8.6 典型实例剖析 • void main( ) • { • int a,b,i; • float x=0.0; • a=1; • b=2; • for(i=0;i<20;i++) • add(&a,&b,&x); • printf("the result is:%f",x); • }

  27. 第8章指针 8.6 典型实例剖析 2.编写程序求1个数组中所有奇数之和以及所有偶数之和。#include<stdio.h> • #include<conio.h> • int n=6; /*定义全局变量n*/ • void fun(int *a,int *odd,int *even) • { • int i; • *odd=0; *赋初值,不能掉了符号“*”*/ • *even=0; /*赋初值,不能掉了符号“*”*/ • for(i=0;i<n;i++) • { • if(*a%2==1) *odd=*odd+*a; /*累加,不能掉了符号“*”*/ • else *even=*even+*a; /*累加,不能掉了符号“*”*/ • a++;/*实现地址的依次后移,注意:a是指针,若是数组则不能这样操作*/ • } • }

  28. 第8章指针 8.6 典型实例剖析 • void main() • { • int a[6],i,odd,even; • clrscr(); • printf(“please input the number to the array:”); • for(i=0;i<n;i++) /*对数组赋值*/ • scanf(“%d”,a+i); • printf(“\nthe original data is:”); • for(i=0;i<n;i++) /*输出数组中的值*/ • printf(“%5d”,*(a+i)); • printf(“\n”); • fun(a,&odd,&even); /*调用函数*/ • printf(“the sum of odd number:%d\n”,odd); • printf(“the sum or even number:%d\n”,even); • }

  29. 第8章指针 8.6 典型实例剖析 3.统计1个长度为2的字符串在另一个字符串中出现的次数 • #include<stdio.h> • #include<conio.h> • #include<string.h> • int fun(char *str,char *substr) • { • int n=0; • while(*str) • { • if(*str==substr[0]&&*(str+1)==substr[1]) • n++; /*出现个数的统计*/ • str++; /*指向长字符串中元素的指针后移*/ • } • return n; • }

  30. 第8章指针 8.6 典型实例剖析 • void main() • { • char str[81],substr[3]; • int n; • printf("please enter the first chars to the array:"); • gets(str); • printf("please enter the second chars to the array:"); • gets(substr); • n=fun(str,substr); • printf("n=%d\n",n); • }

  31. 第8章指针 8.7 小结 • 指针与地址的关系。 简单地说,指针是内存地址的代名词。通过指针(地址)操作,可以对存储单元中的数据实现读写操作。用于存放1个变量地址的特殊变量就是指针变量。 • 指针变量的定义。 指针变量定义的基本形式为: 指针类型 *指针变量名 例如: int *p;

  32. 第8章指针 8.7 小结 • 指针类型。 在指针变量定义中的类型符(int、char、float….)称为指针类型。由于指针代表1个内存单元的地址,程序将要根据此地址读出(或写入)存放在此单元中的数据,因此指针类型实际上表示该地址单元存储数据的类型。 • 指针变量的存储。 指针变量占有固定大小的存储单元。1个地址本质上是整数(或长整数,为简单计,可以认为是整数)。故指针变量都占2个字节的存储空间,与指针类型无关。

  33. 第8章指针 8.7 小结 • 取地址运算。 符号“&”是取变量地址的单目运算符,它直接作用于1个变量前表示该变量的地址,例如,若定义以下变量: float x; char y; 则&x和&y就是这两个变量的内存地址,通常,程序设计者并不关心&x和&y的具体值,只要知道&x和&y是变量x和y的指针就可以了。若在前两个语句后再有1个定义指针变量的语句: float *f1; char *f2; 则可进行以下赋值: f1=&x; f2=&y;

  34. 第8章指针 8.7 小结 这样就使指针变量f1指向变量x所在的地址,f2指向变量y所在的地址。注意,以下的赋值语句是错误的: f1=&y; f2=&x; 错误的原因是:指针基类型与变量的数据类型不一致。

  35. 第8章指针 8.7 小结 • 间接访问变量。 使用取内容运算符“*”可以间接访问1个指针指向的变量,只需要在指针名前加上“*”即可。 • 指针的自加和自减。 指针变量可以进行自加和自减运算,但其含义与普通变量的同种运算不同。若已有定义“float *p”,则: • 表达式p++(p--)将使指针向后(前)移动1个数据的位置。 • p+1指向数组的下1个元素,而不是简单地使指针变量p的值加1。其值实际变化为pointer+1*size(size为一个元素占用的字节数)。例如,假设指针变量pointer的当前值为3000,则pointer+1为3000+1*2=3002,而不是3001。

  36. 第8章指针 8.7 小结 • 指针作函数参数。 在将指针作为函数参数时,一定要保证参数对应。指针是一种可以使我们“绕开”1个变量的名字而存取它的工具或手段,指针本身并没有受间接引用的影响。并且实参和形参指向同一段内存地址,因此在函数调用过程中可修改实参变量的值,还可以从被调函数中获得多个返回值以提高以参数传递效率。

  37. 第8章指针 课后作业 • 将1个字符数组中的字符倒序输出。 • 有1个字符串,包含n个字符,写一函数,将此字符串中第m个字符开始的全部字符复制到1个字符串中。 • 输入10个整数,将其中最小的数与第1个数对换,把最大的数与最后1个数对换,写3个函数∶(1) 输入10个数;(2) 进行处理;(3) 输出10个数。

More Related