1第22讲二维数组字符串与指针函数与指针2a+i=a[i]=*(a+i)=&a[i][0],值相等,含义不同a+i表示第i行首地址,指向行a[i]*(a+i)&a[i][0],表示第i行第0列元素地址,指向列a[0]a[1]a[2]200020082016200020022008201020162018a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]aa+1a+2对二维数组inta[3][4],有a-----二维数组的首地址,即第0行的首地址a+i-----第i行的首地址a[i]*(a+i)------第i行第0列的元素地址a[i]+j*(a+i)+j-----第i行第j列的元素地址*(a[i]+j)*(*(a+i)+j)a[i][j]10.5指针与二维数组1.二维数组和数组元素的地址3inta[3][4];a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]二维数组元素表示形式:(1)a[1][2](2)*(a[1]+2)(3)*(*(a+1)+2)(4)*(&a[0][0]+1*4+2)地址表示:(1)a+1(2)&a[1][0](3)a[1](4)*(a+1)(5)(int*)(a+1)行指针列指针地址表示:(1)&a[1][2](2)a[1]+2(3)*(a+1)+2(4)&a[0][0]+1*4+24表示形式含义地址a二维数组名,数组首地址a[0],*(a+0),*a第0行第0列元素地址a+1第1行首地址a[1],*(a+1)第1行第0列元素地址a[1]+2,*(a+1)+2,&a[1][2]第1行第2列元素地址*(a[1]+2),*(*(a+1)+2),a[1][2]第1行第2列元素值20002000200820082012135main(){staticinta[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};int*p;for(p=a[0];pa[0]+12;p++){if((p-a[0])%4==0)printf(\n);printf(%4d,*p);}}p=*a;p=&a[0][0];p=(int*)a;p=a;inta[3][4];a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]p例用指针变量指向二维数组的数组元素6()不能少(*p)说明p是一个指针变量!(*p)[4]说明p的值是某个包含4个元素的一维数组的首地址,p是行指针inta[3][4];a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]aa+1a+2pp+1p+2p[0]+1或*p+1p[1]+2或*(p+1)+2*(*p+1)或(*p)[1]*(*(p+1)+2)p指向的一维数组的元素个数和二维数组列数必须相同定义形式:数据类型(*指针名)[一维数组的元素个数];例int(*p)[4];2.通过建立指针数组和行指针引用二维数组指针数组:如inta[3][4],*q[4];q[0]=&a[0][0];q[1]=&a[2][0];可让p指向二维数组某一行如inta[3][4],(*p)[4];p=a;7main(){staticinta[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};inti,j,(*p)[4];for(p=a,i=0;i3;i++,p++)for(j=0;j4;j++)printf(%d,*(*p+j));printf(\n);}p=a[0];p=*a;p=&a[0][0];p=a;p=&a[0];inta[3][4];a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]pppp[0][j]例指向一维数组的指针变量(行指针)应用for(p=a,pa+3;p++)a+38实参形参数组名intx[][4]指针变量int(*q)[4]数组名intx[][4]指针变量int(*q)[4]数组名a数组名a指针变量p1指针变量p1若inta[3][4];int(*p1)[4]=a;int*p2=a[0];指针变量p2指针变量int*q3.二维数组名或行指针作函数的形参通过指针引用二维数组的几种形式:9例3个学生各学4门课,计算总平均分,并输出第n个学生成绩main(){voidaverage(float*p,intn);voidsearch(float(*p)[4],intn);floatscore[3][4]={{65,67,79,60},{80,87,90,81},{90,99,100,98}};average(*score,12);search(score,2);}voidaverage(float*p,intn){float*p_end,sum=0,aver;p_end=p+n-1;for(;p=p_end;p++)sum=sum+(*p);aver=sum/n;printf(average=%5.2f\n,aver);}voidsearch(float(*p)[4],intn){inti;printf(No.%d:\n,n);for(i=0;i4;i++)printf(%5.2f,*(*(p+n)+i));}列指针行指针函数说明floatp[][4]6552796080879081909910098pp*(*(p+n)+i)p[n][i]10例3个学生各学4门课,计算总平均分,并查找一门以上课不及格学生,输出其各门课成绩voidsearch(float(*p)[4],intn){inti,j,flag;for(j=0;jn;j++){flag=0;for(i=0;i4;i++)if(*(*(p+j)+i)60)flag=1;if(flag==1){printf(No.%disfail,hisscoresare:\n,j+1);for(i=0;i4;i++)printf(%5.1f,*(*(p+j)+i));printf(\n);}}}main(){voidsearch(float(*p)[4],intn);floatscore[3][4]={{...},{...},{...}};search(score,3);}6552796080879081909910098p*(*(p+j)+i)p[j][i]11如有:inta[5][10],(*p)[10];p=a;系统给数组a分配2*5*10个字节的内存区。系统只给变量p分配能保存一个指针值的内存区(2字节);数组名a的值是一个指向有10个元素的一维数组的指针常量;p=a+i使p指向二维数组的第i行;*(*(p+i)+j)a[i][j];二维数组形参实际上是一个指向一维数组的指针变量,即:fun(intx[][10])fun(int(*x)[10])在函数fun中两者都可以有x++;x=x+2;等操作!但在变量定义(不是形参)时,两者不等价;二维数组与指向一维数组的指针变量的关系12int**p与int*q[10]系统只给p分配能保存一个指针值的内存区;而给q分配10个内存区,每个内存区均可保存一个指针值;指针数组名是二级指针常量;p=q;p+i是q[i]的地址;指针数组作形参,int*q[]与int**q完全等价;但作为变量定义两者不同。指针数组与二级指针的关系13例main(){charstring[]=“IloveChina!”;printf(“%s\n”,string);printf(“%s\n”,string+7);}IloveChistring[0]string[1]string[2]string[3]string[4]string[5]string[6]string[7]string[8]string[9]stringstring[10]string[11]string[12]string[13]n!a\01.字符串表示形式(1)用字符数组实现10.6指针与字符串14例main(){char*string=IloveChina!;printf(%s\n,string);string+=7;while(*string){putchar(string[0]);string++;}}IloveChistringn!a\0字符指针初始化:把字符串首地址赋给string相当于以下两个语句:char*string;string=IloveChina!;string*string!=0(2)用字符指针实现*string15例字符串复制(1)用字符数组作参数voidcopy_string(charfrom[],charto[]){inti=0;while(from[i]!='\0'){to[i]=from[i];i++;}to[i]='\0';}main(){chara[]=Iamateacher.;charb[]=Youareastudent.;printf(string_a=%s\nstring_b=%s\n,a,b);copy_string(a,b);printf(\nstring_a=%s\nstring_b=%s\n,a,b);}2.用指向字符串的指针作函数参数16例10.19实现字符串复制voidcopy_string(char*from,char*to){for(;*from!='\0';from++,to++)*to=*from;*to='\0';}voidmain(){char*a=Iamateacher.123456789;charb[80]=Youareastudent.;printf(string_a=%s\nstring_b=%s\n,a,b);copy_string(a,b);printf(\nstring_a=%s\nstring_b=%s\n,a,b);}(2)用字符指针变量作参数注意:数组b要有足够的存储空间!17例charstr[10];scanf(%s,str);()而char*cp;scanf(%s,cp);()改为:char*cp,str[10];cp=str;scanf(%s,cp);()3.字符指针变量与字符数组的分别char*cp;与charstr[20];字符数组str由若干元素组成,每个元素放一个字符;而指针变量cp中只能存放一个地址值。charstr[20];str=IloveChina!;()char*cp;cp=IloveChina!;()str是地址常量;cp是地址变量。cp接受键入字符串时,必须先开辟存储空间。charstr[20]=……;()cp++;()str++;()str+1;()18charstr[]={“Hello!”};()charstr[]=“Hello!”;()charstr[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’};()char*cp=“Hello”;()inta[]={1,2,3,4,5};()int*p={1,2,3,4,5};()charstr[10],*cp;inta[10],*p;str=“Hello”;()cp=“Hello!”;()a={1,2,3,4,5};()p={1,2,3,4,5};()字符串用一维字符数组存放;一维字符数组中若有一个元素的值为0,则该数组可当字符串用;字符数组具