模块化思想——C++函数的魅力(一)


或许有一天c++系列能全部更新完,但是这里才是我写c++笔记的起点,本人也是边学边写,理解方面肯定会有很多问题存在,会尽量慢慢琢磨修改,有问题的地方也希望大家批评指出。
参考书目《C++ primer plus》
《C++语言程序设计 郑莉》
《C++语言描述,数据结构与算法》

  • 综述:函数是模块划分的基本单位,在面向过程程序设计中,函数是某一过程的抽象,在面向对象程序设计中,函数是某一功能的抽象,函数编写好后只关心函数的功能而不关心函数的内容,有利于分工合作和开发效率

函数的定义和使用

  • 函数是一个子程序,是程序块,main函数是程序执行的开始点,函数之间可相互调用。
  • 可结合程序的机器级表示学习函数调用的底层知识

函数的定义

return_value fun_name(parameter){
	body
}

😈 形式参数表(parameter)
复制构造函数&析构函数
什么是表?不是形容人的,而是用逗号分开的序列

  • 形参是主调函数和被调函数的联系,
  • 命令行参数:main函数的形参,作为操作系统启动程序时初始化
  • 形参被称为傀儡,在没有调用时就是一个符号,只有调用后才能由主调函数将实际参数赋予形参
    😈 函数的返回值和返回值类型
    1 结束当前函数的执行
    2 函数的返回值由return语句给出
    3 也可以不带返回值,函数仅仅实现一种操作

函数的调用

函数名(实参表)
😈 函数的原型(函数声明)
返回值 函数名(形参表);
函数声明不会产生任何代码,只是将函数的有关信息告诉编译器
编译器根据函数原型对函数调用进行检查,判断是否符合要求。

  • 实参和形参相对应
  • 函数作为参数进行调用
    ⭐实例:将二进制转化为十进制
#include<iostream>
double power(double x, int n);
using namespace std;
int main() {
	cout << "Please enter an 8 bit binary number:";
	int dem = 0;
	for (int i = 7; i >=0; i--) {
		char bit;
		cin >> bit;
		if(bit=='1')
		dem +=  power(2, i);
	}
	cout << "Decimal value is " << dem << endl;
	return 0;
}
double power(double x, int n) {
	double result = 1;
	for (int i = 1; i <= n; i++) {
		result *= x;
	}
	return result;
}

在这里插入图片描述

针对本程序的一些解释

  • 为什么选择输入char类型,插入类型一次只读入一个字符,如果我们按int类型输入相应位,就需要用换行或空格的方式告诉程序此次输入结束,当我们使用char类型,输入一串位串后,输入流里就存在这些数字,一次只读取一个数字,即使输入很多,也会按从左往右的顺序按位读取(与输入流有关的知识会专门写博客讲解)
  • 注意到在结果相加之前有个判断语句if(bit=='1'),如果我们直接使用dem+=bit*power(2,i);会出现错误,这里bit会按照int类型解释,就会将其ASCII码作为bit的值。
    ⭐实例:将一个数翻转
bool judge(int x) {
	int m = 0;
	int n = x;
	while (x > 0) {
		m = m * 10 + x % 10;
		x /= 10;
	}
	return m == n;
}

⭐实例:随机数:投骰子的随机游戏

  • 随机函数:int rand(void)产生伪随机数,按照一个既定的序列产生数字,rand函数需要一个称为种子的初始值,不同的种子随机数序列不同,不设置种子其默认值为1,调用函数void srand (unsigned int seed)为其设置种子。
  • 产生随机数需要头文件#include<cstdlib>
    程序设计的过程
    审题分析→设计算法→写程序

嵌套调用

递归调用

  • 将问题进行分简,出现的新问题是原有问题简化的子集
  • 只有有限的阶乘才有意义
  • 递归的过程
    1 递推:将问题分解为子问题,从未知向已知推进,达到已知的条件
    2 回归:根据递归过程逐一求值回归
    ⭐实例:用递归法计算从n个人中选择k个人组成一个委员会的不同组合数
    从n个人里面选k个人=从n-1个人里面选k-1个人+从n-1个人里面选k个人
    经典实例:汉诺塔问题

函数的参数传递

  • 形参:函数未被调用时,形参不具有实际空间和实际的值,函数调用时将实参和形参结合
    😈 形实结合(可结合计算机系统系列过程部分讲解)
    ⭐值传递
    当函数调用时,为形参分配内存空间,并用实参初始化形参,单向传递。形参的值变化对实参不起作用
    ⭐引用传递
    引用是一种特殊类型的变量,被认为是另一个变量的别名

int i,j;
int &ri=i;

  • 声明引用时,必须对其进行初始化,使它指向一个已存在的对象
  • 一旦引用被初始化,就不能指向其他对象
    引用一旦诞生,就确定了一个对象,且一生只为一个对象
    ⭐实例:交换数值
#include<iostream>
using namespace std;
void swap(int &x, int & y);
int main() {
	int x = 10, y = 5;
	int &rx = x;
	int &ry = y;//也可以不定义引用,直接在函数原型和定义中说明引用类型,可直接转换为引用
	swap(rx, ry);
	cout << x << " " << y;
	return 0;
}
void swap(int &x, int &y) { //参数为引用类型
	int temp;
	temp = x;
	x = y;
	y = temp;
	return;
}

内联函数

函数调用可提高开发效率,分块解决问题,但是函数调用降低程序执行效率(尤其是递归函数),对于一些内容简单的函数,调用函数的成本比使用函数内容的成本高得多

  • 内联函数:内联函数不是执行时调用,而是在编译时直接嵌入对应的调用处,节省了参数传递,控制转移等开销(但是对于现在的编译器,有了优化系统,没有设置inline的函数也可能被编译为内联,过于冗杂的函数可能被编译器优化为一般函数)
  • 通俗来讲,与其每次为了见小鬼去全国各地看他的演唱会,不如直接把他拐到家里,省了路费和精力消耗。
  • inline return_type fun_name(parameter){body}
  • 以空间换时间短小精干
  • 引用不是对象,引用并没有在程序中占据内存空间,故没有地址的说法.

含可变参数的函数

  • 可变长度的形参表
  • 当实参类型都相同时,可以使用initializer_list
    initializer_list<string>ls;

带默认参数值的函数

int add(int x=10,int y=6){
	return x+y;
}
int main(){
	int z=add(5);
	int p=add(2,6);
	return;
}
  • 有实参则用实参,无实参则用默认值
  • 有默认参数的形参在后边,赋值所用实参先赋给列表前面
    在这里插入图片描述
  • 如果有函数原型,在函数原型中提供了默认值,在函数定义中不能有默认值,如果没有函数原型,在定义中确定默认值

先写到这里吧,随后根据primer plus上的内容再进行补充

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值