最全的语言指针详解_第1页
最全的语言指针详解_第2页
最全的语言指针详解_第3页
最全的语言指针详解_第4页
最全的语言指针详解_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

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

文档简介

最全的语言指针详解第一页,共四十七页,编辑于2023年,星期三6.1指针的引出一.地址与指针1.地址与取地址运算C程序中的变量在内存中占有一个可标识的存储区,每一个存储区是由若干个字节组成,每一个字节都有自己的地址,而一个存储区的地址是指该存储区中第一个字节的地址C语言允许在程序中使用变量的地址(通过地址运算符&可得到)

如:floatx;变量x的地址----&x

inta[10];数组变量a的地址----数组名a

第二页,共四十七页,编辑于2023年,星期三2.指针与指针变量(1)变量的访问方式①直接访问:通过变量名或地址访问变量的存储区

例:scanf(“%d”,&x);

x=sqrt(x);printf(“%d”,x);②间接访问:将一个变量的地址存放在另一个变量中.如将变量x的地址存放在变量p中,访问x时先找到p,再由p中存放的地址找到xpx201210101010(2)指针:一个变量的指针就是该变量的地址(指针就是地址)(3)指针变量:存放变量地址的变量,它用来指向另一个变量第三页,共四十七页,编辑于2023年,星期三二、指针变量的定义1.格式:数据类型

*指针变量名;

例int*p1;char*p2;2.说明:(1)在变量定义时,*号表示该变量是指针变量

(注意:指针变量是p1,p2,不是*p1,*p2)(2)定义指针变量后,系统为其分配存储空间,用以存放其他变量的地址,但在对指针变量赋值前,它并没有确定的值,也不指向一个确定的变量例:intx,*p;x=5;px2012101051234注:指针变量p的值是随机值,此时p和x并无关联第四页,共四十七页,编辑于2023年,星期三(3)使指针变量指向一个确定的变量必须进行赋值intx,*p;x=5;p=&x;px2012101051010三、指针变量的引用1.指针运算符*(1)p与*p不同,p是指针变量,p的值是p所指向的变量的地址*p是p所指向的变量,*p的值是p所指向的变量的值*p的值为5(*p表示x),而p的值为1010(2)引用指针变量时的*与定义指针变量时的*不同定义变量时的*只是表示其后的变量是指针变量

第五页,共四十七页,编辑于2023年,星期三inta,*p;p=&a;

scanf(“%d”,p);printf(“%d\n”,*p);*p=12;

printf(“%d\n”,*p);pa201210105101012让p指向a

对a重新赋值等价于a=12

即&a2.&与*

p=&a;

*&a*(&a)*pa&*p&(*p)&a第六页,共四十七页,编辑于2023年,星期三2abcd53.*与++,--inta=2,b=5,c,d,*p;p的值为a的地址,*p的值为2p的值不变,*p的值为3(2)c=*p++;

c=*(p++);{c=*p;p++;}执行后c的值为3,*p的值为5(3)d=*++p;

d=*(++p);{++p;d=*p;}执行后d的值为3,*p的值为3p201210101010(1)p=&a;(*p)++;(等价于

a++;)10123310143第七页,共四十七页,编辑于2023年,星期三例6.2#include<stdio.h>voidmain(){int*p1,*p2,*p,a,b;scanf(“%d%d”,&a,&b);p1=&a;p2=&b;if(a<b){p=p1;p1=p2;p2=p;}printf(“a=%d,b=%d\n”,a,b);printf(“max=%d,min=%d\n”,*p1,*p2);}abp1p2p&a&b&a&b&a59输出结果:a=5,b=9max=9,min=5第八页,共四十七页,编辑于2023年,星期三一、指针变量作函数参数例:2个数按大小顺序输出#include<stdio.h>voidswap(intx,inty){inttemp;temp=x;x=y;y=temp;}voidmain(){inta,b;scanf(“%d%d”,&a,&b);if(a<b)swap(a,b);printf(“a=%d,b=%d\n”,a,b);}abxytemp5说明:该程序不能实现a和b的交换因为实参a,b对形参x,y是“值传递”,x和y的变化不影响a和b

所以输出为:a=5,b=99mainswap559956.2指针与函数第九页,共四十七页,编辑于2023年,星期三例6.3①#include<stdio.h>voidswap1(int*p1,int*p2){inttemp;

