老程序员教我的编程技巧

  在编程中,我们经常会遇到问题(俗称bug),找出一个bug很费时间,那么那么我们该如何让程序少出bug,增加编程速度呢?这里有一些老程序员教我的编程技巧,可以用来借鉴和参考一下。

1. 先完成简单的功能, 再逐步增加复杂度
举例来说, 直接求多个数的 min/max, 比较复杂, 我们可以先从最简单的开始。
先求两个数的 min/max。

1 int max(int a, int b) {
2     if (a > b) return a;
3     else return b;
4 }

或是:

1 int min(int a, int b) {
2     if (a < b) return a;
3     else return b;
4 }

2. 求多个数的 min/max。
1) hardcode(硬编码):

1 int hard_max_3(int a, int b, int c) {
2     if (a > b && a > c) return a;
3     if (b > a && b > c) return b;
4     if (c > a && c > b) return c;
5     if (? ? ? ? ) return ? ? ? ? ;
6 }

2) 用两个数的 min/max 来求三个数的 min/max。

1 int max(int a, int b) {
2     if (a > b) return a;
3     else return b;
4 }
5 
6 int max_3(int a, int b, int c){
7     return max(a, max(b, c));
8 }

注意对比1号和2号的max_3,1号代码,也就是硬编码,整整使用了五行来算出这个结果,而2号只用了两行,就算出了结果。而且硬编码,你得保证他全部的情况都覆盖了,所以你要想很久,就很累。不光麻烦,还容易出错。

3) 用三个数的 min/max 来求四个数的 min/max。

1 int max_3(int a, int b, int c){
2     return max(a, max(b, c));
3 }
4 
5 int max_4(int a, int b, int c, int d) {
6     return max(a, max_3(b, c, d));
7 }

 此时如果你还想用硬编码编写4个数的最大值或者是最小值,我劝你还是算了吧。毕竟写三个就已经很累了,何况是4个呢。

3. 先写主框架, 再补充细节。

题目如下:

输入三位同学的期末考试成绩,分别判断以下条件,满足条件,执行动作:

请看以下代码:

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 int max(int a, int b) {
 6     if (a > b) return a;
 7     else return b;
 8 }
 9 
