函数
理解函数
要理解函数,首先要弄懂什么是函数和如何使用函数。
函数是已命名的,执行专项任务的独立C代码段,可选择是否向调用它的程序返回一个值。现在,仔细分析这段定义。
- 函数是已命名的 每个函数都有独一无二的函数名。在程序的其他部分使用函数名,可以执行该函数中的语句。这也称为调用(call)函数。可以在函数中调用其他函数。
- 函数是独立的 函数可独立执行任务,无需程序其他部分干预。
- 函数可以向调用它的程序返回一个值 程序调用函数时,会执行函数中的语句。如果需要的话,可以把特定信息传递给调用它们的程序。
渐进式编程(渐进开发)
初学者常常犯这样一个错误,即在不尝试编译的情况下就编写大量代码,然后再花费大量的时间调试代码。我们认为渐近开发是一种更好的方法,这种方法的要点如下:
- 先编写一个能够运行的简单程序,再逐步修改。这样的话,无论什么时候出现错误,你都知道该检查哪些地方。
- 用变量存储中间值,以便能够用打印语句或调试器检查它们。
- 程序能够正确运行之后再将多条语句合并为复合表达式(前提是这样不会导致程序更难理解。
------以上内容来自《JAVA编程思维》
结合《代码整洁之道》的思想,我们可以将每一部分的小代码提取成为一个实用的函数(在面向对象中实用性更高),然后通过渐进式编程确保每个函数的绝对正确性,这样在出现错误时,更方便检查出错的地方。
实例
求三个整数(有正有负)中绝对值最大的数。
输入 12 -14 7
输出 -14
以下代码是没有使用函数的渐进式编程,测试位置在注释中给出。
#include <stdio.h>
int main(void)
{
// 首先读取三个数
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
// !!! 初期建议在此处停止编写代码, 应当验证数据是否读取
// !!! 在以后的数组读取中, 这里的重要性很高, 数组经常会出现少读、多读、读错位置的情况
// !!! 以下为测试代码, 验证成功后可以删掉或者注释掉
// printf("a = %d, b = %d, c = %d", a, b, c);
// 定义一个变量用来存储绝对值最大的数
int maxAbsolute;
// 比较 a 与 b, 找出绝对值最大的值
if (a < 0)
{
// 此时花括号里的 a 都是负值
if (b < 0)
{
// 此时 a b 都为负数, 谁更小谁的绝对值就越大
if (a < b)
maxAbsolute = a;
else
maxAbsolute = b;
}
else
{
// 此时 a 为负, b 为正, 如果和小于 0, 则负数的绝对值大, 反之同理
if (a + b > 0)
maxAbsolute = a;
else
maxAbsolute = b;
}
}
else
{
// 此时花括号里的 a 都是正值
if (b < 0)
{
// 此时 a 为正, b 为负, 如果和大于 0, 则正数的绝对值大, 反之同理
if (a + b > 0)
maxAbsolute = a;
else
maxAbsolute = b;
}
else
{
// 此时 a b 都是正数, 谁大谁的绝对值就大
if (a > b)
maxAbsolute = a;
else
maxAbsolute = b;
}
}
// !!! 这一部分代码写完之后, 最好验证一下 a 与 b 之间的判断是否正确
// !!! 测试代码如下, 测试完之后删掉或者注释掉
// printf("maxAbsolute between a and b is: %d", maxAbsolute);
// 比较 maxAbsolute 与 c 谁的绝对值更大
if (maxAbsolute < 0)
{
// 此时 maxAbsolute 为负
if (c < 0)
{
// 此时 maxAbsolute 与 c 都为负, 谁越小谁的绝对值越大
if (maxAbsolute < c)
;
else
maxAbsolute = c;
}
else
{
// 此时 maxAbsolute 为负, c 为正, 和小于0, 则负数的绝对值大, 反之同理
if (maxAbsolute + c < 0)
;
else
maxAbsolute = c;
}
}
else
{
// 此时 maxAbsolute 为正
if (c < 0)
{
// 此时 maxAbsolute 为正, c 为负, 和大于0, 则正数的绝对值大, 反之同理
if (maxAbsolute + c > 0)
;
else
maxAbsolute = c;
}
else
{
// 此时 maxAbsolute 与 c 都为正, 谁越大谁的绝对值就越大
if (maxAbsolute > c)
;
else
maxAbsolute = c;
}
}
// !!! 本来此处也是需要验证的, 但是程序最终输出值恰好就是此处的结果
// !!! 所以可以直接执行后面的输出即可
printf("%d\n", maxAbsolute);
return 0;
// 事实是我在全部敲完所有代码之后才编译了, 因为觉得简单, 但是在运行的时候却又一种
// 庆幸感, 觉得程序没出错很幸运, 如果我没做一段就验证的话, 那我将会对结果有绝对的
// 掌控, 而不是用幸运来形容.
}
以上代码算上注释足足111行,但是却只是做了一个很简单的判断三个数中绝对值最大的数的问题,接下来将使用渐进式编程与函数结合去解决这个问题。
#include <stdio.h>
// 在最开始的时候, 主函数与该段注释之前没有任何东西 23:31(当前时间)
int absolute(int n); // 该段函数原型写于该函数定义完之后 23:38(当前时间)
int big(int a, int b); // 该段函数原型写于该函数定义完之后 23:44(当前时间)
int main(void)
{
// 依旧是获取三个数, 并将其存储起来
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
// 验证正确性, 代码如下, 之后可删可注释掉
// printf("a = %d, b = %d, c = %d", a, b, c);
// 定义一个存储最大绝对值的数
int maxAbsolute;
// 在这里我不想再一个个比较了, 我想直接得到他们的绝对值, 直接比较绝对值
// 我假设 absolute(a) 这个东西便是 a 的绝对值, 于是我便需要定义函数absolute
// (23:38) 函数定义了, 函数原型也写好了, 我得测试一下这个函数是不是能用
// 测试代码如下, 实际测试数据需要更多, 以确保正确性
// printf("absolute of -15 is: %d", absolute(-15));
// 测试结束, (23:41) 绝对值没问题了, 但是还需要进行比大小, 我也不想写那么多比大小
// 我假设 big(a, b) 这个东西便是 a b中的绝对值最大值所对应的数, 于是我便需要定义这个函数
// (23:45) 函数定义, 原型都好了, 继续测试 big 函数是否正确
// 测试代码如下
// printf("the big of 15 and 21 is : %d", big(15, 21));
// 测试结束, 我总算可以使用绝对值和比大小了, 直接开始使用
maxAbsolute = big(a, b);
maxAbsolute = big(a, b);
printf("%d", maxAbsolute);
return 0;
// (23:53) 当前时间
// 因为big函数定义的时候是直接比大小, 所以返回值一定是个正数, 修改了一下函数
// 将绝对值作为它调用的函数, 然后返回原数据(可正可负)
// 因为每一个函数都做测试, 所以很容易知道最终出错是在big这里
}
// 该段函数定义于假设 absolute(a) 是 a 的绝对值之后 23:36(当前时间)
int absolute(int n)
{
if (n < 0)
n *= -1;
return n;
}
// 函数定义完了, 因为定义在了 main 函数后面, 所以我便需要在前面写上函数原型
// 该段函数定义于假设 big(a, b) 是 a b中的最大值之后 23:43(当前时间)
// 该段程序修改于 23:52
int big(int a, int b)
{
if (absolute(a) > absolute(b))
return a;
else
return b;
}
// 函数定义完了, 继续补上函数原型
函数整体61行,还可以继续优化,不过暂时就先这样了。
最大的错误在于使用big时返回值为正,然后将绝对值作为big的调用,改变big定义,改为判断两个数的绝对值大小,返回绝对值大的那个数,然后返回值就可正可负,弥补了只能为正的缺憾