temp=*p1;*p1=*p2;*p2=temp;}voidmain(){inta,b,*pt1,*pt2;scanf(“%d%d”,&a,&b);pt1=&a;pt2=&b;if(a<b)swap1(pt1,pt2);printf(“a=%d,b=%d\n”,a,b);}abp1p2temp&b&apt1pt25说明:这种方法是交换p1和p2所指向的变量的值,即交换main函数中a和b的值所以输出为:a=9,b=5mainswap159&a&b95第十页,共四十七页,编辑于2023年,星期三例6.3②#include<stdio.h>voidswap2(int*p1,int*p2){int*temp;

*temp=*p1;*p1=*p2;*p2=*temp;}说明:这种方法可能会破坏系统的正常工作状态,因为temp是一个指针变量但是在函数中并没有给temp一个确定的地址,这样它所指向的内存单元是不可预见的,而对*temp的赋值可能带来危害abpt1pt2main&a&bp1p2temp&b&aswap2?随机值55959第十一页,共四十七页,编辑于2023年,星期三例6.3③#include<stdio.h>voidswap3(int*p1,int*p2){int*p;

p=p1;p1=p2;p2=p;}p1p2p&a&a&b这种方法是交换形参p1和p2的值,使它们的指向发生改变,但是main函数中的a和b的值并没有进行交换所以输出为:a=5,b=95a9b&apt1&bpt2main&b&aswap3第十二页,共四十七页,编辑于2023年,星期三前面我们用到的函数,有些无返回值,有些有返回值,返回值类型多为int,float,char.一个函数的返回值也可以是一个指针类型的数据(即地址)定义函数:数据类型

*函数名(形参表列)

{函数体;}

例:int*fun(inta,intb){函数体;}说明:定义一个返回指针值的函数与以前定义函数格式基本类似,只是在函数名前加*,它表明该函数返回一个指针值,而这个指针值是指向一个int型数据二、函数返回指针第十三页,共四十七页,编辑于2023年,星期三例:#include<stdio.h>#include<string.h>#defineSIZE100charbuf[SIZE];char*p=buf;char*alloc(intn){char*begin;if(p+n<=buf+SIZE){begin=p;

p=p+n;

return(begin);}elsereturn(NULL);}voidmain(){char*p1,*p2;inti;

p1=alloc(10);

strcpy(p1,”123456789”);

p2=alloc(5);

strcpy(p2,”abcd”);printf(“buf=%p\n”,buf);printf(“p1=%p\n”,p1);printf(“p2=%p\n”,p2);

puts(p1);puts(p2);for(i=0;i<15;i++)printf(“%c”,buf[i]);}第十四页,共四十七页,编辑于2023年,星期三buf[0]buf[1]::buf[9]buf[10]:buf[14]buf[15]::buf[99]bufpbuf+10p1p2mainbeginnallocbufbufbuf+1012:9\0a:\010buf+15beginnallocbuf+105第十五页,共四十七页,编辑于2023年,星期三函数的指针:函数的入口地址在程序执行过程中调用函数时,计算机会转去执行函数体内的语句,因此计算机必须知道函数在什么地方。实际上函数在内存中也要占据一片存储单元,这片存储单元一个起始地址,我们称其为函数的入口地址,即函数的指针,这个函数的入口地址是用函数名来表示。因此我们可以定义一个指针变量,让它的值等于函数的入口地址,然后可以通过这个指针变量来调用函数,该指针变量称为指向函数的指针变量三、指向函数的指针第十六页,共四十七页,编辑于2023年,星期三指向函数的指针变量1.定义格式:数据类型(*指针变量名)(形参表列);

int(*pt)(intarr[],intn);说明:①数据类型:指针变量所指向的函数的返回值类型②形参表列:即指针变量所指向的函数的形参表列③格式中的小括号不能省略2.应用(1)让指针变量指向函数

pt=add;

因为函数名为函数的入口地址,所以直接将函数名赋给指针变量即可(2)使用指针变量调用函数

格式:

(*指针变量名)(实参表列)第十七页,共四十七页,编辑于2023年,星期三例求一维数组中全部元素的和#include<stdio.h>intadd(intb[],intn);voidmain(){inta[6]={1,3,5,7,9,11},total;

