实验任务一
原始程序代码:
1 // 一元二次方程求解 2 // 重复执行, 直到按Ctrl+Z结束 3 // 4 #include <math.h> 5 #include <stdio.h> 6 int main() { 7 float a, b, c, x1, x2; 8 float delta, real, imag; 9 printf("Enter a, b, c: "); 10 while(scanf("%f%f%f", &a, &b, &c) != EOF) { 11 if(a == 0) 12 printf("not quadratic equation. "); 13 else { 14 delta = b*b - 4*a*c; 15 if(delta >= 0) { 16 x1 = (-b + sqrt(delta)) / (2*a); 17 x2 = (-b - sqrt(delta)) / (2*a); 18 printf("x1 = %.2f, x2 = %.2f ", x1, x2); 19 } 20 else { 21 real = -b/(2*a); 22 imag = sqrt(-delta) / (2*a); 23 printf("x1 = %.2f + %.2fi, x2 = %.2f - %.2fi ", real, 24 imag, real, imag); 25 } 26 } 27 printf("Enter a, b, c: "); 28 } 29 return 0; 30 }
改版程序代码:
1 // 一元二次方程求解(函数实现方式) 2 // 重复执行, 直到按下Ctrl+Z结束 3 #include <math.h> 4 #include <stdio.h> 5 // 函数声明 6 void solve(double a, double b, double c); 7 // 主函数 8 int main() { 9 double a, b, c; 10 printf("Enter a, b, c: "); 11 while(scanf("%lf%lf%lf", &a, &b, &c) != EOF) { 12 solve(a, b, c); // 函数调用 13 printf("Enter a, b, c: "); 14 } 15 return 0; 16 } 17 // 函数定义 18 // 功能:求解一元二次方程,打印输出结果 19 // 形式参数:a,b,c为一元二次方程系数 20 void solve(double a, double b, double c) { 21 double x1, x2; 22 double delta, real, imag; 23 if(a == 0) 24 printf("not quadratic equation. "); 25 else { 26 delta = b*b - 4*a*c; 27 if(delta >= 0) { 28 x1 = (-b + sqrt(delta)) / (2*a); 29 x2 = (-b - sqrt(delta)) / (2*a); 30 printf("x1 = %f, x2 = %f ", x1, x2); 31 } 32 else { 33 real = -b/(2*a); 34 imag = sqrt(-delta) / (2*a); 35 printf("x1 = %f + %fi, x2 = %f - %fi ", real, imag, real,imag); 36 } 37 } 38 }
解析:
1、定义函数solve,则在这个计算一元二次方程的程序中的共能肯定是进行公式求解。
2、既然是用公式求解来定义函数,那么输入的形参肯定就是三个,“a,b,c"。
3、通过公式计算出结果可以作为函数返回值也可以直接打印,二者都同等方便,仅看使用者需求。
4、若是无返回值的方式编写solve函数,则其应当具有判断是否能成功调用程序至输出结果、计算实参、以及打印计算结果。
若是带返回值的方式,则应当将计算的两根的结果返回给main函数。
5、对比前后两版本的程序,修改的地方无非是让主函数的功能由输入、计算、输出变化为输入、引用函数,而已。
使主函数看起来更加的简洁明了,意图容易理解。
实验任务二
原始程序:
1 // 利用局部static变量计算阶乘 2 #include <stdio.h> 3 long long fac(int n); // 函数声明 4 int main() { 5 int i,n; 6 printf("Enter n: "); 7 scanf("%d", &n); 8 for(i=1; i<=n; ++i) 9 printf("%d! = %lld ", i, fac(i)); 10 return 0; 11 } 12 // 函数定义 13 long long fac(int n) { 14 static long long p = 1; 15 p = p*n; 16 return p; 17 }
运行结果:
为了探究局部static变量
增加一行代码: printf("p = %lld ", p);
修改程序:
1 // 利用局部static变量计算阶乘 2 #include <stdio.h> 3 long long fac(int n); // 函数声明 4 int main() { 5 int i,n; 6 printf("Enter n: "); 7 scanf("%d", &n); 8 for(i=1; i<=n; ++i) 9 printf("%d! = %lld ", i, fac(i)); 10 return 0; 11 } 12 // 函数定义 13 long long fac(int n) { 14 static long long p = 1; 15 printf("p = %lld ", p); 16 p = p*n; 17 return p; 18 }
运行结果:
明显可见,虽然在fac()函数的首段具有p的初始化,但是p的值一直保留着上一次调用结果的p值。
例题:
1 // 练习:局部static变量特性 2 #include<stdio.h> 3 int func(int, int); 4 int main() { 5 int k=4,m=1,p1,p2; 6 p1 = func(k,m) ; 7 p2 = func(k,m) ; 8 printf("%d,%d ",p1,p2) ; 9 return 0; 10 } 11 int func(int a,int b) { 12 static int m=0,i=2; 13 i += m+1; 14 m = i+a+b; 15 return (m); 16 }
猜想打印结果:8 17
实验任务三
题目:填入空缺代码
1 //寻找两个整数之间的所有素数(包括这两个整数),把结果保存在数组bb中,函数返回素数的个数。 2 // 例如,输入6和21,则输出为:7 11 13 17 19。 3 #include <stdio.h> 4 #define N 1000 5 int fun(int n,int m,int bb[N]) { 6 int i,j,k=0,flag; 7 for(j=n;j<=m;j++) { 8 flag=1;/*补足1*/ 9 for(i=2;i<j;i++) 10 if(j%i==0/*补足2*/) { 11 flag=0; 12 break; 13 } 14 if(flag!=0/*补足3*/) 15 bb[k++]=j; 16 } 17 return k; 18 } 19 int main(){ 20 int n=0,m=0,i,k,bb[N]; 21 scanf("%d",&n); 22 scanf("%d",&m); 23 for(i=0;i<m-n;i++) 24 bb[i]=0; 25 k=fun(n,m,bb/*补足4*/); 26 for(i=0;i<k;i++) 27 printf("%4d",bb[i]); 28 return 0; 29 }
运行结果:
思路:
补足1:将flag初始化,作为判定是否为素数的标志
补足2:测试目前检查的这个整数是否能被一个数整除
补足3:如果已经判断出该数为素数
补足4:以主函数中的变量调用函数
实验任务四
例题:实现f(n)=2^n-1
程序:
1 #include <stdio.h> 2 long long fun(int n); // 函数声明 3 int main() { 4 int n; 5 long long f; 6 while(scanf("%d", &n) != EOF) { 7 f = fun(n); // 函数调用 8 printf("n = %d, f = %lld ", n, f); 9 } 10 return 0; 11 } 12 // 函数定义 13 // 补足。。。 14 long long fun(int n){ 15 long long g=0,f=0; 16 if(n==1){ 17 g=2; 18 } 19 else{ 20 g=2*(fun(n-1)+1); 21 } 22 f=g-1; 23 return f; 24 }
输出结果:
bonus part:
例题:实现2^n-1
(待补充
实验任务五
原始程序:
1 #include <stdio.h> 2 void draw(int n, char symbol); // 函数声明 3 #include <stdio.h> 4 int main() { 5 int n, symbol; 6 while(scanf("%d %c", &n, &symbol) != EOF) { 7 draw(n, symbol); // 函数调用 8 printf(" "); 9 } 10 return 0; 11 } 12 // 函数定义 13 // 补足代码。。。 14 void draw(int n, char symbol){ 15 int st; 16 int count=1; 17 for(;n>=0;n--){ 18 //前半空白 19 for(int i=n;i>0;i--) 20 printf(" "); 21 //打印字符 22 st=2*count-1; 23 count++; 24 while(st--){ 25 printf("%c",symbol); 26 } 27 //后半空白 28 for(int t=n;t>0;t--) 29 printf(" "); 30 //换行 31 printf(" "); 32 fflush(stdin); 33 } 34 }
运行结果:
实验总结
说实话我觉得这章和上章的关系太紧密了,函数是这一章的主要内容,我们是学会怎么使用、构造函数,
让它成为我们第三章算法的偷懒工具。递归什么的,函数的亮点在编写程序里还是很能表现出来的。
嗯……熟能生巧还是真理,这是减少你调试次数的绝对办法之一。
有一句话不是说没有人能一遍编出完美的程序吗?Linus Torvalds也说
实际上没有人能一次就写出完美的代码,除了我。但是世界上只有一个我。
我尝试用数组和字符串的方法去写实验任务四的bonus part,但是写都写不出来。
现在先vacant,待我日后经验丰富了立刻回头来补足。
我认为编码风格、编码规范是很重要的东西,一类东西不应当隔着放,而且应当与不同的类隔行。
养成写开头注释,结尾注释,行注释的习惯。
Thanks for reading.