为了写一个程序,首先要构思出程序的用途,再用通俗易懂的文字写下这种方法。这个过程类似于拟定要办事员遵照办理的指令。这组指令称为算法
设计算法最有效的方法就是将任务分解为多个子任务,再将每个子任务分解成更小的子任务,以此类推,子任务会越变越小,很容易被C++代码实现,这种方法被称为自顶向下设计。又是也被称为 逐步求精,或者称为 分而治之
C++提供了预定义函数库。
一些预定义函数
名称 | 说明 | 实参类型 | 返回值类型 | 示例 | 值 | 库的头文件 |
---|---|---|---|---|---|---|
sqrt | 平方根 | double | double | sqrt(4.0) | 2.0 | cmath |
pow | 乘方 | double | double | pow(2.0,3.0) | 8.0 | cmath |
abs | 取int值的绝对值 | int | int | abs(-7) abs(7) | 7,7 | cstdlib |
labs | 取long值的绝对值 | long | long | labs(-70000) | 70000 | cstdlib |
fabs | 取double值的绝对值 | double | double | fabs(-7.5) | 7.5 | cmath |
ceil | 向上取整 | double | double | ceil(3.2) ceil(3.9) | 4.0 4.0 | cmath |
floor | 向下取整 | double | double | floor(3.2) floor(3.9) | 3.0 3.0 | cmath |
srand | 为随机数生成器提供种子值 | 无 | 无 | srand() | 无 | cstdlib |
rand | 随机数 | 无 | int | rand() | 0`RAND_MAX | cstdlib |
实例:
// 函数返回两个数中较大的那个数
int max(int num1, int num2)
{
// 局部变量声明
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
如:
int max(int num1, int num2);
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
调用类型 | 描述 |
---|---|
传值调用 | 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。 |
指针调用 | 该方法把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。 |
引用调用 | 该方法把参数的引用复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。 |
传引用详解
程序变量作为内存位置实现,编译器为每一个变量都分配一个内存位置。在使用传引用参数时,执行该函数调用时,函数得到的不是实参的值,而是得到和每个名称关联的内存位置。因此,执行函数主体语句时,函数主体对形参执行的任何操作实际会作用于与形参关联的内存位置处的变量。
为了区分传引用参数和传值参数,在函数声明和函数定义头中,要在类型名称末尾附加符号&。
例如:
void getInput(double& fVariable)
C++提供了生成伪随机数的预定义函数。伪随机数是表面上随机,实则由可预见的公式决定的数。
#include
#include
...
srand(time(0));
C++允许为同一个函数名称提供多个的定义,这表示在不同的情况下可以重用这些名称。例如,可以有3个名为max的函数,一个计算2个数的最大值,一个计算3个数的最大值,一个计算4个数的最大值。为同一个名称提供两个或多个函数定义被称为重载函数名称
重载函数名时,函数声明的形参必须有区别。如果两个函数唯一的区别就是返回值的类型,则不能使用重载这个函数名。
重载操作符/与重载函数名的区别,编译器已经完成了对操作符/的重载,而对函数名的重载需要依靠你的程序进行。
只需知道程序能执行什么任务,不必知道程序是如何执行的。这就是黑盒的比喻
说一样东西是黑盒,意思是说它像一个物理设备,知道怎么使用,但内部工作原理是保密的。
有时将设计函数,使之能作为黑盒使用的过程称为信息的隐藏
函数作为黑盒来编写和使用,这也称为过程抽象
对函数主体代码的细节进行提炼(抽象)称为黑盒原则、过程抽象或信息隐藏
过程抽象
怎样写返回值的黑盒函数定义
- 在函数声明的注释中,指出对函数实参的所有要求,并指出返回值的意义
- 函数主体使用的变量应该在函数主体中声明
过程抽象的原则在于,函数应设计成像黑盒那样使用。程序员使用函数时,只需查看函数声明和说明函数用途的注释文字,不需要知道函数主体的任何细节。
为函数声明写注释时,一个好办法就是将其分解成两种信息,即前条件和后条件。
前条件指调用函数需要满足什么条件。
后条件描述函数调用的结果。也就是说,对于要返回值的函数,后条件描述返回值。对于要对实参变量进行修改的函数,后条件描述对实参进行的修改。
每个函数都应独立于其他部分设计、编码、和测试。这是自顶向下设计策略的精髓。
函数在目标程序外部如何测试?答案是写专门的测试程序。这样的程序称为驱动程序。
驱动程序是临时工具,唯一要做的就是以尽量简单的方式为函数获得参数值,然后执行函数并显示结果。
测试函数时,有时不得不用到其他尚未编写或测试的函数。这时可以使用其他函数的简化版本。称为存根函数
存根函数不必执行正确的计算,只需提供完成测试所需的值。
将程序看成一个整体,不要妄图通过随意的修改代码的某些部分,以此来修正错误。
assert(断言)宏在assert语句的位置验证是否满足预期条件。条件不满足,程序显示错误并退出。
要求带有头文件#include
例如:
assert(n>0)
如果传递了任何负数或零值为参数,程序就会退出,并报告断言失败。
发布应用程序时,可能不想在最终的可执行程序中包含任何assert语句,因为用户可能看到他们不明白的错误信息。如果我们在代码中添加了大量assert语句,删除可能有一定困难。只需在程序开头,在#include 语句之前添加以下语句,即可禁用所有assert宏:
#define NDEBUG
#include
以后修改了程序需要重新调试,删除#define NDEBUG这一行,即可重新启用所有assert宏。