int(*pt)(intb[],intn);

pt=add;

total=(*pt)(a,6);printf(“total=%d\n”,total);}intadd(intb[],intn){inti,sum=0;for(i=0;i<n;i++)sum=sum+b[i];return(sum);}

定义指向函数的指针变量令指针变量pt指向函数add通过pt调用函数add第十八页,共四十七页,编辑于2023年,星期三6.3指针与数组一.一维数组与指针1.一维数组及元素的地址表示

inta[5]={1,2,3,4,5};

数组的地址:a

元素

地址*aa[0]&a[0]a*(a+1)a[1]&a[1]a+1*(a+2)a[2]&a[2]a+2*(a+3)a[3]&a[3]a+3*(a+4)a[4]&a[4]a+4第十九页,共四十七页,编辑于2023年,星期三2.用指针变量引用数组元素(1)定义指针变量

int*p,a[5]={1,2,3,4,5};

p=a;(2)引用数组元素下标法地址法指针法第k个元素

a[k]*(a+k)*(p+k)第k个元素的地址

&a[k]a+kp+k

注意:指针变量也可以加下标p[k]等价于a[k]①分别用三种方法输出数组元素,其效率不同,下标法与地址法的效率相同,指针法的效率较快②用指针变量访问数组元素时要注意下标是否越界第二十页,共四十七页,编辑于2023年,星期三

例:将数组a中全部元素加1,再输出a#include<stdio.h>voidmain(){inta[5]={1,3,5,7,9},*p,j;for(p=a;p<a+5;p++)printf(“%3d”,*p);printf(“\n”);for(j=0;j<5;j++)a[j]=a[j]+1;for(j=0;j<5;j++)printf(“%3d”,*(p+j));printf(“\n”);}

p=a;13579aa+1a+2a+3a+4246810p可以用p++,但不能用a++因为a代表数组的起始地址它是地址常量,不能改变而p是一个指针变量使用指针变量时要注意它的当前值第二十一页,共四十七页,编辑于2023年,星期三3.指向数组的指针变量作函数参数例6.7①实参和形参都用数组名#include<stdio.h>voidinv1(intx[],intn){inttemp,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;temp=x[i];x[i]=x[j];x[j]=temp;}}voidmain(){inti,a[6]={1,3,4,6,7,9};

inv1(a,6);for(i=0;i<6;i++)printf(“%3d”,a[i]);printf(“\n”);}a[0]a[1]a[2]a[3]a[4]a[5]x[0]x[1]x[2]x[3]x[4]x[5]134679976431maininv1第二十二页,共四十七页,编辑于2023年,星期三例6.7②实参用数组名,形参用指针变量#include<stdio.h>voidinv2(int*x,intn){inttemp,m=(n-1)/2;int*p,*i,*j;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){temp=*i;*i=*j;*j=temp;}}voidmain(){inti,a[6]={1,3,4,6,7,9};

inv2(a,6);for(i=0;i<6;i++)printf(“%3d”,a[i]);printf(“\n”);}134679a[0]a[1]a[2]a[3]a[4]a[5]axai6na+5ja+2pinv29173642mtemp1a+1a+4a+2a+334i和j的指向会变化,p的指向保持不变第二十三页,共四十七页,编辑于2023年,星期三例6.7

③实参和形参都用指针变量#include<stdio.h>voidinv3(int*x,intn);voidmain(){int*p,a[6]={1,3,4,6,7,9};

p=a;

inv3(p,6);for(p=a;p<a+6;p++)printf(“%3d”,*p);printf(“\n”);}voidinv3(int*x,intn){inttemp,m=(n-1)/2;int*p,*i,*j;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){temp=*i;*i=*j;*j=temp;}}例6.7

④实参用指针变量,形参用数组名#include<stdio.h>voidinv4(intx[],intn);voidmain(){int*p,a[6]={1,3,4,6,7,9};p=a;inv4(p,6);for(p=a;p<a+6;p++)printf(“%3d”,*p);printf(“\n”);}voidinv4(intx[],intn){inttemp,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;temp=x[i];x[i]=x[j];x[j]=temp;}}第二十四页,共四十七页,编辑于2023年,星期三例6.8求数组中最大和最小元素#include<stdio.h>intmax,min;voidm1(intarr[],intn){int*p,*end;

