第十一章 对函数的进一步讨论
11.1 传给 main函数的参数以前 main函数的一对圆括号是空的,即 main( )
但是可以通过运行 C程序,把参数传给 C程序如下所示,
main(int argc,char **argv)
{……………}
其中 argc和 argv是两个参数,可由用户命名,
argc必须是整型,argv是一个指向字符型的指针数组的指针
11.1传给 main函数的参数第二个参数也可定义成,char *argv[]
若我们对上述主函数进行编译连接,生成名为 myc.exe的可执行文件,则当我们打入,
myc OK! GOOD<CR>
其中 OK! 和 GOOD称为命令行参数,argc的值为 3
myc\0
OK!\0
GOOD\0
\0
argv的结构如下所示,
argv
即,argv[0],argv[1],argv[2]分别指向字符串 myc,OK!,GOOD
字符串 argv[0]必不可少,argc的值至少 1,按规定 argv[argc]由系统置‘ \0’.
例如:
main(int argc,char *argv[])
{int i;
printf(“argc=%d\n”,argc);
for(i=1;i<argc;i++)
printf(“%s,,argv[i]);
printf(“\n”);
}
若在命令行中打入,myc A COMMAND LINE<CR>
程序将输出:??
2.2 通过实参向函数传递函数名或指向函数的指针变量
1,指向函数的指针变量的定义在C语言中函数名代表该函数的入口地址,可以定义一种指向函数的指针来存放这个地址。
double fun(int a,int *p)
{……}
main()
{double (*fp)(int,int*),y; int n;
fp=fun;
…….
y=(*fp)(56,&n);
…….}
其中,说明符( *fp)(int,int*)说明 fp是一个指向函数的指针变量若写成 *fp(int,int*),说明 fp不是指针变量,
而是说明 fp是一个函数,该函数的返回值的类型是基类型为 double的指针类型语句 fp=fun把 fun函数的地址赋给指针变量 fp,
语句 y=(*fp)(56,&n),实现对函数的调用。
11.3 函数的递归调用递归调用:直接或间接的调用自己二个条件:
可以把要解的问题转化为新的问题,解法与原来的相同,
而对象有规律地递增或递减。
必定要有一个明确的结束递归的条件。
2.函数名或指向函数的指针作为实参函数名或指向函数的指针可作为实参传给函数,当然,
对应的形参必须是类型相同的指针变量。
见书 p161的例 11.2
例 11.3 用递归的方法求 n!(书 p162)
求 n!可以用以下数学关系表示,
n!=
1 当 n =0 时
n.(n-1)! 当 n >0 时也即,求 n!的问题可以转化为求 n.(n-1)! 的新问题,而求 (n-1)! 的解法与求 n!的解法完全相同
fac (int n)
{ int t;
if (n==1||n==0) return 1;
else
{t=n*fac(n-1);
return t;
}
}
main()
{ int m,y;
printf(“enter m:”);
scanf(“%d”,&m);
if( m<0) printf(“input data error!”);
else
{ y=fac(m);
printf(“\n%d!=%d\n”,m,y);
}
}
t’=n’*fac(n’-1);
return t’;
t”=n”*fac(n”-1);
return t”;
t’’’=n’’’*fac(n’’’-1
return t’’’ return 1;
n’=4 n”=3 n’’’=2 n’’’’=1
第一层调用 第二层调用 第三层调用 第四层调用例 11.4 用递归算法根据以下求平方根的迭代公式
x1= ( x0+ )
利用迭代公式求某数 a的平方根的算法已在例 4.11中作过介绍。
用递归算法的程序如下,
#include,math.h”
double mysqrt ( double a,double x0)
2
1 0x
a
{ double x1,y;
x1= ( x0+a / x0 ) / 2.0;
if ( fabs ( x1-x0 )>0.00001 ) return mysqrt ( a,x1 );
else return x1;
}
main ( )
{ double a;
printf (,Enter a,,); scanf (“%lf”,&a );
printf (,The sprt of%f =%f\n”,a,mysqrt ( a,1.0) );
}
TCIDE
说明,
所有递归问题都可用非递归方法解决
递归使程序简洁明了,具有较好的可读性
递归调用会降低程序的运行效率,
[例 ] Hanoi 汉诺 塔问题。这是一个典型的只有用递归方法(而不可能用其它方法)解决的问题。问题是这样的:有三根针 A.B.C,A
针上有 64个盘子,盘子大小不等,大的在下,
小的在上。要求把这 64个盘子从 A针移到 C针,
在移动过程中可以借助 B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。要求编程序打印出移动的步骤。
将 n个盘子从 A针移到 C针可以分解为以下三个步骤:
1.将 A上 n一 1个盘借助 C针先移到 B针上。
2.把 A针上剩下的一个盘移到 C针上。
3.将 n-1个盘从 b针借助于 A针移到 C针上。
例如,要想将 A针上 3个盘子移到 C针上,可以分解为以下三步:
1.将 A针上 2个盘于移到 B针上(借助 c)。
2.将 A针上 1个盘子移到 C针上。
3。将 B针上 2个盘子移到 C针上(借助 A)。
其中第 2步可以直接实现。
第 1步又可用递归方法分解为:
1.1 将 A上 1个盘子从 A移到 C。
1.2 将 A上 1个盘子从 A移到 B.
1.3 将 C上 1个盘子从 C移到 B。
第 3步可以分解为:
3.1 将 B上 1个盘子从 B移到 A上。
3.2 将 B上 1个盘子从 B移到 C上。
3.3 将 A上 1个盘子从 A移到 C上。
将以上综合起来,可得到移动的步骤为:
A==>C,A==>B,C==>B,A==>C,B==>A,B==>C,
A==>C。
上面第 1步和第 3步,都是把 n-1个盘从一个针移到另一个针 上,采取的办法是一样的,只是针的名字不同而已。为使之一般化,可以将第 1步和第 3步表示为:
将,one”针上 n-1个盘移到,two”针,借助 "three"针
".
只是在第 ① 步和第 ③ 步中,One,two,three和 A,B、
C的对应关系不同 。 对第 ① 步,对应关系是 。 one--A,、
two--B,three--C。 对第 ③ 步,是,one--B,two--C,
three--A。
因此,可以把上面三个步骤分成两类操作:
1·将 n一 1个盘从一个针移到另一个针上 ( n> 1) 。
这是一个递归的过程。
2.将 1个盘子从一个针上移到另一针上。
下面编写程序。分别用两个函数实现以上的两类操作,
用 hanoi函数实现上面第 1类操作,用 move函数实现上面第 2
类操作,hanoi( n,one,two,three)表示,将 n个盘子从
"one"针移到 "three"针,借助,two”针,。 move
( getone,putone)表示将 1个盘子从 "getone"针移到
,putone”针。 getone和 putone也是代表 A,B,c针 f之一,
根据每次不同情况分别取 A,B,C代人。
程序如下:
void move( char getone,char putone)
{printf("%c-->%c\n",getone,putone); }
void hanoi( int n,char one,char two,char three)
/ *将 n个盘 从 one借助 two,移到 three*/
{if( n==1) move( one,three);
else
{hanoi( n-1,one,three,two);
move ( one,three) ;
hanoi( n-1,two,one,three); }
}
main()
{ int m;
printf("input the number of diskes,");
scanf( "%d",&m);
printf( "The step to moving % 3d diskes:\n”,m);
hanoi( m,'A','B','C');
}
运行情况如下:
input the number of diskes,3
The step to moving 3 diskes,
A--—>C
A一一 >B
C一一 >B
A一一 >C
B一一 >A
B一一 >C
A一一 >C
由于篇幅关系,不再对上述程序作过多解释,请大家仔细理解。