第7章指针(1).ppt_第1页
第7章指针(1).ppt_第2页
第7章指针(1).ppt_第3页
第7章指针(1).ppt_第4页
第7章指针(1).ppt_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

1、Chap 7 指针,指针的概念 指针参数 数组的指针表示 指针数组 函数的指针 指针函数 指针相关运算,本章要点,变量、内存单元和地址之间是什么关系? 如何定义指针变量,怎样才能使用指针变量? 什么是指针变量的初始化? 指针变量的基本运算有哪些?如何使用指针操作所指向的变量? 指针作为函数参数的作用是什么? 如何使用指针实现函数调用返回多个值? 如何利用指针实现内存的动态分配?,1.指针简介,内存,10,int x,ED53,地址,变量,数据,ED53,int *ptr_x= int *p= p中存的是a的地址, p 是整型指针,指向整型变量 float *fp; fp 是浮点型指针,指向浮点

2、型变量 char *cp; cp 是字符型指针,指向字符型变量,类型名 * 指针变量名,指针声明符,2.声明并初始化指针变量,类型名 * 指针变量名 int * p; 指针变量名是 p,不是*p * 是指针声明符,值为NULL的指针称为空指针,这意味着,指针并不指向任何地址。 在头文件 stdio.h 中,NULL 定义为常量0。,2.声明并初始化指针变量,int k, *p1=NULL; 等价于: int k; int *p1; P1=NULL;,3.与指针相关的运算符,int num, *ptrnum; ptrnum = ,取地址符,指针,FF7C, ptrnum = ,间接运算符,15,

3、*,直接访问:通过变量名访问, 如 num=15;,间接访问:通过另一个变量访问 把变量num的地址放到另一变量中ptrnum 使用时先找到后者 ptrnum 再从中取出前者num的地址,对其操作 *ptrnum=15; 通过ptrnum找到FF7C,把15存入其中,*p1 *p2,int a = 3, *p1, *p2; p1 = p2 也指向 a,相同类型的指针才能相互赋值,3.与指针相关的运算符,赋值运算,4.指针的特点,指针变量的命名规则和其他变量的命名规则一样 指针不能与现有变量同名 指针可存放 C 语言中的任何基本数据类型、数组和其他所有高级数据结构的地址 若指针已声明为指向某种类

4、型数据的地址,则它不能用于存储其他类型数据的地址 应为指针指定一个地址后,才能在语句中使用指针,# include int main (void) int a = 3, *p; p = ,例7-1 指针取地址运算和间接访问运算,a = 3, *p = 3 a = 10, *p = 10 Enter a: 5 a = 5, *p = 5 a = 6, *p = 6,指针变量p指向a, *p是通过a的地址间接访问a,(1) 当 p = 指针p所指向的变量,即a (3) p = ,练习: 以下程序的输出结果 #include int main() int a=1, x,y, *p; p = ,y,x

5、,1,2,2,练习: 以下程序的输出结果 #include int main() int a=1, x,y, *p; p = ,y,x,1,+写在p后面,p先参与运算a=*p,最后自增1,FF80,?,因为一个int数据占四个字节,故p=p+1,指向下一个整数,后移四个字节FF7C+4=FF80,例7-2 输入a和b两个整数,让指针变量p1指向较小的数,p2指向较大的数(不能改变a,b的值),解题思路: (1)定义a,b,p1,p2; (2)让p1指向a,p2指向b (3)若ab 则p1与p2互换内容 (4)输出*p1和*p2,#include int main() int a,b,*p1,*

6、p2,*pt; p1= ,例7-2 源程序,例7-3 输入a和b两个整数,让指针变量p1指向a,p2指向b, 通过p1和p2改变a和b的值,(不允许直接访问a,b), 使得a中存小数,b中存大数,解题思路: (1)定义a,b,p1,p2; (2)让p1指向a,p2指向b (3)若ab 则a与b互换内容 (4)输出*p1和*p2,若*p1*p2 则*p1与*p2互换,#include int main() int a, b, t, *p1, *p2; p1= ,例7-3 源程序,通过p1,p2间接访问并改变a,b,if(ab) t=a; a=b; b=c; ,对指针的操作 / 对指针所指向变量的