end=arr+n;max=min=*arr;for(p=arr+1;p<end;p++)if(*p>max)max=*p;elseif(*p<min)min=*p;}voidmain(){inti,a[6];for(i=0;i<6;i++)scanf(“%d”,&a[i]);

m1(a,6);printf(“max=%d,min=%d\n”,max,min);}a[0]a[1]a[2]a[3]a[4]a[5]6narr+1parr+6endmaxmin471905aarr447910第二十五页,共四十七页,编辑于2023年,星期三二、二维数组与指针二维数组的定义a[0]a[1]a[2]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]对于二维数组a,首先可以把它先理解为一个一维数组,它有3个元素:a[0],a[1],a[2]而每一个元素又是一个一维数组,包含4个元素如a[0]是一维数组,它有4个元素:a[0][0],a[0][1],a[0][2],a[0][3]a[3][4]a[0],a[1],a[2]只是一种地址表示方法,并不真的二维数组元素,可以看作是第二重一维数组的名字。第二十六页,共四十七页,编辑于2023年,星期三二维数组的初始化(1)可以分行给二维数组赋初值inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};1 2 3 45 6 7 89 10 11 12(2)可以将所有数据写在一个花括号中,按顺序对各元素赋初值inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};第二十七页,共四十七页,编辑于2023年,星期三二维数组的初始化(3)可以对部分元素赋初值,其余元素补0inta[3][4]={{1},{5},{9}};1 5 9 inta[3][4]={{1},{0,6},{0,0,11}};1 0 6 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0第二十八页,共四十七页,编辑于2023年,星期三(4)如果对全部数据都赋初值,则定义时第一维的长度可以不指定,但第二维的长度不能省inta[][4]={1,2,3,4,5,6,7,8,9,10,11,12};二维数组的初始化如果只对部分数据赋初值,第一维的长度也可以不指定,但元素必须分行赋初值inta[][4]={{0,0,3},{},{0,10}};0 0 3 00 0 0 00 10 0 0第二十九页,共四十七页,编辑于2023年,星期三二维数组的地址a[0]a[1]a[2]二维数组名a表示二维数组的首地址,也是第0个元素(a[0])的地址a,&a[0]a+1,&a[1]a+2,&a[2]a+1代表第1个元素(a[1])的地址a+1

&a[1]a+2代表第2个元素(a[2])的地址a+2

&a[2]a

&a[0]第三十页,共四十七页,编辑于2023年,星期三a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a,&a[0]a+1,&a[1]a+2,&a[2]a[0],a[1],a[2]既然是第二重一维数组名,它们就代表了相应一维数组的首地址,因此a[0]代表了第0行第0列元素的地址,即二维数组的地址a[1]

&a[1][0]a[1]+2

&a[1][2]a[2]&a[2][0]a[2]+3&a[2][3]a[0]&a[0][0]a[0]+1&a[0][1]a[2]

&a[2][0]a[2]+3

&a[2][3]a[1]+2&a[1][2]a[1]&a[1][0]a[0]

&a[0][0]a[0]+1

&a[0][1]第三十一页,共四十七页,编辑于2023年,星期三Question*a,*a+1,*(a+1),*(a+2)+3分别表示什么值?a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]第三十二页,共四十七页,编辑于2023年,星期三二维数组的地址a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a,&a[0]a+1,&a[1]a+2,&a[2]*(a+2)+3a[2]+3&a[2][3]因a

&a[0]所以*a

*(&a[0])a[0]

&a[0][0]即*a表示元素a[0][0]的地址a[0]&a[0][0]*a*a+1表示元素a[0][1]的地址*(a+1)表示元素a[1][0]的地址*(a+2)+3表示元素a[2][3]的地址*(a+1)a[1]&a[1][0]*a+1a[0]+1&a[0][1]第三十三页,共四十七页,编辑于2023年,星期三二维数组的地址小结:二维数组名a代表二维数组的首地址,即:第0行的地址为a

&a[0]第1行的地址为a+1

&a[1]第2行的地址为a+2

