第七章 指针 指针与指针变量 指针与数组 指针与函数 指针与字符串
学习目标 重点 了解 掌握 指针与指针变量 指针与数组 指针与函数 1
7.1 7.2 7.3 7.4 章节框架 指针与指针变量 指针与数组 指针与函数 指针与字符串 ☞点击查看本小节知识架构
7.1 指针与指针变量 【任务描述】: 使用指针,从键盘输入圆的半径r的值,并使用指针计算圆的面积s。 #include<stdio.h> #define PI 3.14 void main() {float r,s=0.0; printf("请输入半径"); scanf("%f",&r); s=PI*r*r; printf("圆的面积为%f\n",s); }
7.1 指针与指针变量 7.1.1 指针的概念 一个变量的地址称为该变量的“指针”。如果有一个变量专门用来存放其他变量的地址(指针),这个变量被称为“指针变量”。 0x804a020 0x804a120 10
7.1 指针与指针变量 7.1.1 指针的概念 指针和指针变量是两个完全不同的概念,指针是一个地址,而指针变量是存放地址(指针)的变量。
7.1 指针与指针变量 7.1.2 指针变量的定义 指针变量在使用前首先需要定义,定义指针变量的语法格式如下所示: 指针变量只能接受其他变量的地址作为其值。获取变量地址的语法格 式如下所示: 基类型 * 变量名; &变量名;
7.1 指针与指针变量 7.1.2 指针变量的定义 定义指针变量的方式有两种,具体如下: 定义指针变量的同时对其赋值 int a; int * p = &a; 第1种 先定义指针变量,再对其赋值 int * p; int a; p = &a; 第2种
7.1 指针与指针变量 【任务】用指针实现计算圆的面积。 #include<stdio.h> #define PI 3.14 void main() {float r,s=0.0; float *pr,*ps; pr=&r; ps=&s; printf("请输入半径"); scanf("%f",&r); *ps=PI*(*pr)*(*pr); printf("圆的面积为%f\n",*ps); } 思考: 如何输出r和s的内存地址?
7.1 指针与指针变量 7.1.3 指针变量的引用 所谓引用指针变量指向的变量,就是根据指针变量中存放的地址,访问该地址对应的变量。访问指针变量指向变量的方式非常简单,只需在指针变量前加一个“*”(取值运算符)即可,访问指针变量的语法格式如下所示: * 指针表达式;
7.1 指针与指针变量 【例】从键盘输入两个数值分别送给变量x和y,按由大到小的顺序输出。 void main() {double x,y,*px,*py,t; px=&x; py=&y; printf("请输入第一个数x="); scanf("%lf",px); printf("请输入第二个数y="); scanf("%lf",py); if(* px<*py) {t=* px;*px=*py;*py=t; } printf("x=%.2lf,y=%.2lf",x,y); printf("max=%.2lf,min=%.2lf\n",*px,*py);}
7.1 指针与指针变量 【课堂练习】读程序,输出结果是? #include<stdio.h> void main() {int num=100; int *p=# printf("num=%d\n",num); printf("*p=%d\n",*p); printf("p=%d\n",p); }
7.1 指针与指针变量 7.1.4 指针的运算 指针作为一种数据类型在程序中也经常需要参与运算,包括指针与整数的加减、同类指针相减、同类指针关系运算等。 同类指针关系运算 同类指针相减运算 == != < > <= >= 与整数进行加减运算 - + - ++ --
7.1 指针与指针变量 - 7.1.4 指针的运算 1、与整数进行加减运算 指针与整数进行相加、相减运算,实际上是将指针进行上移、下移操作。 int a; int *p = &a; p = p+1 == != < > <= >= -
小结 小结 指针的概念及基础知识 指针的定义及引用
课堂作业 1、定义3个变量a、b、c,分别是int 、 char 、 double类型,定义3个指针变量pa 、pb 、pc,分别指向a、b、c三个变量,利用指针变量给对应的变量赋值,然后分别输出a、b、c和*pa、*pb、*pc。 2、从键盘输入3个整数分别送给变量x、y、z,定义3个指针变量分别指向x、y、z这3个变量,然后利用指针变量,比较这3个数,按由小到大的顺序输出。要求采用两种方法。 方法1:交换指针变量指向的变量值。 方法2:交换指针变量的值。 3、请完成在线评测系统训练场的1036-----1042。
7.2 指针与数组 7.2.1 指针与一维数组 p[下标] // 下标法 或 *(p + 下标) // 指针法 假设指针变量p指向了数组arr,若想引用一维数组中的元素,可以通过下列两种方式。 p[下标] // 下标法 或 *(p + 下标) // 指针法
7.2 指针与数组 7.2.1.1通过指针变量来使用一维数组 1.数组与数组的指针变量 数组的地址与数组的指针:数组中首个元素的地址就是数组的地址,也就是数组的指针。 上图中,a这个一维数组的地址就是a[0]的地址。 数组名与数组的地址:C语言规定,数组名代表数组的地址,即数组首元素的地址。 数组的指针变量:如果一个指针变量存放着数组首元素的地址(数组的地址),即指针变量指向数组的首个元素,则这个指针变量可看作是数组的指针变量 例如:我们用int a[10] , *p;语句定义了数组a和指针变量p,如果有p=a;或者p=&a[0];则指针变量p存放着数组a的地址,即p指向了数组a的首个元素,从而p可以称作数组a的指针变量。
7.2 指针与数组 2. 通过指针变量来使用数组 若p是int型指针变量,并且p已经指向了某个数组元素。如果n是正数,则 p=p+n会使指针变量p指向原位置后面的第n个数组元素。如果n是负数,则p会指向 原位置前面的第n个数组元素。见图8-9所示。
7.2 指针与数组 数组与指针的关系
7.2 指针与数组 [课堂举例] 打印数据中的每个数据元素。 arr p h e l l o #include <stdio.h> void main() { char arr[5]={'h','e','l','l','o',}; char *p=arr; int i=0; while(i<5) printf("%c",*p); p++; i++; } printf("\n"); p h e l l o
7.2 指针与数组 【例题7-7】利用指针变量给N个元素的float型数组赋值,并逆序输出数组各个元素的值(N的值自定,合理即可)。 #include<stdio.h> void main() {float a[5]={0.0},*p; int i; for(p=a,i=1;i<=5;i++) { printf("请输入第%d个数值",i); scanf("%f",p); p++; } printf("数组逆序输出结果为\n"); for(p=&a[4],i=1;i<=5;i++) {printf("%-10.2f",*p); p--;} printf("\n");
7.2 指针与数组 7.2.3数组的指针变量与数组名的关系 例如int a[10],*p=a; 此时此刻该指针变量也代表数组的首地址,那么数组名a和其指针变量p之间有什么关系呢? 1. 数组指针变量p的值可以改变,数组名a的值不能改变 p的值可以改变,但a的值不能改变,如p++;p=p+5;p--;--p等都是正确的,但a++;a=a+5;a--;--a等都是错误的。即数组名永远代表数组的首地址,不能被更改,但数组的指针变量可以任意改变指向,只要合理即可。
7.2 指针与数组 2. 数组的指针变量p可以当数组名使用,数组名a也可以当指针变量使用 除了上面的区别,在使用上数组名和数组的指针变量几乎没有区别。即当指针变量p指向数组a的首个元素时, p+i,a+i,&a[i],&p[i]都代表第i个元素的地址, *(p+i),*(a+i), p[i], a[i]都代表第i个元素。p与a在这点上是等价的。 3. 但若p指向的不是数组的首地址,则上面就不等价。
7.2 指针与数组 【例题】利用数组的指针变量可以当数组名使用的原理,输入一行字符,并按照降序的形式对该行字符排序,并输出结果。 #include<stdio.h> void main() {char x[101],*p,t; int i,j,n; p=x; printf("请输入一行字符(不要超过100个)"); gets(p); printf("你输入的字符串为:%s\n",p); n=strlen(p); for(i=0;i<n;i++) { for(j=0;j<n-i;j++) {if(p[j]<p[j+1]) {t=p[j],p[j]=p[j+1],p[j+1]=t;} } printf("排序后的字符串为:%s\n",p);}
课堂练习 【课堂练习】定义一个函数get_max(),求出数组中m个数的最大值,并返回所求的值,主函数定义有关数据,并调用函数求出结果,主函数中输出所求的结果。
课堂作业 1、在第一例子的基础上,打印出指针每一次移动后的地值。 2、写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。 3、编写程序,将数组中的数按颠倒的顺序重新存放。在操作时,只能借助一个临时存储单元而不得另外开辟数组。 分析:不是要求按颠倒的顺序打印数据,而是要求按逆序重新存放。 4、定义3个变量a、b、c,分别是int、char、double类型,定义3个指针变量pa、pb、pc,分别指向a、b、c三个变量(即把变量的地址送给对应的指针变量),利用指针变量给对应的变量赋值,然后分别输出a、b、c和*pa、*pb、*pc的值。 5、请完成在线评测系统训练场的1036-----1042。 1、#include <stdio.h> void main(){ char arr[5]={'h','e','l','l','o',}; char *p=arr; int i=0; printf("arr=%d\n",arr); while(i<5) {printf("第%d个元素地址:%d\n",i+1,p); p++; i++; } 2、#include<stdio.h> Void main() {int length(char *p); int len; char str[20]; Printf(“input string:”); Scanf(“%s”,str); Len=length(str); Printf(“the length of string is %d\n”,len);} Int length(char *p) {int n=0; While(*p!=‘\0’) {n++; p++;} Return(n);}
课下作业 1、定义一个10个元素的一维float型数组,定义一个指针变量p指向数组首元素,然后用指针变量结全循环给数组元素赋值,用指针变量结合循环输出每个元素的值。除了题目中要求的变量(数组名和指针)之外,不准再定义其他变量。 2、从键盘输入3个整数分别送给变量x、y、z,定义3个指针变量分别指向x、y、z这3个变量,然后利用指针变量,比较这3个数,按由小到大的顺序输出,要求采用两种方法。方法1、交换指针变量指向的变量值。方法2、交换指针变量的值。 3、定义一个函数,其形式如下: Void change(int *p1,int *p2){ }主函数中定义两个整型变量a和b,并赋值,然后调用change()函数,并把a和b的地值传给p1和p2,然后输出a和b的值。
练习课 用指针比较三个数的大小。 void main() { #include<stdio.h> int a,b,c; int *i,*j,*p; i=&a; j=&b; p=&c; printf("请输入三个整数:"); scanf("%d%d%d",i,j,p); if(a>b) f(i,j); if(a>c) f(i,p); if(b>c) f(j,p); printf("now,the order is:%d,%d,%d\n",a,b,c); } #include<stdio.h> void f(int *p,int *q) {int a; a=*p,*p=*q;*q=a; }
课堂练习 【练习1】输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写3个函数: 输入10个数; 进行处理; 输出10个数; 【练习2】有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
课堂作业 1、用指针编写函数,求一个整型数组的平均值、最大值、最小值。主函数调用测试。
7.3 指针与函数 7.3.1 指针作为函数参数 在C语言中,指针除了可以参与运算,还可以作为函数的参数来使用,它的作用是将一个变量的地址传送到另一个函数中。 交换两个变量的值 void swap(int * a, int * b) { int temp; temp=*a; *a=*b; *b=temp; }
7.3 指针与函数 7.3.2 数组指针作为函数参数 当指针指向的是一个函数时,这个指针就称为函数指针。 让IT教学更简单,让IT学习更有效 7.3.2 数组指针作为函数参数 当指针指向的是一个函数时,这个指针就称为函数指针。 函数的形参数组名和数组的指针变量完全等价,则函数间的数组传递存在以下关系: 1、当实参为数组名时,形参可以为数组,也可以为指针变量,且形参的实质就是一个指针变量。 2、当形参为数组时,实参可以为数组名,也可以为指针变量,同时也可以是某个元素的地址。
课堂举例 读程序 #include <stdio.h> void func(int a[5]) { printf("a=%p,sizeof(a)=%d\n",a,sizeof(a)); } void main() { int arr[5]; printf("arr=%p,sizeof(arr)=%d\n",arr,sizeof(arr)); func(arr); 注意事项: 1.如果我们使用数组名作为函数参数,那么数组名会立刻转换为指向该数组第一个元素的指针。C语言会自动的将作为参数的数组声明转换为相应的指针声明。 2.除了a被用作运算符sizeof的参数这一情形,在其他所有的情形中数组 名a都代表指向数组a中下标为0的元素的指针。
7.3 指针与函数 数组名做函数参数 要了解数组名做函数参数传递,我们先看下图所示的代码模式: void main() { int a[10]; …… test(a); } void test(int b[10]) { …… }
7.3 指针与函数 1、一维数组和函数 (1)进行函数调用时,若传送的是地址,则形参应为指针变量。 (2)若传送的是数组元素,则形参是普通变量。 2、二维数组和函数 (1)数组名作为实参的时候,形参为行指针。 (2)数组元素作为实参的时候,形参为普通变量。
7.3 指针与函数 【课堂举例】编程,定义函数,完成对整形数组的赋值和输出,主函数负责统筹调度。 # include <stdio.h> void main() { int x[10]; inputarry(x,10); printarry (x,10);} void printarry(int c[],int m) {int i; for(i=0;i<m;i++) printf(“%4d”,c[i]); printf(“\n”); } void inputarry(int a[],int m) {int i; for(i=0;i<m;i++) {printf(“请输入第%d个整数:”,i+1); scanf(“%d”,&a[i]);} }
7.3 指针与函数 指针变量和其他变量一样,也可以作为函数参数传递,同理,如果需要,函数也可以返回一个指针。 【课堂举例】编写函数myadd(int *a,int *b) 函数中把两个指针a和b所指的存储单元中的两个值相加,然后将和值作为函数值返回。在主函数中输入两个数给变量,把变量地址作为实参,传递给对应形参。
7.3 指针与函数 …... 2000 2008 200A 2002 2004 2006 200C 200E #include “stdio.h” int myadd(int *a,int *b) {int sum; sum=*a+*b; return sum; } a 2008 200A b 15 sum main() {int x,y,z; printf(“Enter x,y:”); scanf(“%d%d”,&x,&y); z=myadd(&x,&y); printf(“%d+%d=%d\n”,x,y,z); } x 6 y 9 15 z 通过传送地址值,可以在被调用函数中对调用函数中的变量进行引用。
7.3 指针与函数 【课堂练习】定义一个函数,利用指针作为函数参数,求m个数组元素的和,并返回所求的结果。 int sum(int a[],int m) {int s=0,i; for(i=0;i<m;i++) {s=s+*a; a++;} return s; } main() {int a[]={1,2,3,4,5,6,7,8,9,10},sum1=0; sum1=sum(a,10); printf("1+2+3+...+10=%d ",sum1);
课堂作业 1、用指针法来解决杨辉三角问题。 2、写一函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。 1、#include<stdio.h> double get_max(double *a,int m) {int i; double max=*a; for(i=1;i<m;i++) {a++; if(max<*a) max=*a; } return max; main() {double b[10]={1,200,36,4,523,7,876,9,910,888}; printf("b[0]~b[9]之间的最大值=%.01f\n",get_max(b,10)); printf("b[0]~b[3]之间的最大值=%.01f\n",get_max(b,4)); printf("b[0]~b[7]之间的最大值=%.01f\n",get_max(&b[2],6)); 2、#include<stdio.h> void main() {void input(int *); void max(int *); int number[10]; input(number); max(number); output(number); void input(int *number) { int i; printf("input 10 numbers:"); for(i=0;i<10;i++) scanf("%d",&number[i]); void max(int *number) { int *max,*min,*p,temp; max=min=number; for(p=number+1;p<number+10;p++) if(*p>*max) max=p; else if(*p<*min) min=p; temp=number[0];number[0]=*min;*min=temp; if(max==number) max=min; temp=number[9];number[9]=*min;*min=temp; void output(int *number) {int *p; printf("now,they are:"); for(p=number;p<number+10;p++) printf("%d ",*p); printf("\n");
课堂作业 1、定义函数void sort(int *x,int n),利用选择法排序,完成对指针x所指向的n个数的排序,要求用指针法完成。 4、#include <stdio.h> void sort(int a[],int n); int main() { int i,a[10],*p=a; for(i=0;i<10;i++)scanf("%d",p+i); sort(a,10); for(i=0;i<10;i++)printf("%d ",*(p+i)); return 0; } void sort(int a[],int n) { int i,j,t,m,c; for(i=0;i<n-1;++i) { c=0;m=i;t=a[i]; for(j=i+1;j<n;++j)if(a[j]<t){m=j;t=a[j];c=1;} if(c){a[m]=a[i];a[i]=t;} 5、#include <stdio.h> void main() {int i,k,m,n,num[50],*p; printf("input number of person:n="); scanf("%d",&n); p=num; for(i=0;i<n;i++) *(p+i)=i+1; i=0;k=0;m=0;//i为每次循环时计数变量,k为按1,2,3报数时的计数变量;m为退出人数 while(m<n-1) {if(*(p+i)!=0) k++; if(k==3) {*(p+i)=0; k=0; m++;} i++; if(i==n) i=0;}//报数到尾后,i恢复为0 while(*p==0) p++; printf("the last one is NO.%d\n",*p);
7.4 指针与字符串 【任务描述】: 用户登录界面,对用户名和密码进行校验,如果验证通过,提示“登录成功”,否则提示“登录失败,请检查用户名或密码是否正确输入”,指针实现。
7.4 指针与字符串 7.4.1、字符串的表示形式 1、用字符数组存放一个字符串 例如:将字符串“department”存放字符数组as中,代码如下:char as[12]=“department” char as[]=“department” 2、用字符指针指向一个字符串 可以不定义字符数组,而定义一个字符指针,指向字符串。 例如:char *p=“computer”; char *p; p=“computer”;
7.4 指针与字符串 【课堂举例】定义一个字符数组,接受一行字符(最多不超过100个),统计一下这行字符中总共用了多少个英文单词。 #include <stdio.h> void main() { //统计一行文字中的单词个数,用指针实现 char str[100]; int i=0,num=0; char *p; printf("请输入一行文字:\n"); gets(str); p=str; //因为单词之间是用空格隔开的,只要统计出句子中 //空格的个数就可以了,另外统计完空格后还要给记 //数器再加1,要不句末的那个单词就统计不到了 while(*(p+i)!='\0') { if(*(p+i)==' ') num++; i++; } printf("你输入的字符是:"); puts(str); printf("num=%d \n",num+1);
7.4 指针与字符串 3、字符串指针变量做函数参数 将一个字符串从一个函数传到另一个函数,其传递方法和数组传递等价。都有两种方法,即用字符数组名做函数参数和用字符指针变量做函数参数,并且形参与实参能结合出四种情况。
7.4 指针与字符串 【例7-13】编程,声明函数copyString,完成和系统库函数strcpy相似的功能 #include "stdio.h" #include<string.h> void copystring(char *p1,char *p2) { while(*p2!='\0') {*p1=*p2; p1++; p2++;} *p1='\0'; } void main() char a[100]="hello,Beijing",b[100]="welcome to China"; copystring(a,b); printf("%s\n",a);
7.4 指针与字符串 【任务】登录界面程序。 #include<string.h> void main() { char username[100],password[100]; printf(“请输入用户名:º"); gets(username); printf(“请输入密码"); gets(password); if(strcmp(username,"ILove")==0&&(strcmp(password,"user"))==0) printf(“用户%s登录成功¦!\n",username); else printf(“登录失败,请检查用户名或密码是否正确输入\n"); }
7.3 指针与函数 【课堂练习】用指针实现,编写一函数用来判断字符串中子串出现的次数。 int sum(int a[],int m) {int s=0,i; for(i=0;i<m;i++) {s=s+*a; a++;} return s; } main() {int a[]={1,2,3,4,5,6,7,8,9,10},sum1=0; sum1=sum(a,10); printf("1+2+3+...+10=%d ",sum1);
课堂作业 1、如果一个字符串正过来读和倒过来读是一样的,那么这个字符串就被称为回文串,请编写一程序,判断字符串MADAM是否是回文串。 2、有一字符串a,内容为“My name is Li jilin.”,另有一字符串b,内容为“Mr.Zhang Haoling is very happy”。写一函数,将字符串b从第3个到第17个字符(即“Mr.Zhang Haoling”)复制到字符串a中,取代字符串a中第12个字符以后的字符(即“Li jilin”)。输出新串a。 #include<stdio.h> #include<string.h> int isletter(char *p) {if(*p>='A'&&*p<='Z'||*p>='a'&&*p<='z') return 1; else return 0; } void main() { char a[101],*p=a; int i,n=0; printf("输入一句话:"); gets(p); while(p<a+strlen(a)) {if(p==a) {if(isletter(p)==1) n++; else if(isletter(p)==1&&isletter(p-1)==0) p++; printf("你输入的内容是:%s\n总共用了%d个英文单词\n",a,n);
本章小结 本章小结 本章首先讲解了指针与指针变量的概念,然后讲解了指针与数组、指针与函数、指针数组与字符等。通过本章的学习,读者应该能够熟练掌握指针的运算以及指针的用法。指针是C 语言的核心内容,希望大家能够好好实践本章的例子,加深对指针的理解 。