模块化编程--函数
《老九学堂C++课程》《C++ primer》学习笔记。《老九学堂C++课程》详情请到B站搜索《老九零基础学编程C++入门》
-------------简单的事情重复做,重复的事情用心做,用心的事情坚持做(老九君)---------------
1. 函数基本知识
函数分类:
- 内置函数(STL,Boost C++)
- 自定义函数(focus on)
C++ Standard Library(C 标准函数,输入/输出,数值,诊断,通用工具,国际化,语言支持,STL(迭代器,算法, 容器))
Boost C++:可移植,开源的代码库
函数三要素:返回值类型,函数名,参数列表
return_type functionName(parametersList){
//函数体
}
自定义函数的完整写法:函数原型+函数调用+函数定义
int sum(int, int); // 函数原型,描述函数到编译器的接口,提前告诉编译器一声。不需要写参数名,以分号结尾
int main(){
// 函数调用
int result = sum(5,3);
}
// 函数定义
int sum(int num1, int num2){
// 函数实现的代码
return num1 + num2
}
注意:
1.函数原型和函数定义的头部类似,函数原型以分号结尾
2.函数原型中的参数名称可以省略,只写参数类型
3. C++返回值类型不能是数组,但是可以是其他任何类型(可以将数组做为结构或者对象的组成部分返回)
dmeo: 计算长方体和圆柱体的体积
//1.定义两个函数,分别用来计算两种形状的体积
//2.在mian 函数中用户可以选择计算某个形状的体积
void calcCuboid(); // 计算长方体的体积
void calcCylinder(); // 计算圆柱体的体积
int main(){
int choice = -1;
while(choice){
cout << "1. 计算长方体体积" << endl;
cout << "2. 计算圆柱体的体积" << endl;
cout << "0. 退出" << endl;
cin >> choice;
switch(choice){
case 1:
calcCuboid();
break;
case 2:
calcCylinder();
break;
}
}
cout << "感谢使用本软件,觉得好用点个赞呗!" << endl;
return 0;
}
void calcCuboid(){
// 输出长宽高
double len, width, height;
cout << "请输入长宽高:" ;
cin >> len >> width >> height;
// 计算体积
double v = len * width * height;
cout << "长方体的体积为:" << v << endl;
}
void calcCylinder(){
double radius, height;
cout << "请输入半径和高:";
cin >> radius >> height;
// 计算体积, pow 的头文件 cmath
double pi = 4 * atan(1.0); // arctan(1.0) 为45度角的弧度表示,pi为其4倍数
// double v = 3.14 * pow(radius, 2) * height;
double v = pi * pow(radius, 2) * height;
cout << "圆柱体的体积为:" << v << endl;
}
2. 函数的参数
2.1 按值传递机制(小议按引用传递)
按值传递:给函数传递变量时,变量值不会直接传递给函数,而是先制作变量值的副本,原始变量被存在栈上,将这个副本传递给函数。
void change(int);
int main(){
int num = 9;
change(num);
cout << "num = " << num << endl;
return 0;
}
void change(int num){
num++;
}
num = 9
如果传递的是引用,那么原变量的值将会改变(引用,传递的是地址,改变的是地址中的值)
void change(int&);
int main(){
int num = 9;
change(num);
cout << "num = " << num << endl;
return 0;
}
void change(int &num){
// 传递了引用,地址
num++;
}
num = 10
2.2 使用数组做函数参数(用户头文件,const的防改)
1.数组作为函数参数时,只传递数组的首地址,并不传递整个数组空间
2.当数组名为实参时,数组首地址指针被传递到函数中
使用函数升级《小公主养成记》-- 函数放在自己写的头文件中(.h结尾),在.cpp文件中include
头文件princess.h编写:
// 使用函数升级《小公主养成记》中基本属性的输入和排序功能
// 基本属性: 体力, 智力, 魅力, 道德, 气质
#include <iostream>
using namespace std;
// 函数定义
// 给一个数组
void input(int [], int);
void show(int [], int);
//自行完成删除和修改数组元素
// 函数实现
void input(int values[], int len){
//int values[] 这么定义形参,传递数组的时候传递的是数组的指针
//传数组时只有指针,建议再传一个数组长度
if(len > 5){
cout << "数组长度只能是5以内,越界了" << endl;
return; // 退出返回值为void的函数
}
string valueNames[] = {"体力", "智力", "魅力", "道德", "气质"};
for(int i=0; i < len; i++){
cout << valueNames[i] << ":" ;
cin >> values[i];
}
}
void show(int values[], int len){
string valueNames[] = {"体力", "智力", "魅力", "道德", "气质"};
for(int i = 0; i < len; i++){
cout << valueNames[i] << ":" << values[i] << endl;
}
}
.cpp中导入自己写的头文件
#include <iostream>
#include "princess.h" // 自己写的头文件使用双引号就可以了
using namespace std;
int main(){
int values[5];
input(values, sizeof(values)/sizeof(int));
show(values,5);
return 0;
}
传递数组参数时,不希望改动数组中的元素,在定义可以使用const 关键字
void show(const int [], int);
int main(){
int valueArray[] = {90, 56, 67, 89, 100};
return 0;
}
void show(const int valueArray[], int len){
for(int i = 0; i < len; i++){
// cout << valueArray[i]++ << endl; ❌,编译不给过,告诉你只读
cout << valueArray[i]<< endl;
}
}
2.3 使用二维数组作为函数的参数
void show_2d(double (*)[5],int);
int main(){
double valueArray[3][5] ={
{45.5, 46.6, 47.7},
{12.2, 13.3, 14.4},
{15.5, 16.6, 17.7}};
show_2d(valueArray, 3);
return 0;
}
//void show_2d(double valueArray[][5], int len) 两种头部书写方式都可以
void show_2d(double (*valueArray)[5], int len){
for(int i = 0; i < len; i++){
for(int j = 0; j < 5; j++){
cout << *(*(valueArray +i) + j) << ",";
}
cout << endl;
}
}
2.4 使用函数指针作为函数的参数
2.4.1 函数指针的基本内容
函数的地址是其机器语言代码在内存中存放的首地址
好处:将函数当作参数来传递,可以在不同的时间使用不同的函数
注意点:现有函数,先声明函数指针,再用函数指针指向需要的函数
使用场景:在很多函数调用的情况下,使用函数指针简化函数调用。
使用函数指针来指向一个函数的地址,函数指针的声明
//函数原型
double sum(double, double);
//函数指针声明, 一个指向函数的指针 ✅
double (*ptrSum)(double, double);
//返回值是double * 的函数, 达不到声明函数指针的效果
double *ptrSum(double, double);
demo1:用户幂函数的实现与对应的指针
#include "funptr.h"
int main(){
// 声明函数指针
int (*ptrmypower)(int, int);
// 让指针指向函数
ptrmypower = my_power;
// 用函数指针调用函数
cout << ptrmypower(2, 3) << endl;
cout << (*ptrmypower)(2,3) << endl;
cout << my_power(2, 3) << endl;
return 0;
}
funptr.h 文件内容
int power(int, int);
int my_power(int num1, int num2){
int result = 1;
for(int i = 0; i < num2; i++){
result *= num1;
}
return result;
}
demo2:使用函数指针实现加减乘除运算
#include "mycalc.h"
int main(){
// 定义函数指针
double (*ptrCalc)(double, double);
double num1, num2;
char op;
cout << "请输入两个运算数字" << endl;
cin >> num1 >> num2;
cout << "请输入运算符" << endl;
cin >> op;
// seitch 语句只用来给函数指针赋值
switch(op){
case '+':
// 调用加法函数
ptrCalc = addtion;
break;
case '-':
// 调用减法函数
ptrCalc = subtraction;
break;
case '*':
// 调用乘法函数
ptrCalc = multiplication;
break;
case '\\':
// 调用除法函数
ptrCalc = division;
break;
}
print_result(ptrCalc, num1, num2);
return 0;
}
mycalc.h 中的内容
// 自定义计算器,使用函数指针
#include <iostream>
using namespace std;
/** 加法 */
double addtion(double, double);
/** 减法 */
double subtraction(double, double);
/** 乘法 */
double multiplication(double, double);
/** 除法 */
double division(double, double);
/** 打印结果*/
void print_result(double (*)(double, double), double, double); // 把后两个duuble 传递给前面的函数指针ptrCalc
void print_result(double (*ptrCalc)(double, double), double num1, double num2){
// 调用函数,打印结果
double result = ptrCalc(num1, num2);
cout << "运算结果" << result << endl;
}
double addtion(double num1, double num2){
return num1 + num2;
}
double subtraction(double num1, double num2){
return num1 - num2;
}
double multiplication(double num1, double num2){
return num1 * num2;
}
double division(double num1, double num2){
if(num2 == 0){
cout << "除数不能为0" << endl;
return 0;
}
else{
return num1 / num2;
}
}
2.4.2 函数指针数组的声明
–自行实践
double (*ptrCalc[])(double, double)
2.4.3 auto
函数指针的声明比较麻烦,C++ 11 中可以使用auto ptrFunc = addition; 实现函数类型的自动诊断(自动诊断需要确保变量的类型和赋值的类型一致),就可以不需要函数指针声明。
// double (*ptrCalc)(double, double);
auto ptrCalc = addtion; // 必须初始化,遇到具体计算需求时,在赋予新的函数地址(如后续需要求减法)
2.4.4 使用typedef 定义函数指针类型
typedef double (*ptrCalc)(double, double); // 定一个了一个函数指针类型
ptrCalc ptrCalc1;