&a[2]二维数组元素的地址a[2][3]a[1][2]a[1][0]a[0][1]a[0][0]元素&a[2][3]&a[1][2]&a[1][0]&a[0][1]&a[0][0]地址a[2]+3a[1]+2a[1]a[0]+1a[0]地址*(a[2]+3)*(a[1]+2)*a[1]*(a[0]+1)*a[0]元素*(a+2)+3*(a+1)+2*(a+1)*a+1*a地址*(*(a+2)+3)*(*(a+1)+2)*(*(a+1))*(*a+1)**a元素第三十四页,共四十七页,编辑于2023年,星期三指向二维数组元素的指针例1:用指针变量输出二维数组中的元素Quizp=a;p=&a[0][0];p=*a;p=*a[0];#include<stdio.h>voidmain(){inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int*p;}for(p=a[0];

p<a[0]+12;p++)printf(“%d”,*p);printf(“\n”);第三十五页,共四十七页,编辑于2023年,星期三2026q指向二维数组元素的指针inta[3][4];int**p;p=a;合法吗?intx=36,*q,**p;q=&x;p=&q;362010x2048p20102026a[0]a[1]a[2]p是二级指针,它指向一个整型指针变量q,而q指向一个整型变量a是一种地址表示方法,a实际指向了第一重一维数组元素a[0],而a[0]是第二重一维数组aa[0][0]a[0][1]a[0][2]a[0][3]非法!第三十六页,共四十七页,编辑于2023年,星期三指向二维数组元素的指针定义格式:类型名(*指针变量名)[数组长度];inta[3][4];int(*p)[4];p=a;p指向一个包含有4个整型数据的一维数组合法!

虽然在定义p的时候只用了一个*,但p实际上是一个二级指针变量第三十七页,共四十七页,编辑于2023年,星期三指向二维数组元素的指针例2:输出二维数组中的元素#include<stdio.h>voidmain(){inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int(*p)[4],i,j;p=a;for(i=0;i<3;i++){for(j=0;j<4;j++)printf(“%6d”,*(*(p+i)+j));printf(“\n”);

}}第三十八页,共四十七页,编辑于2023年,星期三指向二维数组元素的指针二维数组用得较多的是“字符串数组”,配合字符串的操作,使字符串处理更加方便、灵活。chara[4][256]={"Pascal","VC","Basic","Java"};a[0]a[1]a[2]a[3]Pas

ca

lVcBas

i

cJ

ava\0\0\0\0第三十九页,共四十七页,编辑于2023年,星期三#include<stdio.h>#include<string.h>#defineMAXLEN256#defineN4voidmain(){inti,j;

chartemp[MAXLEN];

charname[N][MAXLEN]={"Pascal","VC","Basic","Java"};

for(i=0;i<N;i++)

puts(name[i]);}//书的数量for(i=0;i<N-1;i++)for(j=i+1;j<N;j++)

if(strcmp(name[i],name[j])>0){

strcpy(temp,name[i]);

strcpy(name[i],name[j]);

strcpy(name[j],temp);}选择法排序//书名的最大长度+1指向二维数组元素的指针比较两个字符串大小复制字符串Quiz选择法排序第四十页,共四十七页,编辑于2023年,星期三Assignment1、将数组a[2][3]中的每个元素向右移一列,最后一列换到最左一列(如右图所示)要求:必须用指针实现321654=a2135462、将数组a[M][N]中的每个元素向右移一列,最后一列换到最左一列要求:必须用指针实现第四十一页,共四十七页,编辑于2023年,星期三Experiment实验题目:指向二维数组的指针编程实验目的:深入理解如何用指针变量表示二维数组的元素和元素的地址,学会用指向二维数组的指针变量作函数参数实验内容:编程找出二维数组中的鞍点,二维数组的鞍点是指在该位置上的元素在该行上最大,在该列上最小,也可能没有鞍点。要求必须用指针实现。编写一个找鞍点的函数,用指向二维数组的指针变量作函数参数第四十二页,共四十七页,编辑于2023年,星期三6.4指针与字符串一、字符指针1.定义指向字符串的指针变量

char*p=“China”;

说明:这里没有定义字符数组,但字符串在内存中还是以数组形式存放的.字符串在内存中占有一片连续的存储单元,以‘\0’结束

注意:赋值只是把字符串的首地址赋给p,而不是把字符串赋给p,p是一个指针变量,它不能存放一个字符串,只能存放一个地址China\0

温馨提示

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

评论

0/150

提交评论