10 int min(int a, int b) {
11     if (a < b) return a;
12     else return b;
13 }
14 
15 }
16 int max_3(int a, int b, int c){
17     return max(a, max(b, c));
18 }
19 
20 
21 int max_4(int a, int b, int c, int d) {
22     //return max(a, max(b, max(c, d)));
23     return max(max(a, b), max(c, d));
24     return max(a, max_3(b, c, d));
25 }
26 
27 int min_3(int a, int b, int c) {
28     return min(a, min(b, c));
29 }
30 
31 double average(double a, double b, double c) {
32     return (a + b + c) / 3;
33 }
34 
35 int median(int a, int b, int c) {
36     return 0;
37 }
38 
39 bool diff(int a, int b, int c) {
40     return 0;
41 }
42 bool diff_x(int a, int b, int c) {
43     return false;
44 }
45 
46 int main() {
47     int a, b, c;
48     scanf("%d%d%d", &a, &b, &c);
49     if (a > 90 && b > 90 && c > 90) {
50         printf("%d", max_3(a, b, c));
51     }
52     else if (a < 60 && b < 60 && c < 60) {
53         printf("%d", min_3(a, b, c));
54     }
55     else if (a >= 60 && a <= 90 &&
56         b >= 60 && b <= 90 &&
57         c >= 60 && c <= 90 && diff(a, b, c))
58     {
59         printf("%.2lf", average(a, b, c));
60     }
61     else if (a >= 60 && a <= 90 &&
62         b >= 60 && b <= 90 &&
63         c >= 60 && c <= 90 && diff_x(a, b, c))
64     {
65         printf("%d", median(a, b, c));
66     }
67     else {
68         printf("数据差异过大");
69     }

重点关注第35到第45行。这3个函数median、diff和diff_x,我都没有写任何内容。但是第49行开始,一直到69行。判断语句完成得非常的完善。这就叫做先写主框架,再完成细节。如果你先写细节,在写主框架的话,即使细节很完美,都很有可能导致细节套不进主框架里面。

4. 每个功能写成一个函数。

还是以第3点的例子为例:

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 int max(int a, int b) {
 6     if (a > b) return a;
 7     else return b;
 8 }
 9 
10 int min(int a, int b) {
11     if (a < b) return a;
12     else return b;
13 }
14 
15 }
16 int max_3(int a, int b, int c){
17     return max(a, max(b, c));
18 }
19 
20 
21 int max_4(int a, int b, int c, int d) {
22     //return max(a, max(b, max(c, d)));
23     return max(max(a, b), max(c, d));
24     return max(a, max_3(b, c, d));
25 }
26 
27 int min_3(int a, int b, int c) {
28     return min(a, min(b, c));
29 }
30 
31 double average(double a, double b, double c) {
32     return (a + b + c) / 3;
33 }
34 
35 int median(int a, int b, int c) {
36     return 0;
37 }
38 
39 bool diff(int a, int b, int c) {
40     return 0;
41 }
42 bool diff_x(int a, int b, int c) {
43     return false;
44 }
45 
46 int main() {
47     int a, b, c;
48     scanf("%d%d%d", &a, &b, &c);
49     if (a > 90 && b > 90 && c > 90) {
50         printf("%d", max_3(a, b, c));
51     }
52     else if (a < 60 && b < 60 && c < 60) {
53         printf("%d", min_3(a, b, c));
54     }
55     else if (a >= 60 && a <= 90 &&
56         b >= 60 && b <= 90 &&
57         c >= 60 && c <= 90 && diff(a, b, c))
58     {
59         printf("%.2lf", average(a, b, c));
60     }
61     else if (a >= 60 && a <= 90 &&
62         b >= 60 && b <= 90 &&
63         c >= 60 && c <= 90 && diff_x(a, b, c))
64     {
65         printf("%d", median(a, b, c));
66     }
67     else {
68         printf("数据差异过大");
69     }

从第5到第42行,仅仅是为了求出一组数字的最大数和最小数,我们就写了很多的函数。

5. 对复杂的工程, 变量名和函数名要与实际用途相符。

题目描述

学校给同学们发文具,每个同学都会拿到一定数量的铅笔和橡皮。一共有n个同学,请你计算同学们一共拿到了多少铅笔和橡皮。

输入n,代表有n个同学。接下来n行,每行两个正整数,分别为某个同学收到的铅笔和橡皮数量。

输出同学们一共拿到了多少铅笔,多少橡皮,两个数字之间以空格分开。

代码如下:

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 int main(){
 5     int num_of_stu = 0;
 6     scanf("%d",&num_of);
 7     int i = 0;
 8     int pencil = 0;
 9     int eraser = 0;
10     int total_p = 0;
11     int total_e = 0;
12     while(i < num_of){
13         scanf("%d%d",&pencil,&eraser);
14         total_p += pencil;
15         total_e += eraser;
16         i += 1;
17     }
18     printf("%d %d",total_p,total_e);
19     return 0;
20
21 }

在这段代码中我们定义了6个变量。每个变量的含义都不相同,所以变量名一定要与变量的用处相符。将命名的好处是,在你维护的时候就可以知道这个变量是做什么用的,

6. scanf () 中的格式类型, 要与实际类型相符, 否则容易溢出。

 请看下面代码:

1 #include<cstdio>
2 #include<cmath>
3 using namespace std;
4 int main() {
5     char a = '0';
6     scanf("%d", &a);
7     printf("%c", a);
8     return 0;
9 }

我要输入一个字符,再输出这个字符。如果你运行上面这段代码,会发现你不会得到你想要的输出。那么这是为什么呢?我们用下面的程序来看一下。

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 int main() {
 5     char b = ' ';
 6     float c = 0.0;
 7     double d = 0.0;
 8     long x = 0;
 9     short y = 0;
10     int a = ' ';
11     printf("int: %d\n", sizeof(a));
12     printf("char: %d\n", sizeof(b));
13     printf("float: %d\n", sizeof(c));
14     printf("double: %d\n", sizeof(d));
15     printf("long: %d\n", sizeof(x));
16     printf("short: %d", sizeof(y));
17     return 0;
18 }

 输出如下:

所以整型要占用4个字节,而字符型只要占用一个字节。所以如果你把整型变量装在字符型的“抽屉”里,那它就会溢出了。

7. 在实现特定功能时, 为快速检查功能是否正确, 可以先不要 scanf, 给变量直接赋值,
等功能基本完成或确认无误后, 再注释掉赋值语句, 恢复 scanf。

题目描述

一棵苹果树上结了 n 个果,不幸的是被一条虫子盯上了。虫子每 x 小时能吃掉一个苹果,好在这个虫子比较傻,它吃完一个苹果之前不会吃另一个,

那么经过 y 小时,树上还剩下多少个完整的苹果?

代码如下:

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 int main(){
 5     int a,b,c;
 6     a = b = c = 0;
 7     scanf("%d%d%d",&a,&b,c);
 8     if (c % b != 0){
 9         printf("%d",a-(c / b + 1));
10     }
11     else{
12         printf("%d",a-(c / b));
13     }
14     return 0;
15 }

运行之后会发现程序有错误,什么都不输出,请问你知道为什么吗?

 我们先把scanf注释掉,然后呢,给a、b、c分别赋一个值来试一下。

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 int main(){
 5     int a,b,c;
 6     a = 10;
 7     b = 4;
 8     c = 9;
 9     //scanf("%d%d%d",&a,&b,c);
10     if (c % b != 0){
11         printf("%d",a-(c / b + 1));
12     }
13     else{
14         printf("%d",a-(c / b));
15     }
16     return 0;
17 }

 

此时,输出结果就变成正确的了:

 仔细观察原来的代码,你会发现scanf少了一个取址符。

呵呵🙂,真是个“低级错误”!

以上就是老程序员教给我的7个小妙招。