7、操作,*p1 和 *p2 的值都由 5 和 3 变成了3 和 5 (1) 直接改变指针的值 (2) 改变指针所指变量的值,课堂练习,下列程序段的输出结果是 。 int *p, *q, j=10,k = 5; p= A、5 B、6 C、10 D、11, t=x;x=y;y=t; int main() int a=3, b=5; swap(a,b); printf(%d %dn,a,b); return 0; ,运行结果: 3 5,例7.4a: 以下程序不能实现a、b值的互换,形参变量值的改变不会影响实参,#include void swap( int *pa, int *pb) int t; t

8、=*pa; *pa=*pb;*pb=t; int main() int a=3, b=5; swap( ,运行结果: 5 3,例7.4b: 以下程序可以实现a、b值的互换,*pa,*pb,借助变量t,*pa与*pb内容互换,通过形参指针变量间接访问并改变了a,b的值,#include void swap( int *pa, int *pb) int *t; t=pa; pa=pb; pb=t; int main() int a=3, b=5; swap( ,运行结果: 3 5,例7.4c: 以下程序不能实现a、b值的互换,函数调用结束时,x,y被释放,形参指针变量值的改变不会影响实参,指针作为

9、函数参数,要通过函数调用来改变主调函数中某个变量的值: (1) 在主调函数中,将该变量的地址或者指向该变量的指针作为实参 (2) 在被调函数中,用指针类型形参接受该变量的地址 (3) 在被调函数中,改变形参所指向变量的值,通过指针实现函数调用返回多个值,例7.5 输入年和天数,输出对应的年、月、日。 例如:输入2000和61,输出2000-3-1。 定义函数month_day(year, yearday, *pmonth, *pday) 用2个指针作为函数的参数,带回2个结果 int main (void) int day, month, year, yearday; void month_d

10、ay(int year,int yearday, int *pmonth,int *pday); printf(“input year and yearday: ”); scanf (%d%d, ,例7.5,void month_day ( int year, int yearday, int * pmonth, int * pday) int k, leap; int tab 213 = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 , 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ,

11、 ; /* 建立闰年判别条件leap */ leap = (year%4 = 0 ,input year and yearday: 2000 61 2000-3-1,练习,定义一个函数max_min,求一个数组的最大值和最小值,函数原型如下: void max_min(int a,int n,int *maxp,int *minp) 在主函数中读入n和n个整数,调用上述函数,输出最大值和最小值,7.3 数组的指针表示,int a100, *p; 数组名代表一个地址,它的值是数组首元素的地址(基地址) a+i 是距数组a的基地址的第i个偏移,sum = 0; for(i = 0; i 100;

12、i+) sum = sum + ai ;,*(a+i),下标运算符 的含义:相对位移运算,7.3.1 一维数组的指针表示,ai 即 *(a+i),指针和数组的关系,任何由数组下标来实现的操作都能用指针来完成 int a100, *p; p = a; 或 p = , sum = 0; for(i = 0; i 100; i+) sum = sum + pi ;,等价,等价,用指针完成对数组的操作,int a100, *p; 移动指针,p,sum = 0; for(p = a; p = ,p,p,p,# include int main (void) double a2, *p, *q; p =

13、,例7-6:已知double型数据占8个字节,请写出以下程序的输出结果,1 8,指针p和q之间元素的个数,指针p和q之间的字节数,地址值,double *p, *q; q - p 两个相同类型的指针相减,表示它们之间相隔的存储单元的数目 p + 1 / p-1 指向下一个存储单元 / 指向上一个存储单元 其他操作都是非法的 指针相加、相乘和相除,或指针加上和减去一个浮点数 p q 两个相同类型指针可以用关系运算符比较大小,指针的算术运算和比较运算,# include int main(void) int i, a10, *p; int sum = 0; for(i = 0; i 10; i+)

14、 scanf(%d, ,例7.7 使用指针计算数组元素之和,输入: 10 9 8 7 6 5 4 3 2 1 sum=55,p,p,p,p,数组名是指针常量,相当于指针作为函数的参数 数组名做为实参,形参是指针变量(数组),7.3.2 数组作函数参数时的指针表示,int sum (int *array, int n) int i, s = 0; for(i=0; in; i+) s += arrayi; return(s); ,使用函数实现例7.7数组求和) int main(void ) int i; int b5 = 1, 4, 5, 7, 9; printf(%dn, sum(b, 5)

15、; return 0; ,(1) 实参是数组名 (2) 形参是指针变量 可以写成数组形式,int array ,*(array+i),int sum (int *array, int n) int i, s = 0; for(i=0; in; i+) s += arrayi; return(s); ,int main(void ) int i; int b5 = 1, 4, 5, 7, 9; printf(%dn, sum(b, 5); return 0; ,sum(b, 5),b0+b1+.+b4,sum(b, 3),b0+b1+b2,sum(b+1, 3),b1+b2+b3,sum( vo

16、id reverse(int p , int n); printf(Enter n: ); scanf(%d, ,例7.8 将数组元素逆序存放,void reverse(int p , int n) int i, j, t; for(i=0, j=n-1; ij; i+, j-) t = pi; pi = pj; pj = t; ,Enter n:10 Enter 10 integers: 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10,指针实现例7.8,void reverse(int *p, int n) int *pj, t; for(pj=p+n-1

17、; ppj; p+, pj-) t=*p; *p=*pj; *pj=t; ,int p ,数组名做为函数的参数,在函数调用时,将实参数组首元素的地址传给形参(指针变量),因此,形参也指向实参数组的首元素。如果改变形参所指向单元的值,就是改变实参数组首元素的值。 或:形参数组和实参数组共用同一段存贮空间,如果形参数组中元素的值发生变化,实参数组中元素的值也同时发生变化。,7.3.3 字符数组的指针表示,字符串是一种特殊的一维数组,所以上节中介绍的方法同样适用于对字符串的访问。 字符串的特殊性在于:字符串的末尾是结束标志 0 ,所以访问字符串时常用结束标志进行判断。 char s =“abcde”

18、;,s,s0 s1 s2 s3 s4 s5,例7.9 加密字符串,输入一个由小写字母组成的字符串,实现加密,加密方法:a变为b,b变为cz变为a,void encrypt(char *s); int main (void) char line 100; printf (Input the string: ); gets(line); encrypt (line); printf (“encrypted: %sn, line); return 0; ,void encrypt ( char *s) for ( ; *s != 0; s+) if (*s = z) *s = a; else *s

19、= *s+1; ,Input the string:hello After being encrypted: ifmmp,加密函数的两种实现,void encrypt (char *s) int i; for(i = 0; si != 0; i+) if (si = z) si = a; else si = si+1; ,void encrypt ( char *s ) for ( ; *s != 0; s+) if (*s = z) *s = a; else *s = *s+1; ,char s ,即使形参写成char s ,s在本质上仍是一个指针,1. 指针与字符串,字符串还可以定义为:

20、char *s= “abcde”; 或 char *s; s= “abcde”; 首先在内存中为字符串“abcde” 分配空间,占用6个字节,然后把该空间的首地址存入指针变量s,s,s0 s1 s2 s3 s4 s5,字符串 “abcde” 的值是地址, 故可以赋给指针变量s,char sa = array; char *sp = point; printf(%s , sa); printf(%s , sp); printf(%sn, string);,array point string,printf(%s , sa+2); printf(%s , sp+3); printf(%sn, st

21、ring+1);,ray nt tring,字符串的输出:从printf第二个参数指向的地址开始顺序向后逐字符输出,直到遇到0; 字符串由起始地址和0唯一确定。,2.字符数组与字符指针的重要区别,char sa = This is a string; char *sp = This is a string;,sa,sp,如果要改变数组sa所代表的字符串,只能改变数组元素的内容 如果要改变指针sp所代表的字符串,通常直接改变指针的值,让它指向新的字符串,字符数组与字符指针的重要区别,char sa = This is a string; char *sp = This is a string;

22、strcpy (sa, Hello); sp = Hello; sa = “Hello”; 非法 数组名是常量,不能对它赋值,字符指针先赋值,后引用,定义字符指针后,如果没有对它赋值,指针的值不确定。 char *s ; scanf(“%s”, s); char *s, str20; s = str; scanf(“%s”, s); 定义指针时,先将它的初值置为空 char *s = NULL;,危险!不要引用未赋值的指针,char *s=“Happy”; /正确,3.字符串的存储方法与处理技巧,存储方法 字符串在C语言中的存储方式是从数组名(假定为str),即相当于从指针str指向的地址开始

23、顺序向后一个字符一个字符的存储,在字符串最后一个元素的下一个元素置为0,表示字符串结束,之前的内容就是字符串的内容,这就是字符串的存储方式,,char *str; str=”abcdefg”;,例7.10 输入一个字符串,输出该字符串的靠后长度为3的子串 ,如何实现?,可使str1=str+(len-3),len代表str的长度,,也就是把倒数第三个字符的地址赋给字符指针str1,这时如果把str1当做一个字符串来使用,会发现它就是”efg”,字符串由起始地址和0唯一确定,#include int main() char str100; char str1; int len; gets(str

24、); len=strlen(str); str1=str+len-3; /str1指向倒数第三个字符 puts(str1); /把str1作为一个字符串输出 return 0; ,例7.10 源程序,例7.11: 已知一个字符串表示一个实数(不超过100位) ,请去掉前导0,如str=”0012350.1000”,应变为”12350.1000”,char *p=str; while(*p = 0)p+; /字符串p即所求 puts(p),例7.12从键盘输入两个实数,位数不超过200,试判断这两个实数是否完全相等。注意输入的实数整数部分可能有前导0,小数部分可能有末尾0。,思路分析: 输入的实

25、数位数可能超过19位,显然用double类型无法表示, 只能用字符串存储。 显然需要去掉整数部分的前导0和小数部分的末尾0,然后调用字符串比较函数判断相等。 如str=”0012350.1000”,应变为为”12350.1”。 ”0012350.1000”与”12350.1000000”应该相等 ”0012350.0000”与”12350”应该相等,(1) 去掉前导0 char *p=str; while(*p = 0)p+; p即去掉前导0后的字符串。结果如下图:,此时,字符串p的内容为:”12350.1000”,(2)去掉小数部分的末尾0 需要首先判断字符串中是否含有小数点,如果有小数点,

26、则从后向前找到最后一个非0字符,对其后的位置上赋值0,如下图:,0,此时,p就是去掉前导0和尾部0的字符串 字符串p的内容为:”12350.1”,(3)如果去掉尾部0后,最后一个字符是小数点, 则去掉小数点 str=“0012350.0000”如下图:,0,此时,字符串p的内容为:”12350”,char *conv(char str ) char *p=str,i; while(*p = 0)p+; /去掉整数部分的前导0 for(i=0;stri!=0;i+) /判断是否有小数点 if(stri=.)break; if(stri!=0) /若有小数部分 i=strlen(str)-1; w

27、hile(stri=0)i-; /当while停止时,stri为最后一个非0字符 if(stri=.)i-; /如果去掉尾部0后,最后一个字符是小数点, 则去掉小数点 stri+1=0; /置字符串结束标志 return p; /字符串p即为去掉前导0和小数部分末尾0的字符串 ,函数的返回值是一个字符指针,int main() char str1N,str2N,*p1,*p2; p1=str1; p2=str2; p1=conv(str1); /p1为str1去掉前导0和尾部0的字符串 p2=conv(str2); /p2为str2去掉前导0和尾部0的字符串 if(strcmp(p1,p2)=

28、0) printf(“YESn”); else printf(“NOn”); ,进一步讨论: 如何比较两个大实数的大小?,7.3.4 用指针实现内存动态分配,变量在使用前必须被定义且安排好存储空间 全局变量、静态局部变量的存储是在编译时确定,在程序开始执行前完成。 自动变量,在执行进入变量定义所在的复合语句时为它们分配存储,变量的大小也是静态确定的。 一般情况下,运行中的很多存储要求在写程序时无法确定。,动态存储管理,不是由编译系统分配的,而是由用户在程序中通过动态分配获取。 使用动态内存分配能有效地使用内存 使用时申请 用完就释放 同一段内存可以有不同的用途,动态内存分配的步骤,(1)了解需要多少内存空间 (2)利用C语言提供的动态分配函数来分配所需要的存储空间。 (3)使指针指向获得的内存空间,以便用指针在该空间内实施运算或操作。 (4)当使用完毕内存后,释放这一空间。,动态存储分配函数malloc(),void *malloc(unsigned size) 在内存的动态存储区中分配一连续空间,其长度为size 若

温馨提示

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

评论

0/150

提交评论