第二章函数
2.1函数的定义与使用
2.1.1 函数的定义
1.函数定义的语法形式
类型说明符 函数名(含类型说明的形式参数表)
{
语句序列
}
2.形式参数
形式参数表 type1 name1,type2 name2...typen namen
形参实现主调函数与被调函数之间的联系
3.返回值
函数返回值可有可无
return函数可指定返回值,也可结束当前函数的执行
void mian是一种很蠢的写法,很多编译器不支持
2.1.2 函数的调用(函数练习)
1.编写函数求pi的值
#include<iostream>
using namespace std;
double arctan(double x) {
double sqr = x*x;
double e = x;//规律性变化的分子
double r = 0;//arctan返回值,即该数的arctan
int i = 1;//变量i
while (e / i > 1e-15) {
double f = e / i;
r = (i % 4 == 1) ? r + f : r - f;//善用三目真的比满篇if for 好看的多
e = e*sqr;
i += 2;
}
return r;
}
int main() {
double a = 16.0*arctan(1 / 5.0);
double b = 4 * arctan(1 / 239.0);
//整数相除取整,所以要5.0
cout << "PI=" << a - b << endl;
return 0;
2.1000以内,本身及平方,立方均为回文数的数
#include<iostream>
using namespace std;
bool symm(unsigned n) {
unsigned i = n;
unsigned m = 0;
while (i>0)
{
m = m * 10 + i % 10;
i /= 10;
}
return m == n;//绝了,真简便
}
int main() {
for (unsigned m = 11; m < 1000; m++)
if (symm(m) && symm(m*m) && symm(m*m*m))
{
cout << "m=" << m;
cout << " m * m=" << m*m;
cout << " m * m * m=" << m*m*m << endl;
}
return 0;
}
3.求sin,调用sin的一道数学题
#include<iostream>
#include<cmath>
using namespace std;
const double tiny_value = 1e-10;//为什么不是-6呢,运行之后发现6和10差不多
double tsin(double x) {
double g = 0;
double t = x;
int n = 1;//分母
do {
g += t;//t即为每一个因式
n++;
t = -t*x*x / (2 * n - 1) / (2 * n - 2);//绝了,真屌
} while (fabs(t) >= tiny_value);//绝对值函数fabs
return g;//sin返回值从1开始
}
int main() {
double k, r, s;
cout << "r=";
cin >> r;
cout << "s=";
cin >> s;
if (r*r<=s*s)
k = sqrt(tsin(r)*tsin(r) + tsin(s)*tsin(s));
else
k = tsin(r*s) / 2;
cout<<k<<endl;
return 0;
}
4.投骰子小游戏
#include<iostream>
#include<cstdlib>
using namespace std;
//投骰子,计算和数,输出和数
int rolldice() {
int die1 = 1 + rand() % 6;
int die2 = 1 + rand() % 6;
int sum = die1 + die2;
cout << "player rolled " << die1 << "+" << die2 << "=" << sum << endl;
return sum;
}
enum gamestatus{win, lose, playing};//游戏状态,在主函数之前定义
int main() {
int sum, mypoint;
gamestatus status;//声明变量时可以不写关键字,枚举变量范围即枚举元素
unsigned seed;//seed种子,函数rand的初始值,感觉很喜欢用unsigned
cout << "please input an integer:";
cin >> seed;
srand(seed);//将种子传递给rand
sum = rolldice();//第一轮投骰子,计算和数
switch (sum) {
case 7:
case 11:
status = win;//如果和数为7或11就胜,状态为win
break;
case 2:
case 3:
case 12:
status = lose;//如果和数为2,3,12就负,状态为lose;
break;
default://其他情况,游戏尚无结果,状态为playing,记下点数,为下一轮做准备
status = playing;
mypoint = sum;
cout << "mypoint is " << mypoint << endl;
break;
}
while (status==playing)
{
sum = rolldice();//上面是第一轮的点数,循环内的sum需要一遍遍的试相不相等
if (sum == mypoint)
status = win;
else if (sum == 7)//逻辑结构需要用else if
status = lose;
}
//当状态不为playing时,上面的循环结束,以下程序输出游戏结束
if (status == win)
cout << "player wins" << endl;
else
cout << "player loses" << endl;
return 0;
}
5.简单的平方和,纯粹的快乐
#include<iostream>
using namespace std;
int fun2(int m) {//实现平方
return m*m;
}
int fun1(int x,int y) {//实现平方和
return fun2(x) + fun2(y);
}
int main() {
int x, y;
cout << "请输入两个数(a and b):";
cin>>x>>y;
cout<<"两数平方和为:"<<fun1(x,y)<<endl;
getchar();
getchar();
return 0;
}
6.递归求阶乘,多种做法
#include<iostream>
using namespace std;
unsigned fac(unsigned n) {//设计递归问题,需自后向前递推,否则逻辑上有根本性错误
unsigned f;
for (f=1; n>f; n--)
f = fac(n-1)*n;
return f;
}
int main() {
unsigned n;
cout << "请输入一个正整数:";
cin >> n;
cout << "该数的阶乘是:" << fac(n)<<endl;
return 0;
}
7.高考数学,选人问题
#include<iostream>
using namespace std;
int fac(int n,int k) {//计算n人选k人的组合数
int f;
if (k > n)
return 0;
else if (n == k || k == 0)//不用想明白每个情况,直接把规则一摆,结束标志一放,剩下的交给计算机就好
f = 1;
else
f = fac(n - 1, k) +fac(n - 1, k - 1);
return f;
}
int main() {
int n, k;
cin >> n >> k;
cout << fac(n, k);
return 0;
}
8.汉诺塔问题
关于递归:
1.一定不要试图跟踪大型递归的过程! 要写出递归,关键就是找出递归的递归方程式: 也就是说,要完成最后一步,那么最后一步的前一步要做什么。
2.在求f(n, other variables)的时候,你就默认f(n -1, other variables)已经被求出来了——至于怎么求的,这个是计算机通过回溯求出来的。
3.主要自定义函数里,把需要的全拿来当参数即可
#include<iostream>
using namespace std;
//把arc针最上面一个盘子移动到dest针上
void move(char src, char dest) {
cout << src << "-->" << dest << endl;
}
//把n个盘子从src针移动到dest针,以medium为中介
void hanoi(int n, char src, char medium, char dest) {
if (n == 1)
move(src, dest);
else
{
hanoi(n - 1, src, dest, medium);
move(src, dest);
hanoi(n - 1, medium, src, dest);
}
}
int main() {
int m;
cout<< "enter the number of diskes:";
cin >> m;
cout << "the steps to moving" << m << "diskes:" << endl;
hanoi(m, 'A', 'B', 'C');
return 0;
}
3.1.3 函数的参数传递
函数的参数传递,指的是形参与实参结合的过程,该过程有两种方式,值传递,引用传递
1.值传递(单向):当发生函数调用时,给形参分配内存空间,并用实参初始化形参
#include <iostream>
using namespace std;
void swap(int a, int b) {
int t = a;
a = b;
b = t;
}
int main() {
int x = 5, y = 10;
cout << "x=" << x << " y=" << y << endl;
swap(x, y);
cout << "x=" << x << " y=" << y << endl;
return 0;
}
结果并没有达到交换目的,形参值对实参不起作用(想用他输出交换后的也可以,自定义函数加上printf调用即可,但是实参输出依然不变)
2. 引用传递
引用是一种特殊类型的变量,可以认为是另一个变量的别名
注:声明一个引用时,必须对它初始化,使他指向一个存在的对象
引用初始化之后,就不能改为指向其他对象
int i,j;
int &ri=i;//建立一个int型的引用ri
j=10;
ri=j;//相当于i=j
引用也可做为形参,成为实参的别名,对形参的操作会作用于实参(交换成功)
#include<iostream>
using namespace std;
void swap(int &a, int &b) {
int t = a;
a = b;
b = t;
}
int main() {
int x = 5, y = 10;
cout << "x=" << x << " y=" << y << endl;
swap(x, y);
cout << "x=" << x << " y=" << y << endl;
return 0;
}
3.2 内联函数
函数调用会增加开销,小而频繁的函数设计为内联函数合理。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处
定义方式与普通函数一样,在函数前加 inline关键字即可(inline只表示要求,若过于复杂则不会被编译为内联函数)
3.3 带默认形参值的函数
函数在定义时可以预先声明默认的形参值
如:int add (int x=5, int y =6)
在有默认值的形参右边,不能出现无默认值的形参
在相同作用域内,不允许在同一个函数的多个声明对同一个参数的默认值重复定义(前后定义的值相同也不行)
如下
#include<iostream>
using namespace std;
inline int add(int x = 5, int y = 6);
int main() {
add();
return 0;
}
inline int add(int x/* 5 */, int y/* =6 */) {
//不能再出现默认形参,但是为了清晰可以加注释
return x + y;
}
存在默认形参时,实参变化的函数如下(求长方体体积)
#include<iostream>
#include<iomanip>
using namespace std;
int getvolume(int length, int width = 2, int height = 3);
int main() {
const int x = 10, y = 12, z = 15;
cout << "some box data is";
cout << getvolume(x,y,z) << endl;
cout << "some box data is";
cout << getvolume(x, y) << endl;
cout << "some box data is";
cout << getvolume(x) << endl;
return 0;
}
int getvolume(int length, int width, int height) {
cout << setw(5) << length << setw(5) << width << setw(5) << height<<'\t';
return length*width*height;
}
运行结果
3.4 函数重载(一种静态多态)
不同的功能,同样的函数名,编译时自动确定使用哪一具体功能
使用方法:定义同名函数,但是形参的个数或类型必须不同。正常调用即可
3.5 c++系统函数
http://www.cppreference.com