有些少侠一定要问了之前我们所学的怎么都是使用C/C++标准库的函数呢?我们可不可以自己自创一些函数(武功)呢?
那么带着疑问我们来学习一下怎么自创函数(武功)。
为什么要使用函数
1)“避免重复制造轮子”,提高开发效率
2)便于维护
函数的定义
函数的设计方法:
1)先确定函数的功能
2)确定函数的参数,是否需要参数,参数的个数,参数的类型
3)确定函数的返回值,是否需要返回值,返回值的类型
4)确定函数名,函数名, 一定要顾名思义.
5)函数名的命名方法, 和变量名相同
6) 函数的实现
#include <iostream>
//定义一个名叫sum的函数
int sum(int n) {
int s = 0;
for(int i=1; i<=n; i++) {
s += i; // s = s + i;
}
return s;
}
int main(void) {
// 1+2+3+...+50 = ?
std::cout << sum(10) << std::endl;
// 1+2+3+...+100 = ?
std::cout << sum(100) <<std::endl;
system("pause");
return 0;
}
函数的调用和声明
实参和形参:
函数调用时, 实参的值, 传递给形参.
即, 形参被赋值为实参.
函数声明\函数定义\函数调用的顺序
函数参数的传递方式
调用函数时,形参被赋值为对应的实参,
实参本身不会受到函数的影响!
使用数组作为函数参数
#include <iostream>
#include <Windows.h>
using namespace std;
void scorePrint(int score[], int n) {
for (int i=0; i<n; i++) {
cout << "第" << i+1 << "门成绩 : " << score[i] << endl;
}
}
//每个成绩加5分
void scoreAdd(int score[], int n, int val) {
for (int i=0; i<n; i++) {
score[i] += val;
}
}
int main(void) {
int score[3] = {60, 70, 80};
scorePrint(score, 3);
scoreAdd(score, 3, 5);
scorePrint(score, 3);
system("pause");
return 0;
}
默认参数
注意: C语言不支持函数的默认参数!,C++才支持
//每个成绩加5分
// 默认参数, 只能出现在参数列表的最后, 即默认参数后面, 不能有普通参数
//默认参数在函数调用时可以省略不写,例如:scoreAdd2(score,n);
void scoreAdd2(int score[], int n, int val=5) {
for (int i=0; i<n; i++) {
score[i] += val;
}
}
同名不同命之函数的重载
C语言的每一个函数必须是不同函数名
C++可以使用同名函数[重载函数]实现功能类似的多个不同函数.
int add(int a, int b) {
cout << "调用add版本1" << endl;
return a +b;
}
float add(float a, float b) {
cout << "调用add版本2" << endl;
return a+b;
}
函数名重载:
函数名相同,
但是, 函数的参数(形参)绝不相同:
1)参数个数不同
2)或参数个数相同, 但是参数的类型不同
只有返回类型不同,不能构成函数重载
只有形参变量名不同, 不能构成函数重载.
注意: C语言不支持函数重载
函数的栈空间
要避免栈空间溢出。
当调用一个函数时,就会在栈空间,为这个函数,分配一块内存区域,
这块内存区域,专门给这个函数使用。
这块内存区域,就叫做“栈帧”。
#include <iostream>
#include <Windows.h>
void test(void) {
//运行时将因为栈帧空间溢出,而崩溃
char buff[2000000]; //大约2G内存,而栈一般只有2M大小
std::cout << (int)buff[sizeof(buff) - 1] <<std::endl;
}
int main(void) {
test();
system("pause");
return 0;
}
极速调用之内联函数
函数的作用:
避免重复制造轮子。
(避免重复多次写相同的代码)
函数的缺点:
每调用一次函数,就会为这个函数分配一个“栈”,
在计算机底层做很多准备工作(保护原来的执行环境,切换到新的执行环境)
有一定的“时间开销”
解决方案:
使用内联函数
内联函数:
当编译器在编译时, 如果遇到内联函数,
就会直接将整个函数体的代码插入”调用处”,
就相当于内联函数的函数体, 在调用处被重写了一次。
以避免函数调用的开销, 获得更快的时间。
内联函数的缺点:
使调用内联函数的程序,变得“臃肿”,消耗调用函数的“栈”空间。
内联函数的用法:
inline int add(int a, int b)
{
return a + b;
}
内联函数的使用场合:
1)内联函数中的代码应该只是很简单、执行很快的几条语句。
2)这个函数的使用频度非常高,比如在一个循环中被千万次地使用。
递归函数
定义:在函数的内部,直接或者间接的调用自己。
要点:
再定义递归函数时,一定要确定一个“结束条件”!!!
使用场合:
处理一些特别复杂的问题,难以直接解决。
但是,可以有办法把这个问题变得更简单(转换成一个更简单的问题)。
/*
斐波那契数列
1,1, 2, 3, 5, 8, 13, 21, ....
计算第n个数是多少?
f(n)
当n >2时,f(n) = f(n-1) + f(n-2)
当n=1或n=2时, f(n)就是1
f(8) = f(7) + f(6)
*/
int fib(int n) {
int s;
if (n == 1|| n == 2) {
return 1;
}
s = fib(n-1) + fib(n-2);
return s;
}
递归函数的缺点:
性能很低!!!
实际开发中, 极少使用!