版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
"CaseTutorialsofCLanguageProgramming"isbasedondataprocessing《C语言程序设计案例教程》
----基于数据处理目录02第2章简单的数值运算程序设计03第3章逻辑运算与选择结构程序设计01第1章C语言概述及程序设计基础04第4章重复运算与循环结构程序设计目录06第6章指针与字符串数据处理07第7章函数与程序结构优化05第5章数组与批量数据处理08第8章结构体与复杂数据处理目录10第10章文件与大批量数据处理09第9章链表与非连续存储数据处理第7章
函数与程序结构优化7.9局部变量与全局变量7.11内部函数和外部函数7.1模块化程序设计7.4数组作为函数参数7.2函数的分类与定义7.3函数的调用与执行7.5指针变量作为函数参数7.6指向函数的指针变量与指针型函数7.8函数的嵌套调用与递归调用7.7带参数的main函数7.10变量的存储类别7.12应用举例7.1模块化程序设计7.1.1模块化程序设计概述逐步求精分而治之核心思想逐步求精就是把复杂问题分解成若干个独立的功能模块的过程将分解后的功能块用适合的算法进行描述并用程序实现它设计方法:自顶向下(top-down)实现方法:函数与函数调用第7章
函数与程序结构优化7.1.2函数概述源于数学函数,如z=f(x,y),但比数学函数功能更强大。函数概念:前面各章的程序就是一个函数,它的函数中为main(),所以函数是实现一定功能模块的子程序。C语言程序的全部功能都是由各式各样的函数来完成的,它们通过函数调用的方法来实现对函数的使用,因此也把C语言称为函数式语言。文件包含类型定义说明部分函数1定义函数2定义函数n定义……程序的书写结构程序中函数书写特点:(1)在一个函数中不能再定义另一个函数,即不能嵌套定义。(2)函数在程序中书写的先后顺序没有关系(3)main()函数称为主函数,一个程序有且仅有一个main(),它表示程序的执行总是从main()开始,并在main()结束整个程序的运行。7.2函数的分类与定义函数分类从函数定义的角度分从函数返回值角度分从数据传递的角度分库函数,如printf()用户函数,如arraysort()无返回值函数,如intmax(inta,int
b)有返回值函数,如voidpr(char*str)无参数函数,如voidprint()有参数函数,如intsum(intn)7.2.1函数的分类返回值:类似于数学函数有一个结果,且这个结果可以再次使用。参数:类似于数学函数中的自变量,根据其值可控制函数的执行。函数的形式参数,每个参数均必须有类型说明,[]表示可以省略返回值类型void表示无返回值7.2函数的分类与定义1.函数定义的一般形式类型标识符
函数名([类型说明
形参变量名1[,类型说明
形参变量名2,...]]){
声明部分
//函数内部的变量说明等
语句
//函数中应该完成
一定功能的语句序列}7.2.2函数的定义每个函数均有一个名字注意与main()对比7.2函数的分类与定义2.函数定义的几种具体形式1)空函数的定义void函数名(){
}2)无返回值、无参数函数的定义void函数名()
{声明部分语句}3)无返回值、有参数函数void函数名(形式参数)
{声明部分语句}4)有返回值、无参数函数类型
函数名()
{声明部分语句}5)有返回值、有参数函数类型
函数名(形式参数)
{声明部分语句}7.2函数的分类与定义voidhello()
{
printf("Hello,world\n");}voidprint_stars(intn){
inti,j;
for(i=1;i<=n;i++)
{
for(j=0;j<i;j++)
printf(“%c”,’*’);
printf(“\n”);
}}
intsum(){
inti,s=0;
for(i=1;i<=100;i++)s+=i;
returns;}
intmax(inta,intb)
{
if(a>b)returna;
elsereturnb;}voidempty()
{
}2.函数定义的几种实际形式什么也没干输出n行*形图形求2个数的最大值只能求1加到100的和只能输出一句问候语理解函数形式参数与返回值的意义与重要性什么时候需要形参、返回值?(1)任何函数均不能调用main()。(2)用户自定义函数之间可以任意调用。(3)函数自己可以调用自己,形成递归(4)遵循“先定义,后调用”的调用规则。(5)对库函数的调用,需用#include<库名>格式1:函数名(实际参数);//函数语句格式2:变量=变量名(实际参数);//表达式类型标识符
函数名(形式参数列表);或:类型标识符
函数名(参数类型列表);//省略参数名用于“函数定义在后,调用在先”的情况格式规则说明语句1.函数调用7.3函数的调用与执行传递给形式参数用7.3函数的调用与执行结构清晰简单实用7.3.1函数的调用intfunA(…){……;…}
intfunB(…){…s=funA(…);…}
intfunA(…){
②…s=funB(…);…}
intfunB(…){……;…}
intfunA(…){
②…s=funB(…);…}
intfunB(…){…t=funA(…);…}
①intfunB(…);//说明语句
(a)先定义函数后调用
(b)先调用后定义,必须加说明语句(c)嵌套调用必须加说明语句
①intfunB(…);
//说明语句
注:位置①的说明语句也可以放在位置②这个地方,两者有区别7.3函数的调用与执行【例7.1】用函数调用的方式实现求两个数的最大值#include
<stdio.h>void
main(){
int
max(int
a,int
b);
//函数说明语句
int
x,y,z;
printf("inputtwonumbers:\n");
scanf("%d%d",&x,&y);
z=max(x,y);
printf("maxmum=%d",z);}int
max(int
a,int
b)
//函数定义{
if
(a
>b)return
a;
else
return
b;}#include
<stdio.h>int
max(int
a,int
b);
//函数说明语句void
main(){
int
x,y,z;
printf("inputtwonumbers:\n");
scanf("%d%d",&x,&y);
z=max(x,y);
printf("maxmum=%d",z);}int
max(int
a,int
b)
//函数定义{
if
(a
>b)return
a;
else
return
b;}其作用域不同7.3.3函数的参数与参数传递函数定义时的参数,必须使用类型定义。形参函数调用中的参数,可以是常量、变量或表达式,只要类型一致即可给函数的执行传递具体的数据,以方便函数执行实参参数作用1.函数的参数形式参数均为局部变量,离开函数便不能使用。局部变量7.3.3函数的参数与参数传递函数调用时。函数不调用它是不执行的。时机实参开参单向性实参的数量、类型必须与形参的数量、类型一致方向要求2.参数传递的特点形式为指针类型、数组时,只能传类型一致的显指针变量或变量地址或数组名传地址形式为非指针类型,则可以传表达式(值)传值7.3.3函数的参数与参数传递3.关于函数调用的内存分配函数不调用不分配内存,优点:节省内存空间调用时分配内存,调用结束释放内存,优点:节省内存空间,不同函数的变量名不会混淆或因重名而引起程序的错误。函数A函数B函数main()程序内存分配函数main()当main()运行时内存分配函数main()当main()运行时调用函数A()函数A内存分配函数main()当main()运行时,调用函数A()运行结束内存分配当main()运行结束内存内存内存内存7.3.3函数的参数与参数传递【例7.2】说明参数传递的单向性示例一#include
<stdio.h>void
swap(int
x,int
y);
//函数说明语句void
main(){
int
a,b;
printf("Inputtwointegeraandb=");
scanf("%d%d",&a,&b);
swap(a,b);
//函数调用语句
printf("a=%d,b=%d\n",a,b);}void
swap(int
x,int
y){
int
temp;
temp=x;x
=y;y
=temp;
printf("x=%d,y=%d\n",x,y);}传值
7.3.3函数的参数与参数传递【例7.3】说明参数传递的单向性示例二,交换2个变量的值#include
<stdio.h>void
swap(int
*x,int
*y);
//函数说明语句void
main(){
int
a,b;
printf("Inputtwointegeraandb=");
scanf("%d%d",&a,&b);
swap(&a,&b);
//函数调用语句
printf("a=%d,b=%d\n",a,b);}void
swap(int
*x,int
*y){
int
temp;
temp=*x;*x
=*y;*y
=temp;
printf("*x=%d,*y=%d\n",*x,*y);}传地址
7.3.4函数的返回值1、函数的值只能通过return语句返回一般形式为:
return表达式;或者为:
return(表达式);该语句的功能是计算表达式的值,并将其值返回给其调用函数。在函数定义中允许有多个return语句,但每次调用只能有一个return语句被执行,因为当函数执行到return语句时,立即终止函数的执行,将return表达式的值返回给调用函数,所以一个函数只能返回一个函数值。2、函数返回值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类型为准,自动进行类型转换。3、没有返回值的函数,必须使用void类型说明符。此时函数
定义中也不需要return语句。7.3.5函数的执行
main()调用funA(),而funA()继续调用了funB()形成了嵌套调用1、嵌套调用,遇到调用语句就执行(此时给调用函数分配内存)2、函数运行结束后,返回到其调用点的下一语句继续执行(此时释放内存)3、最后调用的函数最先被执行完成(栈结构,后进先出)7.3.6函数的编写1.规划1个函数,即确定函数头柏拉图(Plato):“良好的开端是成功的一半”函数头:返回值类型
函数名(形式参数列表)函数入口参数:形式参数列表出口参数:0个,返回值类型void1个,确定返回类型,函数中由return返回
1个以上,
在形参列表中用指针体现(例7.3)入口参数出口参数
例:编写一个函数,它能够求出一个数组中函数的最大值与其元素所在的下标。①intarray_max1(inta[],intn,int*pos)②voidarrar_max2(inta[],intn,,int*max,int*pos)7.3.6函数的编写2.编写函数体函数体的写法函数编写:
1、函数体的写法与main()函数的写法基本一致,重点是根据函数头的定义与功能去编写函数体;2、要符合函数头定义的要求;3、要实现函数所给定的功能。函数调用:
函数的调用与函数头的关系十分密切,准确地讲,函数的调用就是要为函数建立起对应的形参数据与形参指针所对应的变量。紧密切合函数头的要求实现函数的功能求1+2+...+n的和。7.3.6函数的编写示例
int
sum(int
n){
int
value=0,i;
for
(i=1;i<=n;i++)
value=value+i;
return
value;}求a,b,c的最大数。int
max(int
a,int
b,int
c){
int
big;
big=a
>b?a:b;
big=big>c
?big:c;
return
big;}int
prime(int
n){
int
i,flag;
if
(n
>=0)
if
(n
==0||n==1) return
0;
else
if
(n
==2) return
1;
else { flag=1;
for
(i=2;i<n;i++) {
if
(n
%i==0) flag=0; }
return
flag; }
else
return
-1;}判断n是否为素数,是返回1,不是返回0,输入错误返回-1。7.4.1数组元素作函数实数7.4数组作为函数参数数组元素作函数实数函数形参必须与数组元素的类型一致如:inta[10];函数调用:fun(a[i])则函数头定义:intfun(intn)【例7.4】用函数编写一个素数判断程序,通过调用该函数求裴波那契数列中前40项中所有素数的和以及素数的个数传值
问题分析:(1)构造裴波那契数列并存放于inta[40]数组中。(2)编写函数:判别一个整数是否为素数,intprime(intn),是返回1,不是返回0(3)对求出的每个裴波那契数进行素数判定,如果是素数,则进行累加与计数运算。7.4.1数组元素作函数实数#include
<stdio.h>#include<math.h>int
prime(int
n){
int
i,flag=1;
//素数flag标记,1表示是,0表示不是
if
(n
<=1)
return
0;
else
for
(i=2;i<=sqrt(n);i++)
if
(n
%i==0)
//表示数n被2~根号n的1个数整除,则它不是素数
{
flag=0;break;
//已确定n不是素数,提前终止循环
}
return
flag;}void
main(){
int
a[40],i,sum=0,count=0;
a[0]=0;a[1]=1;
//因0和1不是素数所以从下一个数开始判断
for
(i=2;i<40;i++)
{
a[i]=a[i-1]+a[i-2];
if
(prime(a[i]))
//计算素数之和、个数
{
sum=sum+a[i];count++;
printf("%10d",a[i]);
}
}
printf("\nSumofprime=%d,
Numbers=%d\n",sum,count);}数组元素实参7.4.2数组作为函数形数、数组名作为函数实数两种典型格式:1)带下标说明的数组形参如函数定义:intsum(inta[10])//求数组a[10]的所有元素之和{inti,s=0;for(i=0;i<10;i++)s+=a[i];returns;}则其函数调用为:
s=sum(b);//其中数组b的说明为:intb[10];2)不带下标说明的数组形参如函数定义:intsum(inta[],intn)
//求数组a[]前n个元素之和{inti,s=0;for(i=0;i<n;i++)
s+=a[i];returns;
}则其函数调用为:s=sum(b,10);
//其中数组b的说明为:intb[10];灵活性更好7.4.2数组作为函数形数、数组名作为函数实数2.数组元素与数组名作函数实参的区别1)数组元素作为实参(1)函数形参的定义:intsum(intn)(2)内存分配
形参与实参独立分配内存单元(3)传递方式
传值(4)效果
形参值
改变不影响实参变量的结果。2)数组名作为实参(1)函数形参的定义:intsum(inta[],intn)
intsum(inta[10])
(2)内存分配形参不分配数组单元,它共享实参的数组空间(3)传递方式
传地址(4)效果在函数中对数组元素的赋值会直接影响实参数组的元素值。VS7.4.2数组作为函数形数、数组名作为函数实数【例7.5】编写函数将数组元素倒置存放,并返回其元素之和;通过主程序调用该函数输出倒置后的结果和其和值。函数头:intreverse(inta[],intn)#include
<stdio.h>int
reverse(int
a[],int
n){
int
i;
int
s=0,t;
for
(i=0;i<n
/2;i++)
//首尾元素交换
{
s=s+a[i]+a[n
-i-1];
//求和
t=a[i];a[i]=a[n
-i-1];a[n
-i-1]=t;
}
if
(n
%2!=0)s=s+a[n
/2];
//求和
return
s;}void
main(){
int
val[8],total;
int
i;
printf("input8data:");
for
(i=0;i<8;i++)
scanf("%d",&val[i]);
total=reverse(val,8);
//数组名作为实参
printf("totalvalueis%6d\n",total);
printf("Afterreservearray:");
for
(i=0;i<8;i++)
//交换后数组元素的值
printf("%6d",val[i]);
printf("\n");}7.4.2数组作为函数形数、数组名作为函数实数【例7.5】编写函数将数组元素倒置存放,并返回其元素之和。函数头:intreverse(inta[],intn)函数调用:total=reserve(a,8);16201412610788710612142016a[0]实参数组a首地址形参数组b首地址a[1]a[7]b[0]b[1]b[7]调用前:数组a已分配了空间调用后:形参数组b获得了与数组a同样的地址空间。intmain(){inta[8];……total=reserve(a,8);…}intreserve(intb[],intn){……//首尾交换
returntotal;}求和函数:主调函数:调用函数函数返回7.4.2数组作为函数形数、数组名作为函数实数【例7.6】编写一个函数,它求出一个数组中函数的最大值与其元素所在的下标,运用此函数实现数组的排序。问题分析:(1)数组肯定是函数入口参数,(2)除此之外函数要求能够得到2个返回值,像这种情况通常都
可以按以下思想来定义函数,一是用return得到1个返回值,另一个用指针来实现实参的改变;第二种方式是2个均使用指针来实现对实参的改变。所以得到以下两种函数头如下:intarray_max1(inta[],intn,int*pos)//返回数组中的最大值,其位置由pos给出voidarray_max1(inta[],intn,int*max,int*pos)//求出数组中的最大值max,其位置由pos给出函数头确定后,它不仅影响函数的写法,也影响函数调用的方法,请注意观察下面2个程序。7.4.2数组作为函数形数、数组名作为函数实数【程序一】#include
<stdio.h>void
array_max1(int
a[],int
n,int*max,int*pos)//求出数组中的最大值max,其位置由pos给出{
int
i;
int
max1,p;//max存放最大值,p存放最大值位置
max1=a[0];p=0;
for
(i=1;i<n;i++)
{
if
(max1<a[i])
{
max1=a[i];p=i;
//保存最大元素及其位置
}
}
*max
=max1;
//将最大值赋给max所指向的变量
*pos
=p;
//将最大元素位置赋给pos所指向的变量}void
main(){
int
val[10]={4324,45,34,67,554,332,256,88,99,167};
int
i,p,m;
for
(i=0;i<10;i++)
{
array_max1(val,10-i,&m,&p);
val[p]=val[10-i-1];val[10-i-1]=m;//最大数与未排序的最后一个元素交换
}
printf("Aftersortedarray:");
for
(i=0;i<10;i++)
//交换后数组元素的值
printf("%6d",val[i]);
printf("\n");}7.4.2数组作为函数形数、数组名作为函数实数【程序二】,注意比较与程序一的差别(函数头定义不一样)。#include
<stdio.h>int
array_max1(int
a[],int
n,int*pos)//返回数组中的最大值,其位置由pos给出{
int
i;
int
max,p;//max存放最大值,p存放最大值位置
max=a[0];p=0;
for
(i=1;i<n;i++)
{
if
(max<a[i])
{
max=a[i];p=i;
//保存最大元素及其位置
}
}
*pos
=p;
//将最大元素的位置赋给pos所指向的变量
return
max;
//函数返回最大值}void
main(){
int
val[10]={4324,45,34,67,554,332,256,88,99,167};
int
i,p,max,t;
for
(i=0;i<10;i++)
{
max=array_max1(val,10-i,&p);
val[p]=val[10-i-1];val[10-i-1]=max;
//最大数与未排序的最后一个元素交换
}
printf("Aftersortedarray:");
for
(i=0;i<10;i++)
//输出
printf("%6d",val[i]);
printf("\n");}7.4.3二维数组作为函数参数二维数组做为函数的形参,在定义时可以省略第一维参数的大小,但不能省略第二维参数的大小;调用:要求其对应的实参必须是同类型二维数组名,并且其各维大小均一致。【例7.7】用函数实现二维数组的转置,并通过调用该函数实现一个二维数组的转置问题分析:1.本问题的第一个函数实现1个二维数组的转置运算,可以用voidreverse(intb[][5],intn)函数头2.同时考虑到二维数组要多次输出,再编写一个输出二维数组元素的函数voidprintarr(inta[][5],intn)3.通过main()函数调用它们来实现。将多次用到的一段代码用函数实现中以减少代码量,且易于程序维护。7.4.3二维数组作为函数参数#include
<stdio.h>void
reverse(int
b[][5],int
n)
//对二维护数组进行转置{ int
i,j,t;
for(i=0;i<n;i++)
for
(j=0;j<i;j++) { t=b[i][j];b[i][j]=b[j][i];b[j][i]=t; }}void
printarr(int
a[][5],int
n)
//输出二维数组{ int
i,j;
for
(i=0;i<n;i++) {
for
(j=0;j<5;j++) printf("%4d",a[i][j]); printf("\n"); }}void
main(){ int
a[4][5],i,j;
for
(i=0;i<4;i++)
//二维数组元素赋值
for
(j=0;j<5;j++) a[i][j]=i*10+j; printf("Initialvaluesofarrayais:\n"); printarr(a,4);
//输出二维数组元素的值
reverse(a,4);
//调用函数进行转置运算
printf("Reversevaluesofarrayais:\n"); printarr(a,4);
//输出二维数组元素的值}【例7.7】用函数实现二维数组的转置,并通过调用该函数实现一个二维数组的转置多个函数组成一个程序,多函数将会成为编程的一种常态。7.5指针变量作为函数参数指针作用函数的参数具有以下重要用途:(1)
实现一个函数可以得到多个返回值的情形。(2)
代替数组作为函数参数,提高程序运行速度。(3)
进一步了解指针与数组的关系。7.5.1形参是指针变量,实参是变量的地址voidswap(int*x,int*y){intt;t=*x;*x=*y;*y=t;}voidswap1(int*x,int*y){
intt,*p=&t;; p=x;x=y;y=p;}voidswap2(int*x,int*y){ ints,t,k;s=*x;t=*y; k=s;s=t;t=k;}voidswap3(int*x,int*y){ ints,t,k;s=*x;t=*y; k=s;s=t;t=k;*x=s;*y=t;}voidmain(){ inta=3,b=4; swap(&a,&b);
printf("a=%d,b=%d\n",a,b);}哪些函数调用的结果能够得到交换a、b值的目标,即输出a=4,b=3?//依次用swap1(&a,&b);swap2(&a,&b);swap3(&a,&b);核心:函数中是否有对*形参变量的赋值回顾:
intx,*p;p=&x;则:*p就是x7.5.1形参是指针变量,实参是变量的地址【例7.8】写1个函数,求出3个数的最大数与最小数void
minmax(int
a,int
b,int
c,int*min,int*max){ int
min1,max1;
if
(a
>b)max1=a;else
max1=b;//先求2个数的最大数
if
(max1<c)max1=c;
//将2个数的最大数与第3个数比较
if
(a
<b)min1=a;else
min1=b;
if
(min1>c)min1=c; *min
=min1;
//把最小值写入到min所指向的变量中
*max
=max1;
//把最大值写入到max所指向的变量中}void
minmax(int
a,int
b,int
c,int*min,int*max){ *max
=a
>b
?a
:b; *max
=*max
>c
?*max
:c; *min
=a
<b
?a
:b; *min
=*min
<c
?*min
:c;}void
main(){ int
x,y,z;
int
max3,min3; scanf("%d%d%d",&x,&y,&z); minmax(x,y,z,&min3,&max3); printf("themaxnumberis%d\n",max3); printf("theminnumberis%d\n",min3);}改进的函数:7.5.2形参是指针变量,实参是指针变量【例7.9】用形参和实参均为指针实现交换两个变量a与b的值void
main(){
int
a=3,b=4;
int*t,*s;
t=&a,s=&b;
swap(t,s);
//实参为指针
printf("a=%d,b=%d\n",a,b);
printf("*t=%d,*s=%d\n",*t,*s);}#include
<stdio.h>void
swap(int*x,int*y)
//形参为指针{
int
temp;
temp=*x;*x
=*y;*y
=temp;}调用过程分析:1.形参与实参均为普通指针7.5.2形参是指针变量,实参是指针变量【例7.10】用函数实现输入a、b、c共3个整数,按由小到大顺序输出#include
<stdio.h>void
swap(int*pt1,int*pt2){
int
temp; temp=*pt1;*pt1
=*pt2;*pt2
=temp;
//交换}void
exchange(int*q1,int*q2,int*q3)
//排序{
if
(*q1
>*q2)swap(q1,q2);//两两交换
if
(*q1
>*q3)swap(q1,q3);//两两交换
if
(*q2
>*q3)swap(q2,q3);//两两交换}void
main(){
int
a,b,c,*p1,*p2,*p3; scanf("%d%d%d",&a,&b,&c); p1=&a;p2=&b;p3=&c; exchange(p1,p2,p3); printf("Aftersorted:%d
%d
%d\n",a,b,c);}1.形参与实参均为普通指针【例7.11】用形参为二重指针,实参为指针的地址的调用方法交换两个指针变量的值的程序7.5.2形参是指针变量,实参是指针变量2.形参为二重指针,实参为指针的地址#include
<stdio.h>void
swap(int**x,int**y)
//形参为二重指针变量{ int*temp; temp=*x;*x=*y;*y=temp;
}void
main(){ int
a=3,b=4;
int*t,*s; t=&a,s=&b;
swap(&t,&s);
//实参为指针变量的地址
printf("a=%d,b=%d\n",a,b); printf("*t=%d,*s=%d\n",*t,*s);}回顾:
intx,*p;p=&x;则:*p就是x调用函数后交换了t与s,所以输出如下:7.5.3数组或指针变量作为函数的参数四种常见情形:(具有等价性,可任意使用)1.形参和实参都是数组名voidmain()
f(intx[],intn){inta[10];
{
……
……
f(a,10);
}
……}调用后,形参数组x指向实参a数组,共享a数组空间。2.实参用数组,形参用指针变量voidmain()
f(int*x,intn){
inta[10];
{
……
….
f(a,10);
}
……}调用后,形参指针x指向实参a数组的首地址,共享a数组空间。3.
实参为指针变量,形参为数组名voidmain()
f(intx[],intn){
inta[10],*p=a;
{
……
……
f(p,10);
}
……}调用后,形参数组x指向变量p所指向的存储空间,而p=a;所以数组x共享a数组空间。4.实参、形参都用指针变量voidmain()
f(int*x,intn){
inta[10],*p=a;
{
……
……
f(p,10);
}
……}调用后指针变量x指向变量p所指向的存储空间,而p=a;所以指针x指向a数组首地址。7.5.3数组或指针变量作为函数的参数【例7.12】编写函数在数组中查找给定元素的下标,如果查到返回其下标,如果没有查找返回-1,再编写一个程序通过反复调用,实现不同数据的查找(使用方案1)int
search(int
pa[],int
n,int
x){
int
i,pos=-1;
//pos初始为-1表示没有查到
for
(i=0;i<n;i++)
if
(pa[i]==x) { pos=i;break;
//查到,保存位置,退出循环
}
return
pos;
//返回位置下标}intsearch(inta[],intn,intx)//参数a为待查数组,n数组长度,x待查数据,查到返回元素下标,没有查到返回-1.#defineN100int
main(){ int
arr[N],m;
//元素个数
int
i,se,p;
//se待查数据p查找结果 scanf("%d",&m);
for
(i=0;i<m;i++)scanf("%d",arr+i);
do { printf("Inputsearchdata:"); scanf("%d",&se); p=search(arr,m,se);//函数调用
if
(p==-1) printf("%d
NOfound\n",se);
else printf("Thissubscriptis=%d,valueis=%d\n",p,arr[p]); }while
(se!=0);
//输入0则结束程序}7.5.3数组或指针变量作为函数的参数【例7.13】编写函数将数组a中的n个整数按相反顺序存放,函数使用指针变量做形参,主程序调用此函数实现数组元素的倒置存放。(使用方案2)voidinv(int*x,intn)void
inv(int*x,int
n)
//形参x为指针变量{ int*p,*q,temp; p=x;q=x
+n
-1;
//p指向数组第1个元素,q指向数组最后1个元素
for
(;p<=q;p++,q--)//交换
{ temp=*p;*p=*q;*q=temp; }
return;}void
main(){
int
i,a[10]={3,7,9,11,0,6,7,5,4,2}; printf("Theoriginalarray:\n");
for
(i=0;i<10;i++) printf("%d,",a[i]); printf("\n"); inv(a,10);//实参为数组名
printf("Thearrayhasbenninverted:\n");
for
(i=0;i<10;i++) printf("%d,",a[i]); printf("\n");}7.5.3数组或指针变量作为函数的参数【例7.14】编写一个函数在已经排序的数组中插入一个新的数使数组元素继续保持有序,并调用此函数对输入数据进行排序voidinsert(inta[],intn,intx)#include
<stdio.h>void
insert(int
a[],int
n,int
x)//在由小到大排列的数组a中插入新元素x{
int
i;
for
(i=n;i>0&&a[i-1]>x;i--)
a[i]=a[i-1];
//从尾部开始后移
a[i]=x;
//插入新的数x}void
main(){
int
a[10],*p=a;
int
m,i; printf("Pleaseinputdata:");
for
(i=0;i<10;i++) { scanf("%d,",&m); insert(p,i,m);//将每个新输入的数插入到已排序的数组中
} printf("Thearrayaftersorted:\n");
for
(p=a,i=0;i<10;i++) { printf("%d
",*p);p++; } printf("\n");}7.5.4字符串作为函数参数大多数情况下程序员习惯于用指针来表示字符串,字符串做为函数形参的常见情形为:
返回值类型
函数名(char*str)【例7.15】要求按strcpy()函数的功能自定义函数实现把一个字符串的内容复制到另一个字符串中,并用此函数实现2个字符串的交换void
cpystr(char*pss,char*pds)//pss为源串,pds为目标串{ while
(*pss
!='\0')//字符串是否结束
{ *pds
=*pss;//逐个字符复制
pds++;pss++;//移动下一位置
} *pds
='\0';
//填充结束符\0}void
main(){ char
a[80],b[80],c[80];
char*pa,*pb,*pc; pa=a;pb=b;pc=c; printf("Inputstring
1:"); gets_s(pa,80); printf("Inputstring2:"); gets_s(pb,80); cpystr(pa,pc);//把a字符串复制到c字符串中
cpystr(pb,pa);//把b字符串复制到a字符串中
cpystr(pc,pb);//把c字符串复制到b字符串中
printf("string1=%s\nstring2=%s\n",pa,pb);}voidcprstr(char*pss,char*pds){while(*pdss++=*pss++);}简化后的函数7.5.4字符串作为函数参数【例7.16】编写一个求字符串的子串的函数,要求将原字符串中从第n个字符开始长度为m的子串写入到新的字符串中,如果n大于原字符串长度则子串为空串,如果原从n开始后面的长度不足m则只取原串中从n开始到结尾字符为止。编写主程序验证上述函数的正确性(ex7_16.cpp)。问题分析:首先构造求子串函数:
voidsubstr(char*source,char*subs,intn,intlen)
//source为原串,subs为子串,n为起始位置(从1开始),m为子串长度(1)求子串的过程实际上就是字符串的复制过程(2)在函数中注意n与m与原字符串长度的关系(3)在求出子串后将\0写入到子串的结尾处。7.5.4字符串作为函数参数#include
<stdio.h>#include<string.h>void
substr(char*source,char*subs,int
n,int
m)//source为原串,subs为子串,n为起始位置(从1开始),m为子串长度{ int
i,len;
char*p; len=strlen(source);
if
(n
<=0||n
>len)//n的值不在有效范围内,子串为空
*subs
='\0';
else { p=source
+n
-1;
//原串的起点
for
(i=0;i<m
&&*p!='\0';i++)//复制子串
*subs++=*p++; *subs
='\0';
//写入结束标记
}}int
main(){
char
a[80],b[80];
char*pa,*pb;
int
n,m; pa=a;pb=b; printf("Inputsourcestring:"); gets_s(pa,80); printf("Inputstartposition(n)andlength(m):"); scanf("%d%d",&n,&m); substr(pa,pb,n,m);//函数调用
printf("substringis=%s\n",pb);
return
0;}在书写函数地一定要严格按照函数头约定的形参五返回值要求来做自行重写上一章中的所有字符串库函数,收获巨大7.5.4指针数组作为函数的参数指针数组作指针型函数的参数通常用于对一组字符串的运算。【例7.17】输入5个国家的英文名称并按字母顺序排列后输出#include
<stdio.h>#include
<string.h>void
sort(char*name[],int
n)//排序{
char*pt;
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)
{pt=name[i];name[i]=name[k];name[k]=pt;
}
}}void
print(char*name[],int
n)//输出字符串{
int
i;
for
(i=0;i<n;i++)
puts(name[i]);}int
main(){
char
str[5][80];//存储10个字符串
char
*name[5];
//指针数组
int
i,m=5;
printf("Input5strimg:\n");
for
(i=0;i<m;i++)
{
name[i]=str[i];//指针数组指向行
gets_s(name[i],80);
}
printf("
Aftersorted:\n");
sort(name,m);
print(name,m);}类型说明符*函数名(形参表)需要用到函数返回值为地址时的情形函数的返回值为指针类型说明符(*指针变量名)(参数表);通过指针实现地不同函数的调用它是一个变量对比7.6指向函数的指针变量与指针型函数指向函数的指针变量指针型函数与指向的函数定义类似加上(*)与一般函数定义类似只加上*函数名就是函数的首地址7.6.1指向函数的指针变量【例7.19】指向函数的指针变量作为函数的形参示例:求三个数的最大、最小数#include
<stdio.h>int
max(int
a,int
b){
return
a
>b
?a
:b;}int
min(int
a,int
b){
return
a
<b
?a
:b;}int
value(int
x,int
y,int
z,int
(*p)(int,int)){
int
temp; temp=(*p)(x,y);
//调用指定的函数p
return
(*p)(temp,z);
//调用指定的函数p}void
main(){
int(*p)(int,int);
//定义指向函数的指针变量p
int
x,y,z; printf("inputthreenumbers:"); scanf("%d%d%d",&x,&y,&z); p=min; printf("min=%d\n",value(x,y,z,p));//指向函数的指针变量p作为实参
p=max; printf("max=%d\n",value(x,y,z,p));//指向函数的指针变量p作为实参}注意观察相关语句的书写方法7.6.2指针型函数指针型函数是指一个函数的返回值是一个指针。指针型函数的定义一般形式为:类型说明符
*函数名(形参表){……//函数体}常用于字符串函数中。【例7.20】编写自定义函数strsubstr实现strstr()函数的功能,并调用它实现子串的替换操作char*strsubstr(constchar*str1,constchar*str2)说明:它是一个参数为两个字符指针类型,返回值是char*类型的函数。功能:用于找到子串(str2)在一个字符串(str1)中第一次出现的位置(不包括str2的串结束符),并返回该位置的指针,如果找不到,返回空指针(NULL)。7.6.2指针型函数char*strsubstr(const
char*str1,const
char*str2)//求子串位置{ const
char*s1=str1;
const
char*s2=str2;
const
char*p=str1;
while
(*p!='\0') { s1=p; s2=str2;
while
(*s1!='\0'
&&*s2!='\0'
&&*s1==*s2)
//逐个字符比较
{ s1++;s2++; }
if
(*s2=='\0')
//找到返回起始位置
return
(char*)p; p++; }
return
NULL;}int
main(){ char
str[]="Thisisasimplestring.helloworld!";
char*pch; pch=strsubstr(str,"string.");//函数调用找子串位置
if
(pch!=NULL) { printf("%s\n",str); printf("%s\n",pch); strncpy(pch,"example",7);//字符串替换,从找到位置开始进行替换
} printf("%s\n",str);//输出替换后的字符串
printf("%s\n",pch);//输出替换后的字符串
return
0;}【例7.20】的程序7.6.2指针型函数【例7.21】编写一个指针型函数,它输入一个1~7之间的整数,返回对应的星期名的指针.constchar*name[]={"Illegalweek-day","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday","Sunday"};解决原始数据的存放函数的定义constchar*day_name(constchar*arr[],intn,intk)#include
<stdio.h>
const
char*day_name(const
char*arr[],int
n,int
k)//根据k的值返回arr[k]{
//因为实参变量类型为constchar*name[],所以形参必须与它一致
//因为返回arr[k],它的类型为constchar*,所以函数返回类型必须为constchar*
return((k
<0||k>7)?arr[0]:arr[k]);
}7.6.2指针型函数【例7.21】编写一个指针型函数,它输入一个1~7之间的整数,返回对应的星期名的指针.int
main(){
const
char*name[]={"Illegalweek-day","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday","Sunday"
};//VS中初始化字符串指针必须用constchar*
int
m;
const
char*p;//因为函数返回类型必须为constchar*,所以它必须定义为constchar*
do { printf("inputDayNo:"); scanf("%d",&m); p=day_name(name,8,m);
//函数调用
printf("DayNo:%2d-->%s\n",m,p); }while
(m>=1&&m<=7);
//输入检测1-7为正确输入对应星期一到星期天
return
0;}7.6.2指针型函数【例7.22】编写一个以指针数组为形参的多字符串查找子串的函数,如果查到了返回查到的字符串指针,如果所有字符串均没有查到该子串,则返回NULL指针。在主函数中用二重字符指针作为函数实参调用上述函数,实现从键盘输入5个汉语句子,输入指定查找的子句,如果查到则输出该中文句子问题分析:(1)定义函数char*subsearch(char*arr[],intn,char*str),其中arr[i]指向所有待查找的句子,n为句子的个数,str为子句;逐句查找,如果查找了某句子包含了子句,则返回句子的起始指针,如果在所有句子中均未查到,则返回NULL。(2)函数的实现过程比较简单,利用strstr函数即可,即在循环中调用p=strstr(arr[i],str),如果p非空,则说明找到,返回arr[i],否则继续。在循环外加一句returnNULL,是因为如果循环中没有执行到return语句,说明所有句子中均不包含子句。7.6.2指针型函数【例7.21】编写一个指针型函数,它输入一个1~7之间的整数,返回对应的星期名的指针.(3)主函数
由于所有句子是从键盘随机输入的,因此先必须定义一个二维字符数组chinese[10][80],用于存放输入的字符串,由于函数形参为char*arr[]字符指针数组,因此必须定义一个指针数组*chp[10],并将此数组与二维数组的行地址进行关联,再定义一个二重字符指针char**p,让p指向chp,进行这样一套组合定义后就构成了如图7.27的结构。7.6.2指针型函数【例7.21】编写一个指针型函数,它输入一个1~7之间的整数,返回对应的星期名的指针.#include
<stdio.h>#include
<string.h>char*subsearch(char*arr[],int
n,char
*str)//在arr中查找子串str{ inti;
char*p;
for
(i=0;i<n;i++) { p=strstr(arr[i],str);
//在第个句子中查找
if
(p!=NULL)
return
arr[i];
//查到的情况
}
return
NULL;
//所有句子中无法没有查到的情况}int
main(){ char
chinese[10][80],**p;//二维数组存放中文句子
char
*chp[10];
//指针数组
char
sub[80],*q,*pos;//sub存放子句
int
i; p=chp;//指向指针数组
q=sub;//指向子句
for
(i=0;i<5;i++) { chp[i]=ch
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 儿科学术大会护理汇报
- 甲亢的护理教学查房
- 小儿气道异物梗阻的护理
- 品管圈护理项目成果改善模板
- 2026智能家居行业市场渗透率分析及未来发展路径研究报告
- 2026中国土壤修复市场规模测算与商业模式创新
- 2026茶饮行业市场发展分析及前景趋势与投资机会研究报告
- 2026中国多发性硬化症治疗药物临床试验进展及上市预测
- 2026中国智能娱乐系统行业市场供需分析及投资评估规划分析研究报告
- 2026全国外经贸从业资格考试(国际贸易业务员实务)历年参考题库含答案详解
- 2026年专业技术人员继续教育公需科目-智慧城市历年参考题库含答案解析
- 2026年县直机关干部公开遴选笔试试卷(附答案)
- 26新六年级上册道德与法治【知识点总结】
- 石材护理技术规范SOP
- CSCO结直肠癌诊疗指南(2026版)
- 《新能源专业导论》新能源相关专业全套教学课件
- 教科版小学科学二年级上册和下册【全册】教学课件上下共两册
- 人力资源业务开展制度
- 中华传统文化课程思政教学案例
- 18.2 课时1 勾股定理的逆定理 教学课件 2025-2026学年沪科版数学八年级下册
- 2026年英语流利说的测试题及答案
评论
0/150
提交评论