第八章 指针
第八章 指针 8.1 指针的基本知识 8.2 指针与维数组 8.3 指针与字符串 8.4 指针数组与指向多级指针 8.5 指针与函数
第八章 指针 本章学习目标 理解指针的概念 学会使用指针 理解指针作为函数参数的特点 学会用指针作为函数的参数 理解指针与数组之间的关系 第八章 指针 本章学习目标 理解指针的概念 学会使用指针 理解指针作为函数参数的特点 学会用指针作为函数的参数 理解指针与数组之间的关系 学会用指针引用数组 理解指针与字符串之间的关系 学会用字符串指针处理字符串 学会定义函数其返回值为指针 了解函数指针的用法
8.1 指针的基本知识 计算机内存储器是由字节组成。内存中字节是连续排列并按一定的规则编号,这个编号通常称为地址。 8.1 指针的基本知识 计算机内存储器是由字节组成。内存中字节是连续排列并按一定的规则编号,这个编号通常称为地址。 在C语言中,定义的每个对象(如变量、数组、函数等)编译系统都为它分配了足够大的内存单元,内存单元占一个或多个字节,每个对象所占的字节数由对象的类型决定,内存单元第一个字节的地址称为首地址,在C程序中称为指针。
8.1 指针的基本知识 程序中: int a=10; double k=23.5; 变量a 变量k 10 23.5 地址 内存 …... 8.1 指针的基本知识 地址 内存 程序中: int a=10; double k=23.5; …... ... 2000 2001 变量a 2002 10 2003 2004 2005 23.5 变量k 2011 …...
8.1 指针的基本知识 1。指针变量的定义: 类型 *变量名; 例: int *p; 2。定义指针变量并初始化 8.1 指针的基本知识 1。指针变量的定义: 类型 *变量名; 例: int *p; 35 x &x p 2。定义指针变量并初始化 int x=35, *p=&x; // 如果指针变量p存储了x的地址,通常称p指向x,或称p的对象是x。图表示了指针变量p、变量x之间的指向关系。
8.1 指针的基本知识 指针基本操作 py y (2000) 1.取地址操作 &运算符求变量的地址, 如,&x 运算结果是变量x的地址。 8.1 指针的基本知识 指针基本操作 1.取地址操作 &运算符求变量的地址, 如,&x 运算结果是变量x的地址。 2. 间接访问操作 *运算符,间接访问指针所指向的对象。 如: int y, *py; py=&y; *py=23;//将23赋给py指向的对象(即变量y) py y (2000) &y (2000) 23
8.1 指针的基本知识 例8.1 取地址运算符“&”和间接访问运算符“*”的使用示例 #include<stdio.h> 8.1 指针的基本知识 例8.1 取地址运算符“&”和间接访问运算符“*”的使用示例 #include<stdio.h> void main() { int a=100,*p; p=&a; // 取变量a的地址赋给p printf("a=%d, *p=%d\n",a,*p); *p=200; // 给p所指向的变量赋值 *p+=1; // pa所指向的变量加1 } 程序执行: a=100,*p=100 a=200,*p=200 a=201,*p=201
8.1 指针的基本知识 例8.2 用指针变量使指针所指向的变量交换值。 /* 例8.2源程序,利用指针修改变量值。 */ 8.1 指针的基本知识 例8.2 用指针变量使指针所指向的变量交换值。 /* 例8.2源程序,利用指针修改变量值。 */ #include<stdio.h> void main() { int a=10,b=20,t; int *p1=&a,*p2=&b; printf("a=%d,b=%d,*p1=%d,*p2=%d\n",a,b,*p1,*p2); t=*p1; *p1=*p2; *p2=t; } 程序执行: a=10,b=20,*p1=10,*p2=20 a=20,b=10,*p1=20,*p2=10
8.1 指针的基本知识 3.赋值操作 同类型指针变量之间可以进行赋值。 float x,*p1=&x,*p2; 8.1 指针的基本知识 3.赋值操作 同类型指针变量之间可以进行赋值。 float x,*p1=&x,*p2; char ch,*q1=&c,*q2; p2=p1; q2=q1; p2=q1; 错误 q2=p1; 错误
8.1 指针的基本知识 指针作函数的参数 在函数中通过指针操作,间接访问指针所指向的变量,达到修改主调函数中变量值的目的。
8.1 指针的基本知识 例8.3下面程序定义了两个函数swap1和swap2,它们分别是用变量和指针变量作为函数的参数。在主函数中,分别调用这两个函数,观察主函数中变量a、b值的变化。 #include <stdio.h> void swap1(int x,float y) // 用整型变量作为函数参数 { int t; t=x; x=y; y=t; } void swap2(int *p,int *q) // 用指针变量作为函数的参数 { int t; t=*p; *p=*q; *q=t;
8.1 指针的基本知识 void main() { int a=3,b=5; swap1(a, b); //函数调用时,把a、b的值传给形参 8.1 指针的基本知识 void main() { int a=3,b=5; swap1(a, b); //函数调用时,把a、b的值传给形参 printf("After calling swap1:a=%d b=%d\n",a,b); a=3; b=5; swap2(&a, &b); //函数调用时,把a、b的地址传给形参 printf("After calling swap2:a=%d b=%d\n",a,b); } 程序执行 After calling swap1:a=3 b=5 After calling swap2:a=5 b=3
8.1 指针的基本知识 例8.4 编函数,求一元二次方程a·x2+b·x+c=0的根(a≠0)的两个实根,并返回1或0分别表示方程有实数解或无实数解。 用两个指针变量作为函数参数,函数调用时使它指向主函数中存储方程根的变量。 int root(float a,float b,float c,float *p1,float *p2) //p1,p2指针变量 { float d; d=b*b-4*a*c; if(d>=0) { *p1=(-b+sqrt(d))/(2*a); //方程根存到p1指向的对象中 *p2=(-b-sqrt(d))/(2*a); return 1; // 方程有实数解 } else return 0; // 表示方程无实数解
8.1 指针的基本知识 void main() { float a,b,c, x1, x2; //x1,x2存放方程的根 int flag; 8.1 指针的基本知识 void main() { float a,b,c, x1, x2; //x1,x2存放方程的根 int flag; scanf(“%f %f %f”,&a,&b,&c);// 输入 1 -1 -2 flag=root(a,b,c,&x1,&x2); if ( flag==1) printf(“x1=%.2f x2=%.2f\n”,x1,x2); else printf("方程无实数解\n"); }
8.2 指针与数组 指针与一维数组 在C语言中,如果定义了一个数组,则在编译时系统会为数组分配足够大的内存单元,按元素的下标顺序依次存储所有元素。数组名就是内存单元的起始地址即指针值,指向数组的第1个元素(即下标0)。因此数组元素的访问可以用指针访问。
8.2 指针与数组 a数组 1 2 3 4 5 a p a[0] 指针与一维数组 1. 用指针引用数组元素 a[1] 假设给出数组如下定义: 8.2 指针与数组 a数组 2000 a p 1 2 3 5 4 a[0] a[1] a[2] a[3] a[4] a[5] 指针与一维数组 1. 用指针引用数组元素 假设给出数组如下定义: int a[6]={1,2,3,4,5,6},*p; p=a; 或 p=&a[0]; // 使指针p指向数组a[0]。 根据指针的间接引用的方法,*p实际就是数组元素a[0]。 数组名或指针访问数组元素的两种形式: 下标法a[i] 指针法*(a+i)。 a[0]=10; a[3]=10; // 下标法引用第1个和第4个元素分别赋值10 *a=10; *(a+3)=10; // 指针法引用第1个和第4个元素分别赋值10 p+2 2008
8.2 指针与数组 例 8.5 定义一个有6个元素的整型数组,并输入6整数存储到数组中,利用指针计算各元素的和并输出和。 8.2 指针与数组 例 8.5 定义一个有6个元素的整型数组,并输入6整数存储到数组中,利用指针计算各元素的和并输出和。 #include <stdio.h> void main() { int a[6],i,s,*p; printf("Please input data:\n"); for(i=0; i<6; i++ ) scanf("%d", &a[i] ); s=0; for(p=a; p<a+6; p++) s+=*p ; // 累加各元素值 printf("s=%d\n",s); // 输出和 }
8.2 指针与数组 一维数组作函数的参数 一维数组作函数参数通常是将数组名作函数参数,而数组名是第一个元素的地址,所以数组名作函数参数其实质就是指针作函数参数。 例 8.5 定义一个有6个元素的整型数组,并输入6个整数存储到数组中,利用指针计算各元素的和并输出和。 #include <stdio.h> int sum(int *b,int n) { int m=0,*p; for(p=b; p<b+6; p++) m+=*p ; return m; }
8.2 指针与数组 void main() { int a[6],s,i; printf("Please input data:\n"); 8.2 指针与数组 void main() { int a[6],s,i; printf("Please input data:\n"); for(i=0; i<6; i++ ) scanf("%d", &a[i] ); s=sum(a,6); // 调用sum函数求数组元素的和 printf("s=%d\n",s); }
8.2.2数组元素指针作为函数的参数 例 s8-8'.cpp 编写函数,将数组中的n个元素值设置为3 #include<stdio.h> void change( int *b, int n ) { int i; for(i=0;i<n;i++) *(b+i)=3; } b a数组 a a[0] a[1] a[2] a[3] void main() { int i,a[10]={0}; change( a+6, 3); // 6号元素指针作实参 for(i=0;i<10;i++) printf("%d ", a[i]); } a[4] a[5] a+6 a[6] a[7] a[8] a[9] 1. void change(int *b, int n) 等价 void change( int b[ ],int n) 2.两种不同的写法,但两个形参b的性质完全一样,都是指针变量,存放地址。 3.函数调用时实参是某个元素指针或数组名。
8.2 指针与数组 b a 例 8.7 定义一个排序函数,完成对n个整数按从小到大排序。 #include <stdio.h> 8.2 指针与数组 b a b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] 9 5 10 6 8 2 1 7 4 3 例 8.7 定义一个排序函数,完成对n个整数按从小到大排序。 #include <stdio.h> void sort(int *a,int n) // 排序函数定义 { int i,j,k,t; for(i=0; i<n-1; i++) for(j=0; j<n-i-1; j++) if(*(a+j)>*(a+j+1)) { t=*(a+j); *(a+j)=*(a+j+1); *(a+j+1)=t; } void main() { int b[10]={5,10,6,9,8,2,7,4,3,1}; int i; sort(b,10); // 调用排序函数 for( i=0; i<10; i++) printf("%4d ",b[i]);
8.2 指针与数组 指针运算: 如: float x,y,*pf; char ch,c,*pch; int m,n,*pi; pf=&x; 8.2 指针与数组 指针运算: 1. 指针之间赋值运算。 如: float x,y,*pf; char ch,c,*pch; int m,n,*pi; pf=&x; pch=&ch; pi=&y //编译出错
8.2 指针与数组 指针运算: 指针类型的数据,除了间接引运算、赋值运算等操作外,当指针指向数组时,指针可以做加减整数、指针相减及指针比较运算。 1.指针与整数的加、减运算 如果指针p是指向数组中的某个元素,加上整数n后,新指针p+n指向后续的第n个元素。 2.指针相减运算 两个指向同个数组的同类型指针作相减运算,其绝对值表示它们之间相隔的元素数目。 3.指针之间作关系运算 两个相同类型指针可作关系运算比较指针大小。例8.5程序循环控制是通过 p<a+6 判断指针p是否指在a数组元素上。 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] p p+3 p+9 a数组 4 1 2 3 5 2000 2012 2036
例8-8编函数,完成将若干个数按值从小到大排序。 void sort(float *a, int n) //排序函数 { int i,j,k; float t; for(i=0; i<n-1; i++) { k=i; for(j=i+1; j<n; j++) if( *(a+j)<*(a+k) ) k=j; t=*(a+i); *(a+i)=*(a+k); *(a+k)=t; } void main() { float b[10]={5.3,1.2,2.3,-3,-1.4,1,0.3,8.4,6.2,2.1}; int i; sort(b+2, 5); //函数调用, 实参是2号元素指针(地址) for( i=0; i<10; i++) printf("%.2f ",b[i]); printf("\n"); a b 5.3 b[0] 1.2 b[1] 2.3 b[2] -3 b[3] -1.4 b[4] 1 b[5] 0.3 b[6] 8.4 b[7] 6.2 b[8] 2.1 b[9]
8.2 指针与数组 指针与二维数组 1.二维数组的存储方式 假设给出二维数组的定义:int a[3][4]; 8.2 指针与数组 指针与二维数组 1.二维数组的存储方式 假设给出二维数组的定义:int a[3][4]; C语言把二维数组a的每一行作为一个一维数组来处理,因此数组a的三行看作三个一维数组,其中a[0]、a[1]和a[2]分别是这三个数组的数组名。 编译时系统为数组分足够大的内存单元,存储数组的所有元素。 内存单元的首地址由数组名表示,各元素在内存单元的排列方式是按行顺序存放。 二维数组名指向数组的第1行而不是第1个元素。
8.2 指针与数组 若定义二维数组 int a[3][4]; a a a[0][0] a[0][1] a[0][2] a数组 a[0][3] 8.2 指针与数组 a 2000 a[0][0] 2004 若定义二维数组 int a[3][4]; a a[0][1] 第1行 2008 a[0][2] a数组 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[0] a[1] a[2] 2012 a[0][3] a+1 2016 a[1][0] 第2行 2020 a[1][1] 2024 a[1][2] 2028 a[1][3] a+2 2032 a[2][0] 第3行 2036 a[2][1] 2040 a[2][2] 2044 a[2][3]
8.2 指针与数组 指针与二维数组 2.二维数组中的两类指针 元素指针:每个元素的地址即为元素指针。 8.2 指针与数组 指针与二维数组 2.二维数组中的两类指针 元素指针:每个元素的地址即为元素指针。 a[i][j]元素指针: 可用&a[i][j]或用a[i]+j表示 行指针:数组中每一行的地址即为行指针。行指针指向的是整个一行。 数组名a是一个行指针指向二维数组的首行,数组名加1即a+1指向数组第2行。 元素指针与行指针的区别 元素指针指向的是一个元素,指针加1后指向下一个元素; 行指针指向的是整个一行(它包含有若干个元素)。
8.2 指针与数组 要注意的是p、q虽然都是行指针变量,但类型不同。 行指针作函数参数 1.定义行指针变量 8.2 指针与数组 行指针作函数参数 1.定义行指针变量 类型标识符 (*变量名)[常量表达式]; 例如:int (*p)[4],(*q)[3]; int a[4][3],x[5][4]; p=x; // 使p指向数组x的第1行 q=a+1; // 使q指向数组a的第2行 要注意的是p、q虽然都是行指针变量,但类型不同。 2.用行指针引用数组元素 例如:int a[3][4],(*p)[4]; p=a; 用行指针表示数组元素a[i][j]的三种形式: a[i][j]、*(*(a+i)+j) 和*(a[i]+j)。 p[i][j]、*(*(p+i)+j) 和*(p[i]+j)。 用行指针表示数组元素a[i][j]地址的三种形式: &a[i][j]、*(a+i)+j 和a[i]+j。 &p[i][j]、*(p+i)+j 和p[i]+j。
8.2 指针与数组 例8.8 输入一个3×4的矩阵到二维数组中,计算所有元素的和。 #include <stdio.h> 8.2 指针与数组 例8.8 输入一个3×4的矩阵到二维数组中,计算所有元素的和。 #include <stdio.h> void main() { int a[3][4], i,j,s=0; int (*p)[4]; printf("Please input data:\n"); for(i=0; i<3; i++) for(j=0; j<4; j++) scanf("%d",*(p+i)+j); // 给a[i][j]元素输入数据 for(p=a,i=0; i<3; i++) s+=*(*(p+i)+j); // 累加所有元素 printf("s=%d\n",s); }
8.2 指针与数组 3.行指针作函数参数 用行指针作为函数参数,在函数中不仅可以访问主函数中的二维数组,更重要的是可以修改这个二维数组中各元素值。 例 8.9 定义一个函数将5×5矩阵中的右上三角元素都设置成0,其余元素值不变。 #include<stdio.h> void change(int (*x)[5],int n , int m) //p是行指针变量 { int i,j; for(i=0; i<n; i++) for(j=0; j<m; j++) if (i<j) *(*(p+i)+j)=0; // 将右上三角元素都设置成0 }
8.2 指针与数组 a // 调用 change(a+2,3,3) 7 6 5 4 3 2 1 void main() 8.2 指针与数组 void main() { int a[5][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}, {4,5,6,7,8},{5,6,,7,8,9}}; int i,j; printf("Matrix:\n"); for(i=0;i<5;i++){ //输出原矩阵 for(j=0; j<5; j++) printf("%3d",a[i][j]); printf("\n"); } change(a,5,5); // 调用change函数 printf("\nNew Matrix:\n"); for(i=0; i<5; i++){ //输出新矩阵 第1行 第2行 第3行 第4行 a 7 6 5 4 3 2 1 // 调用 change(a+2,3,3)
8.3 指针与字符串 a // 调用 change(a+2,3,3) 7 6 5 4 3 2 1 void main() 8.3 指针与字符串 void main() { int a[5][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}, {4,5,6,7,8},{5,6,,7,8,9}}; int i,j; printf("Matrix:\n"); for(i=0;i<5;i++){ //输出原矩阵 for(j=0; j<5; j++) printf("%3d",a[i][j]); printf("\n"); } change(a,5,5); // 调用change函数 printf("\nNew Matrix:\n"); for(i=0; i<5; i++){ //输出新矩阵 第1行 第2行 第3行 第4行 a 7 6 5 4 3 2 1 // 调用 change(a+2,3,3)
8.3 指针与字符串 字符串是由若干个字符组成的字符序列,以‘\0’作为字符串的结束符。 字符串常量的表示 8.3 指针与字符串 字符串是由若干个字符组成的字符序列,以‘\0’作为字符串的结束符。 字符串常量的表示 用双引号括起来的若干字符序列,即字符串常量。 字符串常量通常是被存储在特定的内存单元中。 字符串一般存储在字符数组中,对字符串的访问可以逐个访问数组元素中的字符,或者利用指针访问字符串。 用指针对字符串的处理要比用字符数组对字符串的处理方便得多。
8.3 指针与字符串 字符串指针 字符串第一个字符的地址,即为字符串指针 8.3 指针与字符串 字符串指针 字符串第一个字符的地址,即为字符串指针 字符串常量的值是一个字符串指针,是该字符串在特定内存单元中第一个字符的地址。 例 printf("%x\n","Hello"); 若字符串存放在字符数组,数组名即为字符串指针。 字符串指针实际是一个字符指针,指向字符串的第一个字符,而不是整个字符串。 对一个字符串而言,只要知道了字符串指针,就确定了第一个字符的位置及字符串中的各个字符,‘\0’的位置字决定了字符串的结束位置。
8.3 指针与字符串 用字符指针指向一个字符串 用字符指针指向一个字符串,就是使字符指针指向字符串的第一个字符。例如: 8.3 指针与字符串 用字符指针指向一个字符串 用字符指针指向一个字符串,就是使字符指针指向字符串的第一个字符。例如: char *s="Hello,Everyone "; // 定义字符指针变量s,并初始化。 char *s; //定义字符指针变量s s="Hello,Everyone"; // "Hello,Everyone"的地址赋值给s 程序段1: char *p,*q; // 定义字符型指针变量 p="Hello,Everyone"; q=p+6; // q指向字符串"Everyone " 程序段2: char a[10]= "Hello,Everyone"; // 数组名a指向字符串 char *q; q=a+12; // q指向字符串"one"
8.3 指针与字符串 程序执行: HappyNewYear! NewYear! 字符串的引用 8.3 指针与字符串 字符串的引用 字符串一般放在字符数组中或用指针指向一个字符串,可以用字符数组名或指针引用字符串。 例8.10 用"HappyNewYear!"字符串对字符数组初始化,输出这个字符串及这个字符串的后半部分“NewYear!”。 #include<stdio.h> void main() { char s[]="HappyNewYear!",*p; printf("%s\n",s); //输出s指向的字符串 p=s+5; // 使p指向字符串"Everyone " printf("%s\n",p); // 输出p指向的字符串 } 程序执行: HappyNewYear! NewYear!
8.3 指针与字符串 程序执行: Hello,World 123!↙ Lello,Aorld 123! 8.3 指针与字符串 例8.11 输入一个字符串,将该字符串译成密码输出。密码规律:对大写英文字母用原字母后面的第4个字母代替原字母,若遇到大写字母‘W’、‘X’、‘Y’、‘Z’则分别用‘A’、‘B’、‘C’、‘D’代替,其余字符不变。 #include <stdio.h> void main() { char s[80],*p; int i,n; gets(s); // 输入字符串存放在数组s中 for(p=s ; *p!='\0'; p++) { if( *p>='A'&& *p<='Z' ) if( *p>='W'&& *p<='Z' ){ n=*p-'W'; *p='A'+n; } else *p=*p+4; puts(s); 程序执行: Hello,World 123!↙ Lello,Aorld 123!
8.3 指针与字符串 字符串指针作函数参数 程序执行: the length1 is :15 the length2 is : 5 8.3 指针与字符串 字符串指针作函数参数 例8.12 定义一个计算字符串长度的函数。字符串长度是字符串中字符个数,不计字符结束符'\0'。 #include<stdio.h> int mystrlen(char *s ) { int k=0; while(*s!='\0'){ k++; s++; } return k ; void main() { char *p; char a[80]={"Windows98\nVista"}; printf("the length1 is :%d\n",mystrlen(a)); p=a+10; //p指向字符串"Vista" printf("the length2 is :%d\n",mystrlen(p)); 程序执行: the length1 is :15 the length2 is : 5
8.3 指针与字符串 程序执行: Good,↙ Happy↙ Good,Happy 字符串指针作函数参数 8.3 指针与字符串 字符串指针作函数参数 例8.13 输入两个字符串s1、s2,将字符串s2连接到字符串s1后面,成为一个新字符串,并输出这个新串。要求定义一个函数,功能是把两个字符串连接成一个字符串。 #include<stdio.h> void mystrcat(char *s,char *t) {for( ; *s!='\0'; s++); for( ; *t!='\0' ; s++,t++) *s=*t; *s='\0'; return; } void main() { char a[80],b[40]; printf(“Plese Input strings:”); gets(a); // 输入a字符串 gets(b); // 输入b字符串 mystrcat(a,b); // a、b两字符串连接等 printf("New string: %s\n", a); 程序执行: Good,↙ Happy↙ Good,Happy
8.3 指针与字符串 常用字符串函数 程序执行: HangZhou HangChina 8.3 指针与字符串 常用字符串函数 C语言提供了一些字符串处理函数。这些函数用于字符串处理,包括字符串的拷贝、连接和比较等,对应的头文件为string.h。 1.字符串拷贝函数 strcpy char strcpy(char *s1,char *s2) 功能:字符串s2复制到s1中,从s1指针指的位置开始依次存储字符串2,函数返回值为s1指针。 例如:strcpy的用法: char c[11]="0123456789"; strcpy(c,"HangZhou"); puts(c); strcpy(c+4,"China"); 程序执行: HangZhou HangChina
8.3 指针与字符串 常用字符串函数 2.字符串连接函数strcat char strcat(char *s1,char *s2); 8.3 指针与字符串 常用字符串函数 2.字符串连接函数strcat char strcat(char *s1,char *s2); 功能:把s2字符串(包括‘\0’),复制到字符串s1串后,函数返回值为s1。 例如:strcat的用法: char c[18]="HangZhou "; char a[]="China"; strcat(c,a); puts(c);
8.3 指针与字符串 常用字符串函数 3.字符串比较函数strcmp 字符串大小的定义: 8.3 指针与字符串 常用字符串函数 3.字符串比较函数strcmp 字符串大小的定义: 两个字符串中对应位置上的字符都相等,且串的长度也相等,则两个字符串相等。 两个字符串不等:两个字符串从首字符开始依次比较,第一次出现对应位置上字符不相等,则两个字符串不相等,且由这两个不相等的字符ASCII码值决定字符串大小,ASCII码值大的字符串大。 字符串比较函数: char strcmp(char s1,char s2), 其中s1、s2是字符串。 功能: 比较s1和2两个字符串的大小。函数返回值0则两字符串相等;返回值为1则字符串s1>s2;返回值为-1 则字符串s1<s2。
8.3 指针与字符串 常用字符串函数 3.字符串比较函数strcmp 例如: strcmp("abc","abc")的返回值为0; 8.3 指针与字符串 常用字符串函数 3.字符串比较函数strcmp 例如: strcmp("abc","abc")的返回值为0; strcmp("abc","abcd")的返回值为–1; strcmp("abc","aBc") 的返回值为1; strcmp("ABC","BBC")的返回值为-1。
8.3 指针与字符串 常用字符串函数 4.求字符串长度函数strlen char strlen(char *s) , 其中s是字符串。 8.3 指针与字符串 常用字符串函数 4.求字符串长度函数strlen char strlen(char *s) , 其中s是字符串。 功能:计算字符串中字符的个数(不计‘\0’)。 例如:strlen("China")的返回值为5。 例如:定义语句char a[15]="ab\110\\cd\'\\ne";则strlen(a)的返回值为10(注意转义字符);strlen(a+2)的返回值为8。
8.3 指针与字符串 程序执行: Input strings: 8.3 指针与字符串 例8.14 输入6个字符串,输出最大字符串。 #include <stdio.h> #include <string.h> void main() { char s[80],max[80]; int i; printf("Input strings:\n"); scanf("%s",s); strcpy(max,s); for(i=1;i<=5;i++){ if(strcmp(s,max)>0) } printf("Max-string: %s\n",max); 程序执行: Input strings: elephant finsh tigre apple pear banana↙ Max-string: tigre
8.4 指针数组与多级指针 指针数组与多字符串 C语言允许任何类型的数组,也允许数组元素是指针类型。 8.4 指针数组与多级指针 指针数组与多字符串 C语言允许任何类型的数组,也允许数组元素是指针类型。 如果数组的所有元素都是指针类型,那么这个数组就是指针数组。 指针数组较多的应用于多字符串处理。 1.指针数组定义 类型标识符 *数组名[数组长度]; 例如,int *p[10]; 即定义了数组p是指针数组。 数组p的每个元素是指针类型,存储int型变量的地址。
8.4 指针数组与多级指针 例8.15 读程序,区别指针数组与普通数组。 #include<stdio.h> 8.4 指针数组与多级指针 程序执行: Output x-arry: 1 2 3 4 Output object of px-arry: Output px-arry: 13ff6c 13ff70 13ff74 13ff78 例8.15 读程序,区别指针数组与普通数组。 #include<stdio.h> void main() { int i; int x[4]={1,2,3,4}, *px[4]; // 定义数组x和指针数组px for(i=0;i<4;i++) px[i]=x+i; // 使px[i]指向x[i] printf("Output x-arry:\n"); for(i=0;i<4;i++) // 输出x数组各元素值 printf("%3d",x[i]); printf("\nOutput object of px-arry:\n"); for(i=0;i<4;i++) // 输出px数组各元素对象值 printf("%3d ",*px[i]); printf("\nOutput px-arry:\n "); for(i=0;i<4;i++) // 输出px数组各元素值(数组x各元素的地址) printf("%x ",px[i]); }
8.4 指针数组与多级指针 程序执行1: Input name: Fox↙ Fox is here 2.多字符串 8.4 指针数组与多级指针 2.多字符串 通常可以用字符指针数组来表示多个字符串,即将指针数组中每个元素指向一个字符串。 例8.16 输入一个学生姓名,在含有10个学生名单中查找该学生是否存在,并输出查找结论。 #include<stdio.h> void main() { static char *name[10]= {"Betty","Tom","Smith","Ellen","Fox", "Shakespeare","Steven,Owen,Marie,Arids"}; char sn[20]; int i; printf("Input name:\n"); scanf("%s",sn); // 输入查找人姓名 for(i=0;i<10;i++) if (strcmp(sn,name[i])==0) break; if (i<10) printf("%s is here\n",sn); else ("Sorry,Not found"); } 程序执行1: Input name: Fox↙ Fox is here
8.4 指针数组与多级指针 Tailand\0 Zambia\0 Italy\0 Mauritiania\0 France\0 8.4 指针数组与多级指针 *例8.17 将Tailand, Zambia, Itlay, Mauritania, France,Romania 这6个国家的英文名称按字符串大小排序输出。 char *p[6]={"Tailand", "Zambia", "Itlay", "Mauritania", "France","Romania"}; Tailand\0 Zambia\0 Italy\0 Mauritiania\0 France\0 Romania\0 p[0] p[1] p[2] p[3] p[4] p[5] p[0] p[1] p[2] p[3] p[4] p[5] Tailand \0 Zambia\0 Italy\0 Mauritiania\0 France\0 Romania\0
8.4 指针数组与多级指针 #include <stdio.h> #include <string.h> 8.4 指针数组与多级指针 #include <stdio.h> #include <string.h> void main() { char *p[6]={ "Singapore","Zambia","China","Mexico", "Canada","Romania" }; char *t; int i,j,k; for(i=0; i<5; i++){ k=i; for(j=i+1; j<6; j++) if(strcmp(p[j],p[k])<0) //比较p[j]与p[k]指针指向的字符串大小 k=j; t=p[k]; // 三条语句交换指向 p[k]=p[i]; p[i]=t; } for(i=0; i<6; i++) puts(p[i]);
8.4 指针数组与多级指针 指向指针的指针 pp &p &x p 56 x 二级指针变量定义的一般形式: 类型标识符 **变量名; 例如: 8.4 指针数组与多级指针 指向指针的指针 二级指针变量定义的一般形式: 类型标识符 **变量名; 例如: int x=56; // 定义整型变量x,放整数,初始化56 int *p=&x; // 定义一级指针变量p,放普通变量地址,初始化&x int **pp=&p; // 定义二级指针变量pp,放指针变量p的地址,初始化&p pp、p、x之间的关系是pp指向p,p指向x,x值56 pp &p &x p 56 x
8.4 指针数组与多级指针 ppi &pi &x pi 3 a 例8.18 二级指针变量的定义与引用。 8.4 指针数组与多级指针 例8.18 二级指针变量的定义与引用。 #include <stdio.h> void main() { int a=3,*pi,**ppi; // pi为一级指针变量、ppi为二级指针变量 pi=&a; // 使pi指向a ppi=π // 使ppi指向指针变量pi printf("a=%d\n",a); printf("a-address: %x\n",pi); printf("pi-address: %x\n",ppi); printf("ppi-address: %x\n",&ppi); printf("a=%d,*pi=%d,**ppi=%d\n",a,*pi,**ppi); } 程序执行: a=3 a-address: 12ff7c pi-address: 12ff78 ppi-address: 12ff74 a=3, *pi=3, **ppi=3 ppi &pi &x pi 3 a
8.4 指针数组与多级指针 *例8.19 用指针数组指向6个国家的英文名字,分别用指针数组,指针的指针输出这6个国家名及每个国家名的首字符。 8.4 指针数组与多级指针 *例8.19 用指针数组指向6个国家的英文名字,分别用指针数组,指针的指针输出这6个国家名及每个国家名的首字符。 #include <stdio.h> void main() { char *p[6]={ "Singapore","Zambia","Itlay" ,"China", "America","Romania" }; char **q; // q指针的指针 (二级指针) int i; for(i=0; i<6; i++){ printf("%10s, %c ",p[i],*p[i]); // 用指针数组输出国家名及首字母 q=p+i; printf("%10s, %c\n",*q,**q); // 用指针的指针输出国家名及首字母 } 程序执行: Singapore,S Singapore,S Zambia,Z Zambia,Z Itlay,I Itlay,I China,C China,C America,A America,A Romania,R Romania,R
8.4 指针数组与多级指针 * main函数的参数 main函数可以带参数的。 当C程序运行时,通过命令行输入参数给main函数。 8.4 指针数组与多级指针 * main函数的参数 main函数可以带参数的。 当C程序运行时,通过命令行输入参数给main函数。 C语言规定main函数的参数只能有两个,习惯上将这两个参数名写为argc和argv。 带参数的main函数首行的一般形式为: void main(int argc,char *argv[ ]) 第一个形参argc存放程序执行时的参数个数,至少是一个(这个参数就是该程序的可执行文件名); 第二个形参argv为指针数组,存放指向实参的指针。其中,argv[0]指向第一个实参,即该程序的可执行文件名,argv[1]指向第二个实参,argv[2]指向第三个实参……
8.4 指针数组与多级指针 * main函数的参数 用简单的程序说明如何给main函数传递实参的方法。 8.4 指针数组与多级指针 * main函数的参数 用简单的程序说明如何给main函数传递实参的方法。 例8.20 输出main函数执行时的各参数。 程序的文件名为prg.c。 #include<stdio.h> void main(int argc,char *argv[]) { int i; printf("参数个数为:%d\n",argc); // 输出argc值 i=0; while (i<argc){ printf("第%d个参数:%s\n", i+1,argv[i]); // 输出各参数值 i++; } 程序执行1:将上面的程序经编译、连接后得到可执行文件prg.exe,在Windows的命令提示符环境下,输入命令行: prg.exe Hello, Everyone!↙ 参数个数为:3 第1个参数:prg.exe 第2个参数:Hello, 第3个参数:Everyone!
8.5 指针与函数 指针作为函数的返回值 类型标识符* 函数名(类型标识符 形参, 类型标识符 形参,…) { 函数体 } 8.5 指针与函数 指针作为函数的返回值 类型标识符* 函数名(类型标识符 形参, 类型标识符 形参,…) { 函数体 } 例8.21 输入两个字符串s1、s2,将字符串s2连接到字符串s1后面,成为一个新字符串,并输出这个新串。要求定义一个连接两个字符串的函数,并且函数返回指向连接后新字符串的指针。
8.5 指针与函数 #include<stdio.h> char *mystrcat(char *s,char *t) 8.5 指针与函数 #include<stdio.h> char *mystrcat(char *s,char *t) { char *p; for(p=s ; *s!='\0'; s++) ; for( ; *t!='\0' ; s++,t++) *s=*t; *s='\0'; return p; // 返回连接后的新字符串的指针。 } void main() { char s1[80],s2[80]; printf("Please input two strings:\n"); gets(s1); // 输入s1字符串 gets(s2); // 输入s2字符串 printf("New string is:”); printf("%s\n", mystrcat(s1,s2)); // 输出连接后的新字符串 程序执行: Please input two strings: Windows↙ XP↙ The new string: WindowsXP
8.5 指针与函数 例8.22 输入一个学生姓名,在10个学生名单中查找该学生是否存在,并输出查找结论是或否。 8.5 指针与函数 例8.22 输入一个学生姓名,在10个学生名单中查找该学生是否存在,并输出查找结论是或否。 #include<stdio.h> #include<string.h> char *search(char *s, char *sname[],int n) { int i; for(i=0;i<n;i++) if (strcmp(s,sname[i])==0) return sname[i]; //返回找已到的字符串指针 return NULL; // 没有找,返回空指针 }
8.5 指针与函数 例8.22 输入一个学生姓名,在10个学生名单中查找该学生是否存在,并输出查找结论是或否。 void main() 8.5 指针与函数 例8.22 输入一个学生姓名,在10个学生名单中查找该学生是否存在,并输出查找结论是或否。 void main() { static char *name[10]= {"Betty", "Tom","Smith","Ellen", "Shakespeare","Fox","Steven,Owen,Marie,Arids"}; char sn[20],*p; int i; printf("Please input name:\n"); scanf("%s",sn); // 输入一个欲查找的姓名 p = search(sn, name,10); if(p==NULL) printf("Not Found\n"); else printf("%s\n",p); // 输出找到的人名 } 程序执行1: Please input name: Fox↙ Fox
8.5 指针与函数 指向函数的指针 C语言是由函数组成,每个函数是一段程序。 8.5 指针与函数 指向函数的指针 C语言是由函数组成,每个函数是一段程序。 编译后函数被翻译成一组机器指令。系统为函数分配确定的基地址和足够大的内存空间存储这组指令。 基地址就是函数的指针,指向函数的第一条指令,由函数名表示。 函数被执行时,就从这基地址开始,逐条执行指令,直到区域中的指令执行完。
8.5 指针与函数 指向函数的指针 1.函数指针变量的定义与赋值 类型标识符 (*变量名)(形参类型列表); 例如: 8.5 指针与函数 指向函数的指针 1.函数指针变量的定义与赋值 类型标识符 (*变量名)(形参类型列表); 例如: char (*f1)(float); int (*f2)(int,float); 为函数指针变量赋值 double (*f)(double); double (*q)(double,double); f=sqrt; // 使f指向sqrt函数 q=pow; // 使q指向sqrt函数 可以用指针变量f、q分别调用sqrt、pow函数。 f(5)、q(5,3),即分别调用了sqrt和pow函数。
8.5 指针与函数 指向函数的指针应用 例8.23 用指向函数的指针调用函数的应用举例。 #include <stdio.h> 8.5 指针与函数 指向函数的指针应用 例8.23 用指向函数的指针调用函数的应用举例。 #include <stdio.h> #include <math.h> double max(double x,double y) { return x>y? x:y; } void main() { double (*p)(double,double); // 定义p为函数指针变量 double y1,y2; p=pow; y1=p(5,3); // 调用函数pow(5,3) printf("y1=%.2f\n",y1); p=max; y2=p(5,3); // 调用函数max(5,3) printf("y2=%.2f\n",y2); 程序执行: y1=125.00 y2=5.00
8.5 指针与函数 f(x) f(b) f(c) c a b f(a) 8.5 指针与函数 *例8.24 用二分法编写求f(x)=0在[a,b]区间内一个根的通用函数。 程序设计分析 若函数f(x)在[a,b]区间连续,且满足条件f(a)*f(b)<0,则在区间[a,b]中必有根ξ,使f(ξ)=0。求f(x)=0在[a,b]区间内的一个实根的二分法。基本步骤如下: 1)c=(a+b)/2。 2)|f(c)|<ε,则输出c作为近似解,并终止程序。 3)缩小求根区间, [a,c]或[c,b]作为新的求根区间[a,b],使新[a,b]仍然满足f(a)*f(b)<0,再继续执行第1步。 f(x) f(b) c f(c) a b f(a)
8.5 指针与函数 */* 例8.24源程序,用函数指针作为函数的参数 */ #include <stdio.h> 8.5 指针与函数 */* 例8.24源程序,用函数指针作为函数的参数 */ #include <stdio.h> #include <math.h> double root(double a,double b,double eps,double(*f)(double)) { double c; do{ c=(a+b)/2; if(f(a)*f(c)<0) b=c; else a=c; }while(fabs(b-a)>eps&&fabs(f(c))>eps); return c; }
8.5 指针与函数 double f(double x) // 定义f(x)方程 { return x*x-2*x+1; } 8.5 指针与函数 double f(double x) // 定义f(x)方程 { return x*x-2*x+1; } void main() double x1,x2; x1=root(0,5,1e-4,sin); // 求函数sin(x)=0在[0,5]的一个实根 printf("x1=%.2f\n",x1); x2=root(0,2,1e-5,f); // 求函数f(x)=0在[0,2]的一个实根 printf("x2=%.2f \n",x2);