指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题
能否通过变量地址访问数据? 例 冒泡排序 void sort(int a[], int n) { int i,j; void main() 例 冒泡排序 //函数:输入数组a[n] void sort(int a[], int n) { int i,j; } void main() { int i,j,a[10]; printf("input 10 numbers:\n"); input(a,10); output(a,10); } n-1; n-1-j; for(j=0;j<9;j++) for(i=0;i< 9-j ;i++) if(a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } swap(a[i],a[i+1]); //函数:对数组a[n]冒泡排序 sort(a,10); 错!实参对形参 值传递 形参改变不影响实参 地址 问题引入:使用swap函数并不能交换(a[i],a[i+1]); 借鉴数组名作参数的方法=》需要地址传递 思考: (1)如何得到一个变量的地址? & (2)能否用一个变量来存放地址? 如何得到一个变量的地址? void swap(int x, int y) { int t; t=x; x=y; y=t; }
运算符 & 和 * 如何得到一个变量的地址? 运算符 & 功能:求变量的内存地址. 如何保存一个变量的地址? 指针变量 运算符 * 运算符 & 功能:求变量的内存地址. void sort(int a[],int n) { int i,j,t; for(j=0;j<n-1;j++) for(i=0;i<n-1-j;i++) if(a[i]>a[i+1]) swap(a[i],a[i+1]); } int i; int *p; scanf(“%d”, &i); p=&i; swap(&a[i], &a[i+1]); 如何保存一个变量的地址? 指针变量 运算符 * 功能:定义保存地址的变量 void swap( int x, int y) { int t; t=x; x=y; y=t; } void swap(int *p1, int *p2);
指针概念 3 6 ... .. 变量i 变量j 变量k 3010 2000 2002 2004 变量的值 内存地址 例:有定义: int i=3,j=6,k, *pointer; pointer=&i; k=i; k=*p; // 直接访问: 通过变量名i存取变量值 间接访问 (1)先在地址变量中找到i的地址 (2)再根据地址找到变量i,存取变量值。 3 指向 找到p指向的单元的内容 2000 变量pointer 变量pointer为指针变量,存放变量i的地址,称: pointer指向 i
指针变量的定义 1. 定义方式: 类型标识符 *指针变量名; 例:float *p1; (定义p1为指向float型变量的指针变量) 1. 定义方式: 类型标识符 *指针变量名; 例:float *p1; (定义p1为指向float型变量的指针变量) char *p2; (定义p2为指向char型变量的指针变量) 2. 指针变量的三要素: 指针变量的类型: 和其所指变量的类型一致; 指针变量的值:另一个变量在内存的地址; 指针变量的名字: 同普通变量。 例:int a=10, *p p=&a; 10 a a的地址 p 1000 3000 &a
指针变量的引用 指针变量名 = 某一地址; 例如: int i=10,*p,*q; p=&i; //方式1: 指针变量=&变量; 指向 10 i i的地址 p 1000 3000 &i q i的地址 & i q
指针举例 c=a+b A0801 指针变量定义及运算 main(){ int a=10,b=20,c; int *p,*q; p=&a; q=&b; c=*p+*q; printf("a=%d b=%d c=%d",a,b,c); } 10 20 a b c p q 30 c=a+b *p:指针p所指向的单元中的值10 *q:指针q所指向的空间中的值20 输出结果: a=10 b=20 c=30
指针举例 swap能交换sort函数中的变量吗? void sort(int a[],int n) { int i,j,t; for(j=0;j<n-1;j++) for(i=0;i<n-1-j;i++) if(a[i]>a[i+1]) swap(a[i],a[i+1]); } void swap( int x, int y) { int t; t=x; x=y; y=t; void sort(int a[],int n) { int i,j,t; for(j=0;j<n-1;j++) for(i=0;i<n-1-j;i++) if(a[i]>a[i+1]) swap(&a[i], &a[i+1]); } void swap(int *pa, int *pb); { int t; t=x; x=y; y=t; swap能交换sort函数中的变量吗? t=*pa; *pa=*pb; *pb=t;
值传递 a b 5 9 x y 9 y 5 x b a 9 5 变量x,y,t 释放 变量a,b的值不改变 9 5 5 5 9 b a main中 9 b 5 a 变量x,y,t 释放 变量a,b的值不改变 9 5 (参数传递初始) t a b void f(int x,int y) { int t; t=x; x=y; y=t; } 5 调用 f 函数 f 函数结束
地址传递 5 9 9 &b 5 &a 9 5 变量a,b的值改变,释放变量 t 和指针变量pa,pb 9 5 5 pa a a pa a (参数传递初始) t &a &b swap(int *pa,int *pb) { int t; t=*pa; *pa=*pb; *pb=t; } 5 调用swap函数 swap函数结束
指针变量作为函数参数 A0802例: 指针实现两数交换的函数 传递变量a,b的地址 void swap(int *pa,int *pb) { int t; t=*pa; *pa=*pb; *pb=t; } void main() {void swap(int *pa,int *pb); int a,b; scanf("%d,%d",&a,&b); swap(&a,&b); printf("\n%d,%d\n",a,b); } 传递变量a,b的地址 从键盘输入:5,10 输出: 10,5 (改变了a、b的值)
指针变量作为函数参数 A0802例: 指针实现两数交换的函数 int *p1,*p2; p1=&a; p2=&b; p1,p2 main() {void swap(int *pa,int *pb); int a,b; scanf("%d,%d",&a,&b); swap(&a,&b); printf("\n%d,%d\n",a,b); } void swap(int *pa,int *pb) { int t; t=*pa; *pa=*pb; *pb=t; } int *p1,*p2; p1=&a; p2=&b; p1,p2 从键盘输入:5,10 输出: 10,5 (改变了a、b的值) 传递变量a,b的地址
指针练习 main() { int *p1,*p2,*p,a,b; a=5;b=9; p1=&a;p2=&b; ① if (a<b) } ④ printf("a=%d,b=%d\n",a,b); printf("max=%d,min=%d\n",*p1,*p2); }
[例]不改变变量的内容,按大小顺序输出 main() { int *p1,*p2,*p,a,b; a=5;b=9; p1=&a;p2=&b; ① p1 5 a p if (a<b) { p=p1; ② p1=p2; ③ p2 9 b p2=p; } ④ printf("a=%d,b=%d\n",a,b); printf("max=%d,min=%d\n",*p1,*p2); } a=5, b=9 max=9, min=5 (仅仅按大小顺序输出,但是不改变a、b的值)
指针与数组 例 对一个班的所有学生求某门课程的平均成绩 问题:每个班的学生人数不同 => 动态输入班级人数 通过指针引用数组 例 对一个班的所有学生求某门课程的平均成绩 问题:每个班的学生人数不同 => 动态输入班级人数 数组定义: 类型 数组名[常量表达式]; 例:int a[30]; 1 代码 2 静态数据 3 动态数据 4 自由空间(堆heap) 地址常量 通过指针引用数组 动态分配一块存储空间,返回该存储空间的首地址(指针) 返回指针的函数 数组定义时要求 地址变量
指针的运算 1.算术运算 p 1000 例如: int *p,i; 1001 i char *q , c; 1002 p=&i; …... 2000 2001 c q p=p+1:新p指向下一元素 加一个类型的字节数,而不是加1 如:int 占 2个字节, char占1个字节。
指向数组元素的指针 int a[10]={0,2,4,6}; int *p, t1, t2; p=&a[0]; p=a; t1=*p+1; 地址 1000 1002 1004 1005 … 1018 p= p+1 p+2 p指向的单元内容+1,即a[0]+1 p+1指向的单元的内容, 即a[1] t1=1 t2=2 p+9
指向数组元素的指针 2 通过指针引用数组元素 a数组 a[0] a[1] a[2] a[i] a[9] p=a p+1 p+i p+9 2 通过指针引用数组元素 定义 int a[5], *p; p=a; 引用一个数组元素有两种方法: (1)下标法:a[i]; (2)指针法: *(p+i) 下标法: a[0] a[1] a[2] a[3] a[4] 指针法: *p *(p+1) *(p+2) *(p+3) *(p+4) 各元素地址 p p+1 p+2 p+3 p+4
指向数组元素的指针 A0803例 :用指针的方法访问数组 void main() { int array[10] ,i, *p; p=a p+1 p+i p+9 p+2 p+3 A0803例 :用指针的方法访问数组 void main() { int array[10] ,i, *p; for (i=0;i<10;i++) scanf("%d",&a[i]); p=array; p+i p++ p=array; for (i=0;i<10;i++) printf("%d", a[i] ); } for (p=array;p<(array+10);p++) printf("%d",*p); *(p+i) *(p++)
访问数组 数组名本身就代表数组地址,故通过数组名也可以访问数组 例如: int a[10],*p; p=a; &a[0] p 1 3 15 变量的地址 1 3 15 17 19 a[0] : a[9] 变量的值 例如: int a[10],*p; p=a; a+1或p+1 a+9或p+9
访问数组 若有数组及指针定义 int a[5],*p=a; 下标法: a[0] a[1] a[2] a[3] a[4] 指针法: *p *(p+1) *(p+2) *(p+3) *(p+4) *a *(a+1) *(a+2) *(a+3) *(a+4) 各元素地址 p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+4 注意:p++合法;但a++不合法 因为a是数组名,代表数组首地址,是常数地址 p是指针变量
指针练习2 10 30 (2)写出下面程序输出结果 main() { int a[3],*p=a; a[0]=10;a[1]=20;a[2]=30; printf(“%d\n”,*p++); printf(“%d\n”,*++p); } 先使用*p的值a[0], 再让p++指向a[1] 先让p+1指向a[2],再使用*p的值a[2] 10 30
指针练习3 4, 5, 7 (3) main() { int a[]={1,2,3,4,5}; int *p=a+3; printf(“%d,%d,%d\n”,*p,*(p+1),*p+3); } 4, 5, 7
返回指针的函数 1.定义: 类型标识符 *函数名(参数表); 函数名前有*,是指针函数,函数的返回值是指针类型 1.定义: 类型标识符 *函数名(参数表); 函数名前有*,是指针函数,函数的返回值是指针类型 int *max(int x,int y) { if(x<y) return(&x); else return(&y); } main() { int a,b,*p; int *max( ); scanf(“%d,%d”,&a,&b); p=max(a,b); printf(“max=%d”,*p); } 键盘输入: 1,2 屏幕输出: max=2
内存动态分配函数 #include<stdlib.h> 1. malloc 函数 内存动态存储区中分配一个长度为size的连续空间 2. free函数 释放空间 3. calloc函数 内存动态存储区中分配n个 长度为size的连续空间 引入:
创建动态长度数组--- calloc函数 A0804 动态输入班级人数,及学生成绩,求平均成绩 内存动态存储区中分配n个长度为size的连续空间 void main() { int n,i, *p; float aver; printf("请输入班级人数:"); scanf("%d",&n); p=calloc(n,sizeof (int)); printf("请输入学生成绩:"); printf("\n 平均成绩: %f\n", aver); } void inputarray( int *p, int n) { int i; } for(i=0;i<n;i++) scanf("%d",p+i); inputarray(p,n); float average( int *p, int n) { int i; return aver; } for(i=0,aver=0;i<n;i++) aver=aver+*(p+i); aver=aver/n; average(p,n);
多维数组的指针 1. 定义引用形式与指向一维数组的指针类似 例如: int a[3][4],*p; p=&a[2][3]; 2000 2002 2004 2006 2008 2010 2012 2014 2016 2018 2020 2022 a a+1 a+2 a[0]+1 a[0]+2 a[0]+3 行地址,元素地址的表示 2. 行列地址表示 若有定义:int a[3][4]; 下图表格中的数字表示每个元素的地址值
指针与字符串 例:char *s=“I Love China!” ; /*初始化s*/ s=string; /*字符数组赋值给字符串指针*/ 跟我来! 1. 字符串的表示形式 用字符数组实现(已学过): 例:char string[ ]="I Love China!"; ! e 串首址 I v ... s L o \0 用字符指针实现: 字符指针变量的定义:char *p ; 赋值: 指针=串中某一字符地址; 例:char *s=“I Love China!” ; /*初始化s*/ s=string; /*字符数组赋值给字符串指针*/ s=“ I love China!”; /*字符串整体赋值*/
指针与字符串 A0805例 :用字符指针逐个输出字符串中的字符 #include<stdio.h> void main() { char string[ ]="I like C language!"; char *p; for(p=string; *p!=‘\0’; p++) printf(“%c”,*p); printf(“\n”); } ! e 串首址 I k ... p L i \0
指 针 数 组 1. 概念:一个数组中的每个元素都是指针类型 2. 定义:数据类型 *数组名[数组长度] 2. 定义:数据类型 *数组名[数组长度] 例:int *p[4] /* 4个指向整形的指针构成的数组*/ char *p[3] /* 3个指向字符串的指针构成的数组*/ 每个指针变量 所指向的类型
指针数组实例 American China Japan A C J main() m h a { int i; char *sa[]={“American”,”China”,”Japan”}; for(i=0;i<3;i++) printf(“%s\t”,sa[i]); printf(“\n”); for(i=0;i<3;i++) printf(“%c\t”, *sa[i] ); } m h a *(sa[i]+1)
指向指针的指针 ------指向指针变量的指针. 定义形式: 类型 **变量名; 例如: int i,*p,**q; i=30; p=&i; 定义形式: 类型 **变量名; 例如: int i,*p,**q; i=30; p=&i; q=&p; printf(“%d”, i); printf(“%d”, *p); printf(“%d”, **q); 1000 2000 1001 3000 i p q 内存示意图: 30
指向函数的指针 1.函数名代表函数的入口地址 max 2.指向函数的指针的定义方式: 类型 (*指针变量名)( ); p 函数 数 … 类型 (*指针变量名)( ); max p 函数 数 … 例:设有函数定义: int max(…) {…….} int (*p) ( ); /*定义指向函数的指针变量*/ p=max; /* 使p指向max函数的入口地址,可以通过(*p)( 参数)来调用max函数*/
指向函数的指针 c=(*p)(a,b); 例 : 输入两个整形,返回最大值 main( ) int max(int x, int y) 例 : 输入两个整形,返回最大值 main( ) { int max(int,int); int (*p) ( ); //指向函数的指针变量 int a,b,c; p=max; /*指针变量赋值*/ scanf("%d,%d",&a,&b); c=max( a, b) ; /*调用函数*/ printf("a=%d,b=%d,max=%d",a,b,c); } int max(int x, int y) { int z; if (x>y) z=x; else z=y; return (z); } c=(*p)(a,b);
命令行参数1 main函数可以有参数,使用指针数组作为形参 main(int argc, char *argv[]) { 函数体; } 字符串指针数组 存放接收的参数 argv[i] 指向一个参数 其中argv[0]指向命令名 接收到的 参数个数 main函数的实参和命令一起给出,格式如下: 命令名 参数1 参数2 参数3 ……. 说明:命令名 是main函数所在的文件名
命令行参数2 程序调试运行步骤 如源文件保存为 limain.c 保存路径为 D:\C 经过编译生成 limain.obj 经过链接生成 limain.exe 例 :带参数的main函数。 main(int argc, char *argv[]) { int i; for(i=1;i<argc;i++) printf("%s\n",argv[i]); } 在DOS下输出 java c++ 打开DOS环境,进入D:\C D:C\>limain java c++
命令行参数3 argc=3 例 :带参数的main函数。 main(int argc, char *argv[]) { int i; for(i=1;i<argc;i++) printf("%s\n",argv[i]); } 打开DOS环境,进入D:\C D:C\>limain java c++ argv argv+1 argv+2 argv[0] argv[1] argv[2] limain\0 java\0 c++\0 main(int argc, char *argv[]) { while( argc>1) { ++argv; printf(“%s\n”, *argv); --argc ; } argc=3 在DOS下输出 java c++
指针小结 int *p1 ; /*指向整形变量,整形数组的指针变量*/ char *p /*指向字符串的指针变量*/ int *a(int x,float y) /*返回指针值的函数*/ {…函数体…} int *p[4] /* 指向整形的指针数组*/ char *p[4] /* 指向字符串的指针数组*/ int **q /*指向指针变量的指针*/
指针 习题 B0801(习题8.5)有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位? B0802 (习题8.17)自己写一个函数,实现字符串的比较