C++学习 第七章

这篇博客详细介绍了C++中的函数,包括函数的定义、无返回值与有返回值的函数、返回值传递方式、函数原型、参数传递(按值传递)以及函数与数组的交互。特别强调了数组作为参数时,实际上传递的是数组的地址,并讨论了使用const保护数组和二维数组、C风格字符串以及结构在函数中的应用。此外,还提到了递归、函数指针及其数组的使用,以及typedef在简化函数指针定义中的作用。
摘要由CSDN通过智能技术生成

1.函数的三个要求

  • 提供函数定义
  • 提供函数原型
  • 调用函数
//一个简单的函数使用

//第一步 声明函数原型
void simple();
int main()
{
   
	using namespace std;
	//第三步 使用函数
	simple();
	return 0;
}
//第二步 定义函数
void simple()
{
   
	using namespace std;
	cout << "Shi Yuqi is so cool!";
}

2.定义函数

  • 无返回值的函数
    没有返回值的函数被成为 void 函数,它相当于是一个过程,或者子程序,一般用于执行一系列的操作,其通用格式如下:
void functionName(parameterList)
{
   
	statement(s);
}

//一个小栗子
void apple(int n)
{
   
	using namespace std;
	for(int i = 0; i < n; i++)
	{
   
		cout << "apple" << endl;
	}
}

参数列表意味着调用函数apple的时候 需要给参数进行赋值。
例如这个int类型的参数,在调用apple的时候,就需要传送一个int型的参数给他。

  • 有返回值的参数
    有返回值的参数会生成一个值,并将它返回个调用函数,其通用格式如下:
typeName functionName(parameterList)
{
   
	statements;
	return value;
}

注意:由返回值的函数必须要有返回语句,返回的值也可以是变量,可以是常量,甚至可以是表达式,但是返回的值一定要与函数头声明的返回值类型匹配。
注意:C++中返回值不能为数组。但是数组可以作为结构和对象的组成部分进行返回。

3.返回值是如何传递的
通常,函数会将返回值复制到指定的内存单元或指定的CPU寄存器中来将其返回,随后调用程序来查看该内存单元。返回函数和调用函数必须就该内存单元中存储的数据类型达成一致。函数原型负责告知调用程序返回值类型,函数头告知被调用函数返回什么数据类型。

4.函数原型
原型描述了函数到编译器的接口,函数原型将函数的返回值类型,参数类型和数量都告诉编译器。函数原型是一条语句,以分号结尾,其中包含函数返回值类型,函数参数的个数个类型。
注意:函数原型不需要提供参数的名称,只需要提供参数的类型即可。

double score(int);
//函数原型可以包含变量名 也可以不包含变量名

原型的优点

  • 编译器可以正确处理函数返回值
  • 编译器可以检查参数数目是否正确
  • 编译器可以检查参数类型是否正确,如果不正确,可以试图将它变成正确的

5.函数参数和按值传递
C++通常按值传递参数,也就是将数值传递给函数,而后者将其赋给一个新的变量。

//举个小栗子
int size = 5;
apple(size);
//apple函数的函数头如下
void apple(int x)
/*
	在被调用的时候,该函数创建了一个新的变量x,
用于存放从调用函数传递来的数值5,这里函数使用
的是size的副本,而不是原来的数据。
	用于接受传递来的函数值的变量成为形参
	传递给函数的值称为实参
	C++中使用参数[argument]来表示实参
	C++中使用参量[parameter]来表示形参
*/

注意:函数中声明的变量是函数私有的,也就是说,函数被调用的时候,计算机会给变量分配内存,函数调用结束后,计算机就会释放这部分内存。这种变量成为局部变量,他们被限制在函数内使用,也被成为自动变量。因为他们是被计算机自动分配内存和销毁的。(还记得之前说的三种类型吗 自动存储 外部存储 动态存储)
6.一个函数小程序

// 计算扑克牌中抽到六个选中的概率
#include<iostream>
long double probability(unsigned numbers,unsigned picks);
using namespace std;
int main()
{
   
	unsigned int number,pick;
	while((cin >> number >> pick ) && pick <= number)
	{
   
		cout << "You have a chance in "
		cout << probability(number,pick);
		cout << " of winning.\n";
		cout << "Next two numbers (q to quit):";
	}
	return 0;
}
	long double probability(unsigned numbers,unsigned picks)
	{
   
		long double result = 1.0;
		unsigned n;
		unsigned p;
		for(n = numbers,p = picks; p > 0; n--,p--)
			result = result * n / p;
		return result;
	}

7.函数和数组
现在我们如果思考去使用一个函数解决数组元素累加求和的问题,那么我们知道函数需要做的是计算总数,然后返回总数值,那么函数需要知道对哪个数组进行累计,同时还需要知道要累计多少量,也就是数组的长度,这两个量应该成为函数的参数。也就是如下:

//函数头应该如此声明
int appleNum (int arr[],int n)

但是需要注意的是,这里的方括号并不是指出arr是一个数组,而是一个指针!
这里可能就有小朋友问了,指针的声明方法不是这样的鸭,不是应该是如下:

int appleNum (int* num, int n)

实际上这两种方法均可实现目的,因为我们之前介绍过,数组名在C++中,绝大部分情况都可以视作数组元素的首地址,(目前我已知的是在使用sizeof()以及取地址运算符&进行计算的时候由不同)。而在函数原型或函数头中(注意只有这两个位置),int arr[] 和int* arr 表示的含义是相同的,都是传递指针,数组表示法[],是为了提醒阅读程序的人员,这不仅是一个指向int的指针,而且是指向数组第一个int元素的指针。
一般来说,当指针指向单个元素的时候,使用int* arr
当指针指向的是数组的时候,使用数组表示法 int arr[]
至于为什么这两个表示方法都可以使用方括号访问数组元素,这个就像我们之前介绍的一样,无论是指针,还是数组都可以通过方括号访问元素。这也是动态数组的实现方法。

//复习
//创建动态数组
int* ps = new int[55];
//删除动态数组
delete []ps;

传递数组实际上是传递指针意味着,调用函数传递给被调用函数的内容是数组的地址,包含元素的类型,元素的个数。有了这些信息之后,函数就可以使用传递来的数组了。这乍一看和之前讲过的C++参数按值传递由一定的差异,实际上这并不违反按值传递,只不过传递的值变成了地址的值,传递的仍然属于一个值,这个值依然被赋值给了一个新的变量,只不过它代表的是地址,而不是数组内容。
注意:这里传递的内容仅代表一个地址,它不代表数组首地址,也不能使用数组首地址的特性,sizeof()得到的结果仅代表地址的长度。
注意:因为传递的量是地址,int arr[] 只是int* arr的另一种表示方式而已,不能使用数组的表示方法。
例如 int arr[size]这样是不建议的。

使用const保护数组
在某些情况下,我们只是想要使用数组而已,并不希望在函数中对数组的值进行改变,这时候我们就需要使用const关键字,将指针指向的内容声明为常量数据,防止程序在不经意的时候对原始数据进行修改。

void show_array (const double arr[] ,int n)
//将arr声明为const类型,这样数组中的数据就不会被修改

8.一个小例子

//一个使用数组函数的完整房地产分析程序
#include<iostream>
using namespace std;
int fill_array (double arr[] ,int n
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值