C语言基础——指针的高级应用 Week 05
内容指要 指针内容复习 指针与多维数组 指针数组 多级指针 *函数指针
Max=100,min=-3 指针 运行结果: enter 10 integer numbers -2 4 6 8 0 -3 45 67 89 100 the 10 integer numbers: -2 4 6 8 0 -3 45 67 89 100 Max=100,min=-3 指针 void main() { int i,number[10],*p; p=number; printf("enter 10 integer numbers:\n"); for(i=0;i<10;i++,p++) scanf("%d",p); printf("the 10 integer numbers:\n"); for(p=number,i=0;i<10;i++,p++) printf("%d ",*p); max_min_value(p,10); printf("\nmax=%d,min=%d\n",max,min); } int max,min; void max_min_value(int *array, int n) { int *p,*array_end; array_end=array+n; max=min=*array; for(p=array+1;p<array_end;p++) if(*p>max) max=*p; else if(*p<min) min=*p; return; }
指针 void copy_string(char *from,char *to) { for(;*to++=*from++;); } void main() { char a[]="I am a teacher."; char b[]="You are a student."; printf("string_a=%s\nstring_b=%s\n",a,b); copy_string(a,b); printf("\nstring_a=%s\nstring_b=%s\n",a,b); }
指针与多维数组 由于多维数组使用较少,且使用方法可以由一维和二维的关 系推得,因此这里主要讲的是指针与二维数组的关系 二维数组可以看作是n个相同数据类型的一维数组的集合,而 每个一维数组数组名是一个静态指针,因此二维数组也可看 做是n个相同类型的静态指针的集合,而二维数组名就是n个 静态指针中第一个指针的地址 例:定义二维数组: int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 该二维数组由三个一维int型数组组成,且三个int数组的头地址分别是 a[0],a[1],a[2],因此a[0]==&a[0][0],a[1]==&a[1][0], a[2]==&a[2][0] 以上结论可得,二维数组名也就是a本质上是a[0]的地址,也就是一个 指针的地址,因此*a取出的值是a[0],依然是一个地址
指针与二维数组 a 因此可以很清楚的得到,当我们在对a进行运算的时候,其偏移 的单位不再是int,而是其元素值,也就是数组的长度,也就是 1 3 5 7 9 11 13 15 17 19 21 23 a[0] a[1] a[2] = 因此可以很清楚的得到,当我们在对a进行运算的时候,其偏移 的单位不再是int,而是其元素值,也就是数组的长度,也就是 说当a+1时,a+1不是指向了矩阵中第二个元素3,而是直接指向了 二维数组的第二个元素,也就是数组a[1],a+2时,也不会指向第 三个元素5,而是直接指向了第三个数组a[2]。 在对二维数组名使用了取值运算符*后,提取出的是第一个数组, 也就是其首地址,此时再进行加法运算(*a)+1,此时指针指向的就 是数组a[0]当中的第二个元素a[0][1]
指针与二维数组 a[0]+0 a[0]+1 a[0]+2 a[0]+3 *(a+0)+0 *(a+0)+1 *(a+0)+2 2000 a[0][0] 2004 a[0][1] 2008 a[0][2] 200C a[0][3] a[1]+0 a[1]+1 a[1]+2 a[1]+3 *(a+1)+2 *(a+1)+0 *(a+1)+1 *(a+1)+3 a+1 2010 a[1][0] 2014 a[1][1] 2018 a[1][2] 201C a[1][3]
指针与二维数组 a[2]+0 a[2]+2 a[2]+1 a[2]+3 *(a+2)+2 *(a+2)+3 *(a+2)+1 2020 a[2][0] 2024 a[2][1] 2028 a[2][2] 202C a[2][3]
指针与二维数组 由于增加了一个维度,在操作上会有很多的层次嵌套问题, 因此必须清楚常见的二维数组操作表达式代表的意思 例:对二维数组 int a[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]
指针与二维数组 例:输出二维数组相关的值 #define FORMAT "%d,%d\n" void main() {int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; printf(FORMAT,a,*a); printf(FORMAT,a[0],*(a+0)); printf(FORMAT,&a[0],&a[0][0]); printf(FORMAT,a[1],a+1); printf(FORMAT,&a[1][0],*(a+1)+0); printf(FORMAT,a[2],*(a+2)); printf(FORMAT,&a[2],a+2); printf(FORMAT,a[1][0],*(*(a+1)+0)); }
指针与二维数组 之前所提到的,都是在二维数组名这个静态指针上面进行的 指针操作,并没有真的定义一个指针变量来存储二维数组。 由于二维数组是一维数组的集合,因此使用指针来定义二维 数组和一维数组的指针定义一样——通过一个指针来指向第 一个元素,也就是第一个数组,所以只需要将数组第一维改 成指针形式即可 定义形式: 数据类型 (*指针名)[一维数组维数]; 例 int (*p)[4];定义了指向包含4个整型元素的一维数组 注:切记不能忘记括号,由于只是将第一维改变为指针形式, 如果不写括号就会变成指针数组的定义方式,二者完全不同
指针与二维数组 void main() {int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4],i,j; p=a; scanf("i=%d,j=%d",&i,&j); printf("a[%d,%d]=%d\n",i,j,*(*(p+i)+j)); } 运行结果: i=1,j=2 a[1][2]=13
指针与二维数组 例:3个学生各4门课,计算总平均分,并输出第n个学生成绩 void average(float *p,int n); void search(float (*p)[4],int n); void main( ) {float score[3][4]={{65,67,79,60},{80,87,90,81},{90,99,100,98}}; average(*score,12); search(score,2); } void average(float *p,int n) { 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); } void search(float (*p)[4], int n) { int i; printf(" No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(p+n)+i)); } 运行结果: Average=82.25 90.00 99.00 100.00 98.00
指针与二维数组 运行结果: No.1fails,his scores are: 65.0 57.0 70.0 60.0 例 3个学生各学4门课,查找一门以上课程不及格学生, 输出其各门 课程的成绩 void search(float (*p)[4], int n) { int i,j,flag; for(j=0;j<n;j++) { flag=0; for(i=0;i<4;i++) if(*(*(p+j)+i)<60) flag=1; if(flag==1) { printf("No.%d is fail,his scores are:\n",j+1); printf("%5.1f ",*(*(p+j)+i)); printf("\n"); } void search(float (*p)[4], int n); void main() {float score[3][4]={{...},{...},{...}}; search(score,3); 运行结果: No.1fails,his scores are: 65.0 57.0 70.0 60.0 No.2fails,his scores are: 58.0 87.0 90.0 81.0
指针数组 数组可以用来存放任何数据类型的集合,因此也可以用于存 放指针类型。通常,指针数组是用来存放多个字符串的 指针数组 定义:数组中的元素为指针变量 定义形式:[存储类型] 数据类型 *数组名[数组长度]; 例 int *p[4]; //注意与二维数组指针形式的区别 指针数组的赋值与初始化 赋值: void main() { int b[2][3],*pb[2]; pb[0]=b[0]; pb[1]=b[1]; …….. } 初始化: void main() { int b[2][3],*pb[ ]={b[0],b[1]}; …….. }
指针数组 int *pb[2] pb[0] pb[1] int b[2][3] 1 2 3 4 6
指针数组 赋值: 或: 初始化: void main() void main() { char a[]="Fortran"; L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3] 赋值: void main() { char a[]="Fortran"; char b[]="Lisp"; char c[]="Basic"; char *p[4]; p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; …….. } 或: { char *p[4]; p[0]= "Fortran"; p[1]= "Lisp"; p[2]= "Basic"; p[3]=NULL; 初始化: void main() { char *p[]={"Fortran", "Lisp", "Basic",NULL}; …….. } L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3]
指针数组 通常,指针数组用来存放多个字符串信息,与用二维数组相 比,指针数组有着很大的优势,因为二维数组存放的数组长 度必须是相同的,在用来存放许多长度不相同的字符串的时 候就会出现空间的浪费——因为必须要用这些字符串当中最 长的字符串来定义二维数组中存放的数组长度 例: char name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”}; g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 name[0] name[1] name[2] name[3] name[4] b y e \0 g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 b y e \0 char *name[5]={“gain”,“much”,“stronger”, “point”,“bye”};
指针数组 例:对字符串由小到大排序(简单选择排序)
指针数组 void sort(char *name[],int n); void print(char *name[],int n); void main() { char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer "}; int n=5; sort(name,n); print(name,n); } void sort(char *name[],int n) { char *temp; int i,j,k; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(strcmp(name[k],name[j])>0) k=j; if(k!=i) { temp=name[i]; name[i]=name[k]; name[k]=temp;}
指针数组 k k j j j j i=0 name name[0] Follow me BASIC name[1] name[2] Great Wall FORTRAN Computer Follow me BASIC k k j j j j i=0
指针数组 k j k j k j i=1 name name[0] Follow me BASIC name[1] name[2] Great Wall k j name[3] FORTRAN k j name[4] Computer i=1
指针数组 k k j j i=2 name name[0] Follow me BASIC name[1] name[2] Great Wall k j name[3] FORTRAN j name[4] Computer i=2
指针数组 k k j i=3 name name[0] Follow me BASIC name[1] name[2] Great Wall FORTRAN k j name[4] Computer i=3
指针数组 name name[0] Follow me BASIC name[1] name[2] Great Wall name[3] FORTRAN name[4] Computer
多级指针 定义:指向指针的指针 一级指针:指针变量中存放目标变量的地址 例 int *p; int i=3; 二级指针:指针变量中存放一级指针变量的地址 例 int *p; int i=3; p=&i; *p=3; &i 3 P(指针变量) i(整型变量) 例 int *p1; int **p2; int i=3; p1=&i; p2=&p1; **p2=3; p2 &p1 &i 3 P1(指针变量) i(整型变量)
二级指针 i p1 p2 3 &i &p1 **p2, *p1 *p2 定义形式:[存储类型] 数据类型 **指针名; 定义形式:[存储类型] 数据类型 **指针名; 如 char **p; i p1 p2 3 &i &p1 例 int i=3; int *p1; int **p2; p1=&i; p2=&p1; **p=3; **p2, *p1 *p2 例 int i, **p; p=&i; ()//p是二级指针,不能用变量地址为其赋值
二级指针 1 2 2004 2000 2008 200C 2000 输出: 2,1 (main) 2000 变量a 变量b 2004 2010 2014 2004 2008 200C 1 2 变量a 变量b (main) 指针变量p 指针变量q #include <stdio.h> void swap(int **r,int **s) { int *t; t=*r; *r=*s; *s=t; } void main() { int a=1,b=2,*p,*q; p=&a; q=&b; swap(&p,&q); printf("%d,%d\n",*p,*q); 2004 2000 二级指针s 二级指针r (swap) 指针变量t 200C 2008 2000 输出: 2,1
二级指针 p a q b p r a s b q p r a s b q p b q a #include <stdio.h> void swap(int **r,int **s) { int *t; t=*r; *r=*s; *s=t; } void main() { int a=1,b=2,*p,*q; p=&a; q=&b; swap(&p,&q); printf("%d,%d\n",*p,*q); a b r s p q a b r s p q b a p q
二级指针 #define NULL 0 void main() { char **p; name[0] name[1] name[2] name[3] name[4] char *name[5] world bye \0 hello good name p 二级指针 #define NULL 0 void main() { char **p; char *name[]={"hello","good","world","bye",""}; p=name+1; printf("%o : %s ", *p,*p); p+=2; while(**p!=NULL) printf("%s\n",*p++); }
二级指针 二级指针与指针数组的关系 指针数组名是二级指针常量 p=q; p+i 是q[i]的地址 int **p 与 int *q[10] 指针数组名是二级指针常量 p=q; p+i 是q[i]的地址 指针数组作形参,int *q[ ]与int **q完全等价;但 作为变量定义两者不同 系统只给p分配能保存一个指针值的内存区;而给 q分配10块内存区,每块可保存一个指针值
小结 指针的数据类型 定义 含义 int i; 定义整型变量i p为指向整型数据的指针变量 int *p; int a[n]; int *p[n]; int (*p)[n]; int f(); int *p(); int (*p)(); int **p; 定义整型变量i p为指向整型数据的指针变量 定义含n个元素的整型数组a n个指向整型数据的指针变量组成的指针数组p p为指向含n个元素的一维整型数组的指针变量 f为返回整型数的函数 p为返回指针的函数,该指针指向一个整型数据 p为指向函数的指针变量,该函数返回整型数 p为指针变量,它指向一个指向整型数据的指针变量 指针的数据类型