版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第十章指针一、概念存储单元的地址:微机以字节为存储单元,每个字节有唯一地址。变量地址:一个变量占用若干个存储单元(int4字节,char1字节),变量地址为变量占用空间的首字节地址。变量的值:变量对应存储空间所存储的数据。指针:变量地址的别称。指针变量:存储指针(其他变量的地址)的变量。例:内存单元的地址与内容的区别voidmain(){inta=10,b[4];printf(“a的地址(10进制):%d\n”,&a);printf(“b的地址(10进制):%d\n”,b);//b==&b[0]printf(“b[1]的地址(10进制):%d\n”,&b[1]);printf(“a的地址(16进制):%x\n”,&a);printf(“b的地址(16进制):%x\n”,b);//b==&b[0]printf(“b[1]的地址(16进制):%x\n”,&b[1]);}运行结果:a的地址(10进制):1310588b的地址(10进制):1310572b[1]的地址(10进制):1310576a的地址(16进制):13ff7cb的地址(16进制):13ff6cb[1]的地址(16进制):13ff70第十章指针1.指针变量的定义、引用和初始化指针变量是一种存放内存地址的变量。一般的定义形式为: 基类型*指针变量名例:intvar=10;int*pointer=&var;floatf;int*p=&f;//错误,int*与float*不匹配 其中int*为类型名,pointer和p为变量名。inta,b,*p1,*p2;//注意,*p2不是变量名p1=NULL;//在头文件stdio.h中,#defineNULL0或p1=0;10pointer12ff78var12ff7c12ff7c
2.与指针变量有关的运算符取地址运算符 &:单目运算符,右结合
返回其右边变量的地址。
例如,int*p1,*p2,a=5,b[10];p1=&a;p2=b;p2=&b[0];指向运算符*:单目运算,右结合
返回其右边指针变量所指的变量。
例如,p1=a;*p1=10;*p1此时就是a,*p1可以像一般整型变量使用。p2=&b[1];*p2=*p1+2;*&a等价于a,&*p1等价于&a
例子:输入两个整数,按先大后小的顺序输出。#include<stdio.h>voidmain(){int*p1,*p2,*p,a,b;printf(“输入任意两个整数:“);scanf(“%d%d”,&a,&b);p1=&a;p2=&b;if(a<b){p=p1;p1=p2;p2=p;}printf(“a=%db=%d\n”,a,b);printf(“max=%dmin=%d\n”,*p1,*p2);}运行结果:输入任意两个整数::35a=3b=5max=5min=3
&a3p1a&b5p2b&b3p1a&a5p2b赋值运算符=
把指针常量或另一个同类型的指针变量赋给指针变量。
例如,inta,*p1,*p2=0;p1=&a;p2=p1;p=10//错误,其中地址常量只能是0(NULL)。a=p1;//错误,地址不能赋值给整型变量算术运算符:+,-,++,--(1)指针和整数进行加减运算只有当指针指向数组的某个元素时,这种运算才有意义。例如,int*p,x,a[10]={8,10,20,30,40,50,60,70,80,90};p=a;//p指向a[0]p++;x=*p+3;//p指向a[1],x为8+3=11p+=2;//p指向a[3]p=&a[2];//p指向a[2],*(p+3)=5;//a[5]为5*++p=6;//等价于*(++p),a[3]为6++*p;//等价于++(*p),a[3]为6+1=7
p51(2)两个基类型相同的指针相减两个指针相减的结果是一个整数,表示两个指针所指数组元素下标值之间的差。例如,int*p,*q,a[15];p=a+2;q=&a[7];printf(“%d\n”,q-p);关系运算符:!=,==,>,<,>=,<=(1)两个指针相等或不相等,用于确定他们是否指向同一对象。例如,int*p,*q,a[10];p=&a[2];q=a+2;if(p==q)printf(“equal\n”);if(p!=NULL)printf(“notnull\n”);(2)两个指针的大小关系,用于确定它们所指数据对象存储位置的前后关系。只有对指向同一数组的元素的指针才有意义。for(p=a,q=&a[5];p<q;p++)printf(“%d”,*p);指向指针的指针指针变量也是变量,它在内存中也分配存储空间,因此指针变量也有地址。可以定义一个指针变量存储另一个指针变量的地址,这个变量就是指向指针变量的指针变量,简称为指向指针的指针。
一般形式为类型名**变量名;
例如,inta=10,*p=&a,**q=&p;3004q的地址30083000p的地址300410a的地址3000a=8;//直接访问*p=8;//单级间址访问**q=8;//二级间址访问printf(“%d”,**q+2);
第十章指针二、指针与函数指针作为函数参数指针变量可以作为函数的形式参数。函数调用时,相应的实际参数必须是同类型的指针(常量、变量或表达式)voidchange(intx,int*y) //形参x为整型,y为指针型{ x=10; //修改x的值,对a没有影响 *y=10; //修改*y的值,相当于修改b的值}voidmain(){ inta=200,b=200; change(a,&b); //把a的值赋给x,把&b的值赋给y printf("a=%d\tb=%d\n",a,b);}运行结果:a=200b=10用指针做参数,实际参数和形式参数之间仍然是值传递,即在调用函数时,把实际参数的值赋给形式参数。在被调函数中虽然不能改变作为实际参数的指针变量的值,但可以改变指针变量所指变量的值,从而达到在被调函数中修改主调函数中变量的目的。#include<stdio.h>voidswap(int*a,int*b){inttemp;temp=*a;*a=*b;*b=temp;}voidmain(){intx=5,y=10;swap(&x,&y);printf("x=%dy=%d\n",x,y);}#include<stdio.h>voidswap(inta,intb){inttemp;temp=a;a=b;b=temp;}voidmain(){intx=5,y=10;swap(x,y);printf("x=%dy=%d\n",x,y);}例:交换两个变量的值。运行结果:x=5y=10运行结果:x=10y=5#include<stdio.h>voidswap(int*p1,int*p2){int*temp;temp=p1;p1=p2;p2=temp;}voidmain(){intx=5,y=10;swap(&x,&y);printf("x=%dy=%d\n",x,y);}运行结果:x=5y=10函数的返回值为指针
函数调用可以返回一个指针型的函数值。
返回指针的函数定义格式为
类型名*函数名(参数表)例如,int*fun(intn,int*p);int*fun();指向函数的指针
编译后的函数存储在内存中,因此函数也有地址。
函数地址是指函数的入口地址(即函数代码的起始地址)。
实际上,函数名指定的就是函数的入口地址。定义指向函数的指针变量的一般形式为
数据类型(*指针变量名)()例如,int(*p)();
第一对括号表示优先级,表示符号*和p优先结合;
第二对括号表示*p是函数。
如果没有第一对括号,即int*p();,那么表示函数p返回一个指针值。例子:求任意函数在任意区间上的定积分。#include<stdio.h>#include<math.h>#defineEPS0.00001doublefun(doublex){returnx*x;}doubleintegral(inta,intb,double(*f)(double)){doublesum=0.0,x;for(x=a;x<b;x+=EPS)sum+=EPS*(*f)(x);returnsum;}voidmain(){printf(“f(x)=x*x在[0,1]区间的定积分:%f\n”,integral(0,1,fun));printf(“f(x)=sin(x)在[0,1]区间的定积分:%f\n”,integral(0,1,sin));printf(“f(x)=sqrt(x)在[0,1]区间的定积分:%f\n”,integral(0,1,sqrt));}将指向函数的指针作为函数参数,使得函数更具通用性。三、指针和数组数组名代表该数组的首地址,指向数组元素a[0]。1.指向数组元素的指针例:inta[10],*p1,*p2;p1=a;//等价于p1=&a[0];p2=&a[1];数组首地址是系统编译时确定的,是一个常量。因此不能对数组首地址赋值,例如,a=p;//错误
a++;//错误a(或a+0)代表a[0]的地址,a+i代表a[i]的地址,用a[i]方式访问数组元素,称为下标引用法。用*(a+i)方式访问数组元素,称为指针引用法。完全等价指针引用数组元素示例:inta[]={1,3,5,7,9},i,*p;for(i=0;i<6;i++)printf(“%d“,a[i]);for(i=0;i<6;i++)printf(“%d“,*(a+i));//即a[i]for(p=a;p<a+6;p++)printf(“%d“,*p);//即a[i]inta[5]=,i,*p;for(i=0;i<6;i++)scanf(“%d“,&a[i]);for(i=0;i<6;i++)scanf(“%d“,a+i);//即&a[i]for(p=a;p<a+6;p++)scanf(“%d“,p);//即&a[i]三种方式完全等效三种方式完全等效p=a;p[i]=6;与a[i]=6;是等价的。数组名作为函数参数因为数组名代表数组首地址,所以用数组名作为参数实际上就是用指针作为函数参数。例如:求数组元素的平均值。#include<stdio.h>intaverage(inta[]){inti,sum=0;for(i=0;i<5;i++)sum+=a[i];returnsum/5;}voidmain(){intscore[5]={60,80,90,70,50},ave;ave=average(score);printf(“ave=%d\n”,ave);}写成如下形式效果是一样的:intaverage(inta[5])intaverage(int*a)这三种形式的a都不是数组,是指针变量。二维数组与指针二维数组的地址设二维数组a定义如下:inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};a[0]a[1]a[2]把二维数组a看成一维数组,即a={a[0],a[1],a[2]},a[0],a[1],a[2]又分别是一维数组。a[0]={a[0][0],a[0][1],a[0][2],a[0][3]};a[1]={a[1][0],a[1][1],a[1][2],a[1][3]};a[2]={a[2][0],a[2][1],a[2][2],a[2][3]};所以,a是a[0]的地址,a+1是a[1]的地址,a+2是a[2]的地址;*a就是a[0],*(a+1)就是a[1],*(a+2)就是a[2],a[0]是a[0][0]的地址,a[0]+1是a[0][1]的地址,a[0]+2是a[0][2]的地址;
*a[0]是a[0][0],*(a[0]+1)是a[0][1],*(a[0]+2)是a[0][2];a[1]是a[1][0]的地址,a[1]+1是a[1][1]的地址,a[1]+2是a[1][2]的地址;
*a[1]是a[1][0],*(a[1]+1)是a[1][1],*(a[1]+2)是a[1][2];a[i][j]的地址为:a[i]+j或*(a+i)+j
或&a[i][j],a[i][j]与*(a[i]+j)和*(*(a+i)+j)等价。intb[4]={1,2,3,4};b={b[0],b[1],b[2],b[3]};b是b[0]的地址,b+1是b[1]的地址。*b就是b[0],*(b+1)就是b[1]。不考字符串与指针使用字符数组存储字符串。字符数组除了具有一般数组的特征之外,还允许对字符数组进行整体操作。charstr1[]=“hello”;printf(“%s”,str1);
字符数组还可以做如下存储,但不是字符串。charstr2[]={‘h’,’e’,’l’,’l’,’o’};for(i=0;i<5;i++)printf(“%c”,str2[i]);
还允许用字符指针表示字符串。char*str2=“hello”;printf(“%s”,str2);charstr[]=“hello”;strcpy(str,“we”);hello\0str1hello\0str3hellostr2we\0lo\0str1(1)赋值运算charstr1[16];str1=“hello”;//错char*str2;str2=“hello”;//对(2)输入charstr1[16];scanf(“%s”,str1);//对char*str2;scanf(“%s”,str2);//错char*str3=““;scanf(“%s”,str3);//危险p261例子:char*a=“ABCD”;while(*a)printf(“%s\n”,a++);char*a=“ABCD”;while(*a)printf(“%c\n”,a++);运行结果:ABCDBCDCDD运行结果:ABCD例子:求字符串的长度。intstrlen(char*str){char*p=str;while(*p)p++;//或while(*p++);returnp-str;}voidmain(){char*a=“hello”;printf(“len=%d”,strlen(a);}或者intstrlen(char*str){intcount=0;while(*str++)count++;returncount;}
intstrlen(char*str){inti=0;while(str[i])i++;returni;}例子:字符串连接函数。//把str2连接到str1之后:char*strcat(charstr1[],char*str2)char*strcat(char*str1,char*str2){char*p1=str1,*p2=str2;while(*p1)p1++;while(*p2){*p1=*p2;p1++;p2++;}*p1=0;retuenstr1;}voidmain(){chara[20]=“Chinese“,*b=“xiamen“,*c,c=strcat(a,b);printf(“c=%s\n”,c);}
运行结果:Chinesexiamen10.3.4指针数组元素类型为指针的数组叫指针数组。类型名*数组名[数组长度];例如,int*a[5];char*name[]={“zhang”,”li”,“wang”,”zhao”};name[0]name[1]name[2]name[3]zhang\0li\0wang\0zhao\0char*name[]={“zhangsan”,”lisi”,“wangwu”,”zhaoliu”};for(i=1;i<4;i++)//冒泡法,p265错误(i=0)for(j=0;j<4-i;j++)if(strcmp(name[j],name[j+1])>0){temp=
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《人工智能应用》教学课件-2025-2026学年浙教版(新教材)初中信息技术八年级下册
- 2025年工业元宇宙数字孪生模型转换技术
- 大学生竞聘社联部部长演讲稿
- 山区分散式清洁取暖项目中超声波热量表的部署挑战
- 识字4 中国美食 课件
- 2026年门窗采购安装合同(1篇)
- 2026年医疗影像数据存储合同协议
- 2026年医疗AI辅助诊断系统开发合同协议
- 2026年商超促销合同(1篇)
- 2026年市场股权激励合同(1篇)
- 2025年西北永新集团有限公司招聘4人笔试历年参考题库附带答案详解
- 劳务安全合同协议书
- 2026病理学人卫题库及答案
- GB/Z 177.3-2026人工智能终端智能化分级第3部分:移动终端
- 2026中国广藿香己醇行业应用动态与投资盈利预测报告
- 2025年测绘行业面试模拟题及答案解析
- 中国建筑业企业数字化研究报告2025
- T∕CPCPA 0017-2026 托育机构婴幼儿回应性照护服务规范
- 外科住院部工作制度
- 青贮加工基地建设方案
- 2026年1月浙江省高考(首考)历史试题(含答案)
评论
0/150
提交评论