版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第8章 善于利用指针数学科学学院:汪小平一、地址和指针的概念1、数据的存储与读取 内存可以想像为由字节构成的一连续存储区。 每个字节都有一个编号,称为内存地址。 当用 int i,j,k; 声明变量时,编译程序给变量分别分配sizeof(int)个字节内存空间,i,j,k分别代表所分配内存单元的名称,在使用时用内存名对该单元进行存取,但实际上在编译时已转化为该单元的地址。就像网络中的域名与IP地址的关系一样。 分析:k=i+j;的存取过程内存用户数据区2000200420083012ijk一、地址和指针的概念2、直接存储与间接存储 上面通过变量地址直接访问内存单元的方式称为直接访问。 若有一内
2、存单元(名叫i_pointer)放变量i的地址,在存取i的内容前,可以先从i_pointer中取出i的地址,再去存取i的内容,这种方式称为间接访问。 相当于A抽屉的钥匙放在B抽屉中,要打开A抽屉,先从B中拿出A的钥匙一样 称地址2000指向变量单元i,地址2000称为变量i的指针,而存放指针的变量称为指针变量。内存用户数据区2000200420083012iji_pointerk2000二、变量的指针和指向变量的指针变量int i;i_pointer存储变量i的地址 称i_pointer指向变量i。 (*i_pointer)表示i_pointer所指向的变量,其中*表示指向。所以*i_poin
3、ter相当于变量i。 有:i_pointer=&i2000i_pointer3i*i_pointer1、定义一个指针变量 基类型 *指针变量名;例: int *p1; int *p2,*p3;两个运算符: &:取地址运算符。 *:指针运算符,取其指向的内容。 结合方向自右向左。#include int main()int a,b;int * p1,*p2;a=100;b=10;p1=&a;p2=&b;printf(%d,%dn,a,b);printf(%d,%dn,*p1,*p2);return 0;二、变量的指针和指向变量的指针变量2、指针变量的引用&ap1100a&bp210b*p1*p2
4、分析: *&a &*p1例1 指针的简单使用#include int main()int a,b,*p,*p1,*p2;scanf(%d%d,&a,&b);p1=&a; p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(max=%d,min=%dn,*p1,*p2);return 0;二、变量的指针和指向变量的指针变量&ap112a&bp225b*p2*p1例2 输入a,b两个整数,按先大后小的顺序输出。p&b&a#include void swap(int *p1,int *p2);int main()int a,b,*pointer1,*pointer2;scanf(%
5、d%d,&a,&b);pointer1=&a;pointer2=&b;if(ab)swap(pointer1,pointer2);printf(max=%d,min=%dn,a,b);return 0;二、变量的指针和指向变量的指针变量3、指针变量作为函数参数例3 输入a,b两个整数,要求用函数实现a保存两数中的较大者,b保存较小者。.int a,b;scanf(%d%d,&a,&b);if(ab)swap(&a,&b);.void swap(int *p1,int *p2)int temp;temp=*p1;*p1=*p2;*p2=temp;二、变量的指针和指向变量的指针变量&apointe
6、r_112a&bpointer_225b*p1*p2&ap1&bp2复制复制二、变量的指针和指向变量的指针变量如果想通过函数调用得到n个要改变的值,可以:在主调函数中设n个变量,用n个指针变量指向它们;然后将这n个指针变量作为实参传递给函数形参;通过形参指针变量,改变该n个变量的值;主调函数中就可以使用这些改变了值的变量。三、数组与指针1、指向数组元素的指针 数组元素的指针就是数组元素的地址。 使用指针法能使目标程序质量高(占内存少,运行速度快)。 数组元素相当于一个普通变量,所以指向数组元素的指针的定义与使用方式与指向普通变量的指针一样。例:int a10,*p;p=&a3; /*p指向元素
7、a3 */*p=10; /*相当于a3=10 */p=a; /*p指向数组的首元素 */ 注意数据名表示数组在内存中的首地址。但数组名绝不代表整个数组。例4 编程观察指针p和p+1表示的地址。三、数组与指针2、通过指针引用数组元素 C语言规定:指针p指向数组某个元素,则p+1指向数组下一个元素,而不是简单的地址加1 若有定义:类型 *p; 则p+1在内存地址上相当于为: p+sizeof(类型)#include int main()char a,*pa=&a;int b,*pb=&b;float c,*pc=&c;double d,*pd=&d;printf(n&a=%x,pa+1=%xn,&
8、a,pa+1);printf(n&b=%x,pb+1=%xn,&b,pb+1);printf(n&c=%x,pc+1=%xn,&c,pc+1);printf(n&d=%x,pd+1=%xn,&d,pd+1);return 0;三、数组与指针 若有 int a10,*p; 则p=a与p=&a0等价 p+i与a+i都表示&ai,即*(p+1)与*(a+i)均相当于ai。区别在于p是变量,a是常量。 若有p=a,则p可带下标访问数组的元素,即pi与ai、*(p+i)及*(a+i)完全等价。 以下几种方法都是输出数组的全部元素(即遍历):for(i=0;i10;i+)printf(%5d,ai);fo
9、r(i=0;i10;i+)printf(%5d,pi);for(i=0;i10;i+)printf(%5d,*(a+i);for(i=0;i10;i+)printf(%5d,*(p+i);for(p=a;p(a+10);p+)printf(%5d,*p);for(p=a;p(a+10);)printf(%5d,*p+);三、数组与指针3、用数组名作函数参数 用数组名作为实参,实质是把数组的首地址传递给了形参 也可以先用指针变量保存数组的首地址,再作为实参传递给形参void func(int a,int n);int main()int a10;.func(a,10);.return 0;voi
10、d func(int a,int n);int main()int a10,*p=a;.func(p,10);.return 0;三、数组与指针 作为形参,同样道理,既可以声明为数组,也可以声明为指针void func(int a,int n);int main()int a10;.func(a,10);.void func(int a,int n)int i;for(i=0;in;i+)*a+=i;void func(int *a,int n);int main()int a10;.func(a,10);.void func(int *a,int n)int i;for(i=0;in;i+)
11、ai=i;三、数组与指针例5 将数组a中n个整数按相反顺序存放。2457601197337911067542下标410个元素上界:545760119734576011973下标39个元素上界:4三、数组与指针#include void inv(int x,int n);int main()int i,a10=3,7,9,11,0,6,7,5,4,2;printf(The original array:n);for (i=0;i10;i+) /*输出10个元素*/printf(%4d,ai);inv(a,10); /*数组名作为实参 */printf(nThe array has been in
12、verted:n);for(i=0;i10;i+) /*输出10个元素*/printf(%4d,ai);return 0;void inv(int x,int n)int temp,i,j,m=n/2;for(i=0;im;i+)j=n-i-1; /* 对称位置*/temp=xi;xi=xj;xj=temp; /* 交换*/三、数组与指针#include void inv(int *x,int n);int main()int *p,a10=3,7,9,11,0,6,7,5,4,2;printf(The original array:n);for (p=a;pa+10;p+) /*输出10个元
13、素*/printf(%4d,*p);inv(a,10); /*数组名作为实参 */printf(nThe array has been inverted:n);for(p=a;pa+10;p+)printf(%4d,*p);return 0;void inv(int *x,int n)int temp,*i,*j,*p,m=n/2;i=x;j=x+n-1;p=x+m;for(;ip;i+,j-)temp=*i;*i=*j;*j=temp;三、数组与指针4、多维数组与指针(1) 一维数组与指针若有定义:int a10=0,1,2,3,4,5,6,7,8,9,*p=a;9876543210低地址高
14、地址aappfor(;pa+10;p+)printf(“%5d”,*p);pppppppppppa+1a+2a+3a+4a+5a+6a+7a+8a+9a+10a+10由于加1后,p指向下一列,因此这种指针称为列指针。三、数组与指针(2)二维数组元素的地址816357492int a33;aa0a+1a+2 二维数组名a表示第0行的首地址;a+i表示第i行一维数组的首地址(有时称为行指针)。 行指针+数 还是行指针 ai表示第i行数组首元素的首地址(列指针),与a+i的关系为a+i=&ai,或*(a+i)=ai , 行指针转换为列指针要加*,而列指针转换为行指针要加&。 ai+j表示第i行第j个
15、元素的首地址,相当于&aij,即有:*(ai+j)=aij,或*(*(a+i)+j)=aij 列指针+数 还是列指针(注意元素的地址是列指针)三、数组与指针816357492int a33;aa0a+1a+2 第i行首地址 a+i &ai /*列指针转换行指针*/ 第i行首元素的首地址: &ai0 /*取元素地址*/ ai /*第i行首元素的首地址*/ *(a+i) /*行指针转换为列指针*/ 第i行第j列元素的地址: &aij /*取元素地址*/ ai+j /*行首地址为j*/ *(a+i)+j /*行指针转为列指针*/ 第i行第j列的元素表示: aij *(ai+j) *(*(a+i)+j
16、) (*(a+i)j /*下标法*/三、数组与指针要得到元素aij,有三种方式: 下标法ai (第i行首元素首地址)aij (相当于一个变量)行地址转化列地址 指针法a+i (第i行地址)*(a+i) (第i行首元素地址)*(a+i)+j (元素地址)行地址转化列地址a (首行地址)*(*(a+i)+j) (元素)列转化元素 混合法ai (第i行首元素首地址)a (首行地址)ai+j (元素地址)*(ai+j) (元素)*(a+i) (第i行首元素地址)a+i (第i行地址)行地址转化列地址行地址转化列地址(*(a+i)j (相当aij)列转化元素三、数组与指针(3)指向多维数组元素的指针变量
17、 定义int a33;若指针定义为:int *p; 则p是列指针,若p指向二维数组中某个元素,则执行 +p 只能使p指向下一列元素。#include int main()int *p,a33;p=a; /*最好代替为p=*a; */printf(n%x,%xn,p, p+1);p=a0; /* 或p=&a00 */ printf(n%x,%xn,p,p+1);return 0;例6 观察不同赋值方式下p与 p+1 存储的地址。三、数组与指针 若指针定义为:int (*p)3; 表明p是行指针,指向一行数组,一行包含3个元素的一维数组。注意括号不能少。这时p相当于二维数组a3中的a。#inclu
18、de int main()int (*p)3,a33=1,2,3,4,5,6,7,8,9;p=a;printf(n%x,%xn,p,p+1);p=a0; printf(%x,%xn,p,p+1);printf(%d,%d,%d,%d,%d,*(*(p+1)+1),(*(p+1)1,*(p1+1),p11,*(p+1)1);return 0;例7 指向数组的指针的使用。四、字符串与指针1、字符串的表示方式(1)用字符数组存放字符串 char str14=“I love China!”; /*可不要括号*/ char str=“I love China!”; /*可不要括号*/ char str1
19、4; str=“I love China!” /*错误,字符串不能赋值*/ char str114,str =“I love China!” ; str1=str; /*错误,数组之不能作赋值运算*/ strcpy(str1,str); /*正确*/缺点:预分配空间,字符串长度一般小于字符数组长度,浪费内存。四、字符串与指针(2)用字符指针指向一个字符串 C语言对字符串常量按字符数组处理,在内存中开辟一个字符数组用来存放,最后一个字符是0。 char *str=“I love China!”; /*str保存的是字符串的首地址*/ char *str; str=“I love China!”;
20、 str=“other string”; /*正确,但不提倡,前字符串丢失*/ char *str1,ch15,*str =“I love China!” ; str1=str; /*正确,指向的是同一字符串,没有产生复制*/ strcpy(str1,str); /*错误,str1没有指向具体存储空间*/ str1=ch; /*str1指向字符数组ch的首地址 */ strcpy(str1,str); /*正确,把str指向的字符串复制入ch */四、字符串与指针例8 将字符串a复制到字符串b。abcde0#include #include int main()char b20,a=I am
21、a boy.;int i,k;k=strlen(a);/*取得字符串a的长度,不含0*/for(i=0;ik;i+)bi=ai;bi=0; /*循环结束时0没有复制入b*/printf(%sn,b);return 0;四、字符串与指针例8 将字符串a复制到字符串b。(实现二)abcde0#include int main()char b20,a=I am a boy.;int i;for(i=0;ai!=0;i+)bi=ai;bi=0; /*循环结束时0没有复制入b*/printf(%sn,b);return 0;四、字符串与指针例8 将字符串a复制到字符串b。(实现三)abcde0#incl
22、ude int main()char b20,a=I am a boy.;int i;for(i=0; (bi=ai)!=0;i+);/*先赋值,后比较,循环结束时,0在b中*/printf(%sn,b);return 0;四、字符串与指针例8 将字符串a复制到字符串b。(实现四)abcde0#include int main()char *p,*q,b20,a=I am a boy.;p=a; /*p指向a数组首元素*/q=b;/*q指向b数组首元素*/for(;(*q=*p)!=0;p+,q+);printf(%sn,b);return 0;四、字符串与指针例9 用字符指针输出下列图形。#
23、include #include int main()char *p,a=123456789;for(p=a;*p!=0;p+)printf(%sn,p);return 0;五、指向函数的指针1、用指针变量调用函数 函数的指针:一个函数在编译时被分配给一个入口地址(即函数代码在内存的起始地址)。这个地址称为函数的指针。可以认为函数的名称表示函数的入口地址,就像数组的名称一样。 指向函数的指针声明形式为: 数据类型 (*指针变量名)(函数参数列表)例如: int (*p)(int a,int b); void (*p)(int a,int n); /*a是指针,表示数组首地址*/ void (*
24、p)(int *a,int n); /*a是指针,可表示数组首地址*/ void (*pf)(int a10,int n); /*a是二维数组首地址*/ void (*pf)(int (*a)10,int n); /*a可看作二维数组首地址*/五、指向函数的指针例10 函数的指针的初步使用。#include #include int main()double result,(*p)(double);p=sin;result=(*p)(PI/6);printf(nsin(pi/6)=%lfn,result);p=cos;result=(*p)(PI/3);printf(cos(pi/3)=%lf
25、n,result);return 0;五、指向函数的指针2、用指向函数的指针作函数参数void qsort( void *base,size_t num, size_t width, int (_cdecl *compare )(const void *, const void *) ); 例11 使用qsort函数进行10个整数排序(从小到大)。#include #include int compint(const void* p1,const void* p2)/前者大于后者返回正,相等返回0,否则返回负数return (*(int*)p1)-(*(int*)p2);int main()i
26、nt i,a10=8,9,1,5,6,7,5,12,14,32;for(i=0;i10;i+)printf(%d ,ai);printf(n);qsort(a,10,sizeof(int),compint);for(i=0;i10;i+)printf(%d ,ai);printf(n);return 0;例11 使用qsort函数进行10个整数排序(从大到小)。#include #include int compint(const void* p1,const void* p2)/前者大于后者返回正,相等返回0,否则返回负数return (*(int*)p2)-(*(int*)p1);int
27、main()int i,a10=8,9,1,5,6,7,5,12,14,32;for(i=0;i10;i+)printf(%d ,ai);printf(n);qsort(a,10,sizeof(int),compint);for(i=0;i*y) return x; else return y;#include int *func(int *x,int *y);main() int a=2,b=3; int *p; p=func(&a,&b); printf(%dn,*p);23 指针变量y 指针变量xffd4ffd0复制地址变量a 变量b 指针变量p*ffd4输出:3六、返回指针值的函数in
28、t *func(int x,int y) if(xy) return &x; else return &y;#include int *func(int x,int y);main() int a=2,b=3; int *p; p=func(a,b); printf(%dn,*p);.ffd0ffe0ffd4ffd8ffdc23 形参变量y 形参变量x32复制地址变量a 变量b 指针变量p*ffe0输出:3六、返回指针值的函数int *func(int x,int y) if(xy) return &x; else return &y;void other(int x,int y)#inclu
29、de int *func(int x,int y);void other(int x,int y);main() int a=2,b=3; int *p; p=func(a,b); other(8,9); printf(%dn,*p);.ffd0ffe0ffd4ffd8ffdc23 形参变量y 形参变量x32复制地址变量a 变量b 指针变量p*ffe089输出:9动态分配内存 前面所学的变量声明属于静态分配内存,在程序执行前内存空间就分配好了。有时在程序代码执行前很难确定需要多少内存单元保存数据,比如任意个数排序、任意矩阵的乘法等等。 动态分配内存函数:void *malloc(unsigne
30、d int size); malloc在内存的动态存储区中分配一个size长度的连续存储空间。返回一个指向分配空间首地址的指针(类型为void*);若未成功,则返回空指针(NULL) 例如:int *p; p=(int *)malloc(4*sizeof(int); /*相当于声明了4个元素的整型数组*/ 释放用malloc函数申请的内存:void free(void *p); 动态内存分配例12 从键盘读入任意个整数进行从小到大排序,并输出结果。#include void sort(int *p,int n);int main()int *p,n,i; /*先声明整型指针 */scanf(“
31、%d”,&n); /*读入元素个数*/p=(int*)malloc(n*sizeof(int); /*分配内存*/for(i=0;in;i+) /*下面可以当作数组使用*/scanf(%d,&pi);sort(p,n);for(i=0;in;i+)printf(%4d,pi);free(p); /*不要忘记释放内存*/return 0;动态内存分配void sort(int *p,int n) /*简单选择法排序*/int i,j,k,temp;for(i=0;in-1;i+)k=i; /*k在下面循环保存最小元素的下标*/for(j=i+1;jpj)k=j;if(k!=i) /*与下标为i的
32、元素交换*/temp=pi;pi=pk;pk=temp;七、指针数组和指向指针的指针1、指针数组的概念 若一个数组的元素均为指针类型数据,称为指针数组。例如:int *p4; /*4个元素的指针数组*/ 使用指针数组一个比较好的场合是用字符指针数组指向若干字符串,从而使字符串处理更方便灵活。(若为常量字符串,可以更节约存储空间)下面以一个例子说明字符指针数组指向字符串与字符数组存储字符串的区别。七、指针数组和指向指针的指针Follow meBASICGreat WallFORTRANComputer designFollowme0BASIC0GreatWall0FORTRAN0Computer
33、design0字符串:char str516;pstr0pstr1pstr2pstr3pstr4char *pstr5;Computerdesign0FORTRAN0GreatWall0BASIC0Followme0七、指针数组和指向指针的指针考虑两种存储方式下的排序操作(简单选择排序):(1)二维字符数组函数声明:void sort(char str16,int n) 或:void sort(char (*str)16,int n)char temp16;int i,j,k; /*k保存最小字符串在数组中的行下标*/for(i=0;in-1;i+)k=i; /*开始假定第i个字符串是最小的*
34、/for(j=i+1;j0) k=j;if(k!=i) /*交换字符串*/strcpy(temp,stri);strcpy(stri,strk); strcpy(strk,temp);七、指针数组和指向指针的指针(2) 字符指针数组函数声明:void sort(char *str,int n)void sort(char *str,int n)char *temp;int i,j,k;/*k保存指向最小字符串的指针在数组中的下标*/for(i=0;in-1;i+)k=i; /*开始假定第i个指针指向的字符串是最小的*/for(j=i+1;j0)k=j;if(k!=i)/*交换指针*/temp=
35、stri;stri=strk;strk=temp;七、指针数组和指向指针的指针Follow meBASICGreat WallFORTRANComputer design原字符串0ngisedretupmoC0NARTROF0llaWtaerG0emwolloF0CISAB排序后的字符数组pstr4pstr3pstr2pstr1pstr0排序后的指针数组指向0ngisedretupmoC0NARTROF0llaWtaerG0CISAB0emwolloF二维字符数组操作的完整程序#include #include void sort(char str16,int n); /*函数声明*/void
36、 print(char str16,int n);int main()char str16=“Follow me”,“BASIC”,“Great Wall”,“FORTRAN”,“Computer design”; /*字符数组初始化*/int n=5;sort(str,n);print(str,n);return 0;void sort(char str16,int n)char temp16; /*临时字符数组,作交换用*/int i,j,k;二维字符数组操作的完整程序for(i=0;in-1;i+)k=i;for(j=i+1;j0)k=j;if(k!=i) /*注意交换的是字符串*/strcpy(temp,stri);strcpy(stri,strk);strcpy(strk,temp);void print(char str16,int n)int i;for(i=0;in;i+)pu
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 淮阴师范学院《土壤污染及其防治》2023-2024学年第一学期期末试卷
- 淮阴师范学院《中学音乐课教学案例分析》2023-2024学年第一学期期末试卷
- 淮阴师范学院《初等数学研究》2023-2024学年第一学期期末试卷
- DB2310-T 140-2024牡丹江地区森林可持续经营规程
- 宝石中英对照词汇-总和
- 春节前安全检查与培训考核试卷
- 油炸食品制造业中的员工健康与安全管理考核试卷
- 打印技术在建筑领域的应用考核试卷
- 广东省广州市白云区2024-2025学年四年级上学期期中英语试卷
- 新型环保技术与安全应用考核试卷
- 鲁教版七年级上册地理知识点汇总
- 新课标-人教版数学六年级上册第四单元《比》单元教材解读
- 全国高中青年数学教师优质课大赛一等奖《函数的单调性》课件
- 部编版道德与法治 四年级上册 单元作业设计《为父母分担》
- 核酸的生物合成 完整版
- 第一章-教育及其本质
- 天然气巡检记录表
- 食品进货台账制度范本(3篇)
- 甲苯磺酸瑞马唑仑临床应用
- 中国古代文学史PPT完整PPT完整全套教学课件
- 车牌识别一体机安装调试教程
评论
0/150
提交评论