4124人加入学习
(13人评价)
C++编程系列 第二季函数和类

制作于2018.4.2

价格 免费
// 自写
#include <iostream>

using namespace std;

float HarmonicMean(float num1, float num2);

int main()
{
	float num1;
	float num2;
	do
	{
		cout << "请输入第一个数字:";
		cin >> num1;
		cout << "请输入第二个数字:";
		cin >> num2;
		if (num1 == 0 || num2 == 0)
		{
			break;
		}
		cout << num1 << "和" << num2 << "调和平均数是:" << HarmonicMean(num1, num2) << endl;
	} while (num1 != 0 || num2 != 0);

	return 0;
}

float HarmonicMean(float num1, float num2)
{
	return (2 * num1*num2) / (num1+num2);
}

Teacher:

#include <iostream>

using namespace std;

float harmonicMean(float a, float b);

int main()
{
	float num1, num2;
	cout << "请输入两个数的值:" << endl;
	while (cin >> num1 >> num2 && num1 != 0 && num2 != 0)
	{
		cout << num1 << "和" << num2 << "的调和平均数为:";
		cout << harmonicMean(num1, num2) << endl;
		cout << "请输入两个数的值:" << endl;
	}
	return 0;
}

float harmonicMean(float a, float b)
{
	return 2 * a * b / (a + b);
}

 

[展开全文]

 

递归函数

直接或间接调用自己的函数称为递归函数

递归函数的要求:递归函数必须定义一个终止条件,否则,函数将永远递归下去。

#include <iostream>

using namespace std;

long fact(int i);

int main()
{
	int num;
	cout << "请输入一个10以内的正整数:" << endl;
	cin >> num;
	long res = fact(num);
	cout << num << "的阶乘为:" << res << endl;
	return 0;
}

long fact(int i)
{
	long temp;
	if (i == 0)
	{
		temp = 1;
	}
	else
	{
		temp = i * fact(i - 1);
	}
	return temp;
}

 

习题2

完成程序:求两个数的调和平均数

要求:

1.不断要求用户输入2个数,直到其中一个数的值为0。

2.对于每两个数,程序将使用一个函数来计算它们的调和平均数。

3.函数将计算结果返回给主函数,在主函数中输出输入的数字和它们的调和平均数。

调和平均数是指倒数平均值的倒数。

 

 

[展开全文]

返回类型

无返回值函数:没有返回值的return语句只能用在返回类型是void的函数中。

有返回值函数;return语句的第二种形式提供了函数的结果。只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值。

 

 

返回类型

返回一个值的方式和初始化一个变量或形参的方式完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果

 

 

返回类型

返回引用类型:返回引用类型,可以在内存中不产生被返回值的副本,返回的是对象本身

但需要注意:不要返回局部对象的引用的引用或指针。函数完成后,它所占用的存储空间也随之被释放掉。为避免这种问题,我们可以返回一个作为参数传递给函数的引用。

 

 

#include <iostream>
#include <string>

using namespace std;

void swap(int &a, int &b);
int max(int a, int b);
int &sum(int a, int b, int &res);

int main()
{
	int num1 = 15;
	int num2 = 20;
	swap(num1, num2);
	cout << "num1: " << num1 << endl;
	cout << "num2: " << num2 << endl;
	int res = max(num1, num2);
	cout << "最大值为:" << res << endl;

	res = sum(num1, num2, res);
	cout << "两个数的和为:" << res << endl;
	
	sum(num1, num2, res)++;
	cout << res << endl;

	return 0;
}

//没有返回值的函数,可以使用return;
void swap(int &a, int &b)
{
	if (a >= b)
	{
		return;
	}
	else
	{
		int temp = a;
		a = b;
		b = temp;
		return;
	}
}

//有返回值的函数,每个return语句都必须带有结果。
int max(int a, int b)
{
	if (a > b)
	{
		return a;
	}
	else
	{
		return b;
	}
}

//返回引用类型
int &sum(int a, int b, int &res)
{
	res = a + b;
	return res;
}

[展开全文]

默认实参:某些函数有这样一种形参,在函数的很多次调用中他们都被赋予一个相同的值,我们把这个反复出现的值称为函数的默认实参。

调用含有默认实参的函数时,可以包含该实参,也可以省略该实参。

对于有多个形参的函数,必须从右向左添加默认值。

 

#include <iostream>
#include <string>

using namespace std;

void compare(int num1, int num2 = 100);
void greet(string name = "User");

int main()
{
	int a = 59;
	int b = 120;
	compare(a);
	compare(b);
	compare(a, b);
	greet();
	greet("Jane");
	return 0;
}

void compare(int num1, int num2)
{
	if (num1 > num2)
	{
		cout << num1 << "大于" << num2 << endl;
	}
	else if (num1 < num2)
	{
		cout << num1 << "小于" << num2 << endl;
	}
	else
	{
		cout << num1 << "等于" << num2 << endl;
	}
}

void greet(string name)
{
	cout << name << ", hello!" << endl;
}

[展开全文]

const形参和实参

总结:

1.int cube(int i); 实参可以为int类型,也可以为const int类型。在函数体中可以修改i的值,函数不会修改实参的值。

2.int cube(const int i); 实参可以为int类型,也可以为const int类型。在函数体中不可以修改i的值,函数不会修改实参的值。

总结:

3.int pCube(int* pi); 实参为int*类型的指针,不能为const int*类型。可以通过修改*pi的值修改实参指向的对象的值,修改pi对实参没有影响。

4.int pCube(const int *pi); 实参可以为const int*类型,也可以为int*类型。不可以通过修改*pi的值修改实参指向的对象的值,修改pi对实参没有影响。

5.int pCube(int * const pi); 实参为int*类型,不能为const int*类型。可以通过修改*pi的值修改实参指向的对象的值,不可以给pi赋值。

总结:

6.void reset(int &r); 实参为int类型,不可以为const int类型。可以通过修改r的值,从而修改实参的值。

7.void print(const int &r); 实参可以为int类型,也可以为const int类型,不可以修改r的值

 

 

#include <iostream>

using namespace std;

int cube1(int i);
int cube2(const int i);

int pCube1(int *pi);
int pCube2(const int *pi);
int pCube3(int* const pi);

int rCube1(int &r);
int rCube2(const int &r);

int main()
{
	//num1 为 int 类型的变量,可以修改它的值
	//num2 为 int 类型的常量,不可以修改它的值
	int num1 = 10;
	const int num2 = 10;
	num1 = 20;
	//num2 = 10;//出错

	//普通指针,可以修改p1的值,也可以修改*p1来修改num1的值。
	//所以只能用int类型的数据来初始化,不能用const int类型,不能修改常量的值。
	int *p1 = &num1;
	//int *p2 = &num2;//出错
	
	//底层const,可以修改指针(p3,p4),但是不可以修改*p3,*p4,去修改num1,num2的值。
	//可以使用int类型或const int 类型的数据来初始化
	const int *p3 = &num1;
	const int *p4 = &num2;

	//顶层const,不可以修改指针(p5,p6),但是可以通过*p5去修改num1的值。
	//所以只能使用int类型的数据来初始化,不能const int类型
	int * const p5 = &num1;
	//int * const p6 = &num2; //错误

	//int类型的引用,可以通过r1去修改num1的值,所以只能使用int类型去初始化,不能使用const int类型
	int &r1 = num1;
	//int &r2 = num2; //出错

	//const int 类型的引用,不能修改r3,r4的值
	//可以使用int类型的数据来初始化,也可以使用const int类型
	const int &r3 = num1;
	const int &r4 = num2;

	//实参为int类型或const int类型
	cout << cube1(num1)<<" "<< cube1(num2) << endl;
	cout << cube2(num1) << " " << cube2(num2) << endl;

	//实参只能为int类型
	cout << pCube1(&num1) << endl;
	//cout << pCube1(&num2) << endl; //出错

	//所以实参可以是int类型,const int类型
	cout << pCube2(&num1) << " " << pCube2(&num2) << endl;
	
	//实参类型只能是int类型
	cout << pCube3(&num1) << endl;
	//cout << pCube3(&num2) << endl; //出错

	//实参只能是int类型
	cout << rCube1(num1) << endl;
	//cout << rCube1(num2) << endl; //出错

	//实参类型可以是int类型,也可以是const int类型
	cout << rCube2(num1) << " " << rCube2(num2) << endl;

	return 0;
}

//可以修改形参i
int cube1(int i)
{
	//i = 0;
	return i * i * i;
}

//不可以修改形参i
int cube2(const int i)
{
	//i = 0; //出错
	return i * i * i;
}

int pCube1(int *pi)
{
	//*pi = 0;
	return *pi * (*pi) * (*pi);
}

//可以修改pi,但是不可以修改*pi,所以实参可以是int类型,const int类型
int pCube2(const int *pi)
{
	//*pi=0; //出错
	return *pi * (*pi) * (*pi);
}

//不可以修改pi,但是可以修改*pi,所以实参类型只能是int类型
int pCube3(int* const pi)
{
	//*pi=0;
	return *pi * (*pi) * (*pi);
}

//可以修改r,实参只能是int类型
int rCube1(int &r)
{
	//r = r * r * r;
	return r * r * r;
}

//不可以修改r,实参类型可以是int类型,也可以是const int类型
int rCube2(const int &r)
{
	//r = r * r * r; //出错
	return r * r * r;
}

[展开全文]

const形参和实参

用实参初始化形参时,会忽略掉顶层const,也就是说,当形参有顶层const时,传给它常量对象或者非常量对象也是可以的。

 

#include <iostream>

using namespace std;

int cube1(int i);
int cube2(const int i);
int pCube1(int *pi);
int pCube2(const int *pi);
int pCube3(int* const pi);

int main()
{
	//num1 为 int 类型的变量,可以修改它的值
	//num2 为 int 类型的常量,不可以修改它的值
	int num1 = 10;
	const int num2 = 10;
	num1 = 20;
	//num2 = 10;//出错

	//普通指针,可以修改p1的值,也可以修改*p1来修改num1的值。
	//所以只能用int类型的数据来初始化,不能用const int类型,不能修改常量的值。
	int *p1 = &num1;
	//int *p2 = &num2;//出错
	
	//底层const,可以修改指针(p3,p4),但是不可以修改*p3,*p4,去修改num1,num2的值。
	//可以使用int类型或const int 类型的数据来初始化
	const int *p3 = &num1;
	const int *p4 = &num2;

	//顶层const,不可以修改指针(p5,p6),但是可以通过*p5去修改num1的值。
	//所以只能使用int类型的数据来初始化,不能const int类型
	int * const p5 = &num1;
	//int * const p6 = &num2; //错误

	//int类型的引用,可以通过r1去修改num1的值,所以只能使用int类型去初始化,不能使用const int类型
	int &r1 = num1;
	//int &r2 = num2; //出错

	//const int 类型的引用,不能修改r3,r4的值
	//可以使用int类型的数据来初始化,也可以使用const int类型
	const int &r3 = num1;
	const int &r4 = num2;

	//实参为int类型或const int类型
	cout << cube1(num1)<<" "<< cube1(num2) << endl;
	cout << cube2(num1) << " " << cube2(num2) << endl;

	//实参只能为int类型
	cout << pCube1(&num1) << endl;
	//cout << pCube1(&num2) << endl; //出错

	//所以实参可以是int类型,const int类型
	cout << pCube2(&num1) << " " << pCube2(&num2) << endl;
	
	//实参类型只能是int类型
	cout << pCube3(&num1) << endl;
	//cout << pCube3(&num2) << endl; //出错

	return 0;
}

//可以修改形参i
int cube1(int i)
{
	//i = 0;
	return i * i * i;
}

//不可以修改形参i
int cube2(const int i)
{
	//i = 0; //出错
	return i * i * i;
}

int pCube1(int *pi)
{
	//*pi = 0;
	return *pi * (*pi) * (*pi);
}

//可以修改pi,但是不可以修改*pi,所以实参可以是int类型,const int类型
int pCube2(const int *pi)
{
	//*pi=0; //出错
	return *pi * (*pi) * (*pi);
}

//不可以修改pi,但是可以修改*pi,所以实参类型只能是int类型
int pCube3(int* const pi)
{
	//*pi=0;
	return *pi * (*pi) * (*pi);
}

[展开全文]

const形参和实参

顶层const:表示任意的对象是常量。

底层const:与指针和引用等复合类型有关。

对指针而言,顶层const表示指针本事就是个常量,而底层const表示指针所指的对象是一个常量。

int i = 22;

const int ci = 20; //顶层const,不能修改 ci 的值

const int *p1 = &ci; //底层const,允许修改 p1 的值,但是不能通过 *p1 修改 ci 的值。

int *const p2 = &i; //顶层const,不能修改 p2 的值,但是允许通过 *p2 修改 i 的值。

 

 

#include <iostream>

using namespace std;

int main()
{
	//num1 为 int 类型的变量,可以修改它的值
	//num2 为 int 类型的常量,不可以修改它的值
	int num1 = 10;
	const int num2 = 10;
	num1 = 20;
	//num2 = 10;//出错

	//普通指针,可以修改p1的值,也可以修改*p1来修改num1的值。
	//所以只能用int类型的数据来初始化,不能用const int类型,不能修改常量的值。
	int *p1 = &num1;
	//int *p2 = &num2;//出错
	
	//底层const,可以修改指针(p3,p4),但是不可以修改*p3,*p4,去修改num1,num2的值。
	//可以使用int类型或const int 类型的数据来初始化
	const int *p3 = &num1;
	const int *p4 = &num2;

	//顶层const,不可以修改指针(p5,p6),但是可以通过*p5去修改num1的值。
	//所以只能使用int类型的数据来初始化,不能const int类型
	int * const p5 = &num1;
	//int * const p6 = &num2; //错误

	//int类型的引用,可以通过r1去修改num1的值,所以只能使用int类型去初始化,不能使用const int类型
	int &r1 = num1;
	//int &r2 = num2; //出错

	//const int 类型的引用,不能修改r3,r4的值
	//可以使用int类型的数据来初始化,也可以使用const int类型
	const int &r3 = num1;
	const int &r4 = num2;
	return 0;
}

111

[展开全文]

传引用参数

引用:引用是已定义的变量的别名。对于引用的操作实际上是作用在引用所引的对象上的。它们共用相同的内存空间。

传引用参数:通过将引用变量用作参数,函数将使用原始数据,而不是其副本。

int n = 0;

int &r = n;(&不再是地址运算符,r是n的引用)

 

 

传引用参数

用途:

1.当某种类型不支持拷贝操作,或是需要拷贝的对象太大时,我们可以通过引用形参来访问对象。

2.当函数需要同时返回多个值时,可以使用引用形参来处理。

 

 

#include <iostream>
#include <string>

using namespace std;

void reset(int &i);
int min(int num1, int num2, int num3, int &max);

int main()
{
	int num = 10;
	reset(num);
	cout << num << endl;

	int maxNum;
	int minNum;
	minNum = min(20, 15, 23, maxNum);
	cout << "最大值为:" << maxNum << endl;
	cout << "最小值为:" << minNum << endl;
	return 0;
}

//将引用变量作为参数,函数使用的是圆石数据,而不是副本。
//对形参的修改其实就是对实参的修改。
void reset(int &i)
{
	i = i * 2;
}

//函数的返回值为int类型,返回的是3个数中的最小值
//定义了一个引用类型的参数,通过这个参数修改maxNum的值,获得最大值
int min(int num1, int num2, int num3,int &max)
{
	int temp1, temp2;
	temp1 = num1 < num2 ? num1 : num2;
	temp1 = temp1 < num3 ? temp1 : num3;

	temp2 = num1 > num2 ? num1 : num2;
	temp2 = temp2 > num3 ? temp2 : num3;

	max = temp2;
	return temp1;
}

 

[展开全文]

参数传递

形参的类型决定了形参和实参的交互方式。

如果形参是引用类型,它将绑定到对应的实参上(传引用参数);否则,将实参的值拷贝后赋给形参(传值参数)。

 

 

传值参数

传值参数有2种方式:

1.将实参的实际值复制给函数的形参。在这种情况下,修改函数内的形参对实参没有影响。

2.将参数的地址复制给形参(指针)。因为指针使我们可以见间接地访问它所指的对象,所以通过指针可以修改它所指对象的值。

 

 

#include "pch.h"
#include <iostream>
#include <string>

using namespace std;

int reset(int i);
void reset1(int* pi);

int main()
{
	int num = 10;
	cout << "reset: " << reset(num) << endl; // 20
	cout << "num: " << num << endl; // 10
	cout << "num的地址:" << &num << endl; // num的地址:001FFD04
	reset1(&num);
	cout << "reset1: " << num << endl; // 20
	cout << "num的地址:" << &num << endl; // num的地址:001FFD04
	return 0;
}
//传递实参的实际值,将实参的值拷贝给形参,函数体种修改的是形参的值,对实参不产生影响
int reset(int i)
{
	i *= 2;
	return i;
}

//传递实参的地址,修改*pi的值,就是修改实参指向的对象的值,修改pi的值,是修改的形参存储的地址,不影响实参的地址。
void reset1(int* pi)
{
	*pi *= 2;
	pi = 0;
}

 

[展开全文]

局部对象

在C++中,名字(变量、函数、类型)有作用域(静态),对象有生命周期(动态)。

名字的作用域是程序文本的一部分,名字在其中可见。对象的生命周期是程序执行过程中该对象存在的一段时间。

形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见。

在所有函数体外定义的对象存在于程序的整个执行过程中。局部变量的生命周期则依赖于定义的方式。

 

 

自动对象

我们把只存在于块执行期间的对象称为自动对象。

普通的局部变量对应的对象,是自动对象,在每次调用函数时创建和销毁。

形参也是一种自动对象。函数开始时为形参申请存储空间,因为形参定义在函数体作用域内,所以一旦函数终止,形参也就被销毁。

 

 

局部静态对象

局部静态对象在程序的执行路径第一次经过对象定义语句时初始化,并且知道程序终止才被销毁,所以局部静态对象不是自动对象。

可以用static关键字来修饰局部变量,从而获得局部静态对象。

static int count = 0;

 

 

#include <iostream>
#include <string>

using namespace std;

int min(int num1, int num2, int num3);
//定义在所有函数体外的对象,为全局对象。
int a = 3;

int main()
{
	//res的作用域为main()函数
	int res = min(4, 8, 2);
	//cout << res << endl;

	res = min(3, 3, 6);
	res = min(2, 3, 5);
	return 0;
}

//num1/num2/num3为函数min()的形参
int min(int num1, int num2, int num3)
{
	//res的作用域为min()函数
	int res;
	//局部静态变量,直到程序终止才被销毁
	static int count = 0;
	count += 1;
	cout << count << endl;
	res = num1 < num2 ? num1 : num2;
	res = res < num3 ? res : num3;
	return res;
}

 

[展开全文]

函数声明(函数原型)

函数原型描述了函数到编译器的接口,它将函数的信息告诉了编译器。

函数的名字也必须在使用之前声明。

函数的声明和函数的定义非常类似,唯一的区别是函数声明无需函数体,用一个分号替代即可。

returnType functionName(parameterList);

 

 

函数原型

函数原型可以确保:

1.编译器正确处理函数返回值。

2.编译器检查使用的参数数目是否正确。

3.编译器检查使用的参数类型是否正确。

 

 

函数调用

函数的调用完成两项工作:

1.用实参初始化函数对用的形参。

2.将控制权转移给被调函数。此时,主调函数的执行被暂时中断,被调函数开始执行。

return语句也能完成两项工作:

1.函数有返回值的话,则返回return语句中的值。

2.将控制权从被调函数转回主调函数。

 

 

形参和实参

形参:用于接受传递值的变量被称为形参。

实参:传递给函数的值被称为实参。

实参是形参的初始值,所以实参的类型须与对应的形参类型匹配。

 

#include <iostream>
#include <string>

using namespace std;
//函数声明
void greet();
int sum(int a, int b);

int main()
{
	int num1 = 10;
	int num2 = 5;
	//调用函数
	greet();
	//需要一个int类型的变量来接受返回值
	int result = sum(num1, num2);
	cout << result << endl;
	return 0;
}

//没有返回值,没有参数
//函数名greet
//函数体为输出Hello语句
void greet()
{
	cout << "Hello!" << endl;
}

//返回值为int类型
//参数为2个int类型的值a,b
//函数名为sum
//函数体为求得两个参数的和,并返回一个int类型的数值
int sum(int a, int b)
{
	int res = a + b;
	return res;
}

 

[展开全文]

 

函数的基本概念

函数是一个i命名了的代码块,我们通过调用函数执行相应的代码。

每个C++程序都至少有一个函数,即主函数main(),所有简单的程序都可以定义其他额外的函数。

想要使用函数,必须完成以下工作:

1.提供函数定义

2.提供函数原型

3.调用函数

 

 

函数定义

一个典型的函数定义包括:

1.返回类型(returnType)

2.函数名(functionName)

3.形参列表(parameterList)

4.函数体(functionBody)

returnType functionName(parameterList)

{

functionBody;

}

 

 

函数定义

返回类型:一个函数可以选择生成一个值并将它返回给调用函数,或者不返回值。返回值时,returnType为这个值的数据类型。不返回值时,returnType为关键字void。

参数列表:参数列表包括函数参数的类型、顺序、数量。一个函数可以有0个或多个参数。

函数主体:函数主体定义了函数执行的任务。

 

 

 

 

#include <iostream>
#include <string>

using namespace std;

int main()
{
	return 0;
}

//没有返回值,没有参数
//函数名greet
//函数体为输出Hello语句
void greet()
{
	cout << "Hello!" << endl;
}

//返回值为int类型
//参数为2个int类型的值a,b
//函数名为sum
//函数体为求得两个参数的和,并返回一个int类型的数值
int sum(int a, int b)
{
	int res = a + b;
	return res;
}

 

[展开全文]
//自写
cout << "请输入你喜爱的游戏,并给它们评分,分数为0-10分之间的小数" << endl;
	string gameName[5]{ "","","","","" };
	float gameScore[5]{ 0.0f,0.0f,0.0f,0.0f,0.0f };
	for (int i = 0; i < 5; i++)
	{
		cout << "请输入游戏名称:";
		cin >> gameName[i];
		cout << "请输入游戏评分:";
		cin >> gameScore[i];
	}
	for (int i = 0; i < 5 - 1; i++)
	{
		for (int j = 0; j < 5 - i - 1; j++)
		{
			if (gameScore[j] < gameScore[j + 1])
			{
				float temp1 = gameScore[j];
				gameScore[j] = gameScore[j + 1];
				gameScore[j + 1] = temp1;

				string temp2 = gameName[j];
				gameName[j] = gameName[j + 1];
				gameName[j + 1] = temp2;
			}
		}
	}
	for (int i = 0; i < 5; i++)
	{
		cout << (i + 1) << " : " << gameName[i] << "(" << gameScore[i] << ")" << endl;
	}

老师写的:

#include "pch.h"
#include <iostream>
#include <string>
using namespace std;

struct Game
{
	string gameName;
	float gameScore;
};

int main()
{
	const int size = 5;
	Game games[size] = {};

	cout << "请输入5个你喜爱的游戏的名称,并给他们评分,(分数为0-10之间的小数)" << endl;
	for (int i = 0; i < size; i++)
	{
		cout << "请输入游戏名称:";
		cin >> games[i].gameName;
		cout << "请输入游戏评分:";
		cin >> games[i].gameScore;
	}

	for (int i = 0; i < size - 1; i++)
	{
		for (int j = i + 1; j < size; j++)
		{
			Game temp;
			if (games[i].gameScore < games[j].gameScore)
			{
				temp = games[i];
				games[i] = games[j];
				games[j] = temp;
			}
		}
	}

	for (int i = 0; i < size; i++)
	{
		cout << i + 1 << " : " << games[i].gameName << "(" << games[i].gameScore << ")" << endl;
	}
}

 

[展开全文]

int n=0

int &r=n(&不再是地址运算符,r是n)

[展开全文]

形参的类型决定了形参和实参的

[展开全文]

可以用static关键字来修饰局部变量,从而获取局部静态对象。

static int cout==0;

[展开全文]

函数的形参在执行完以后会回收,不对实参产生影响,如果直接作用于地址,可以修改改指针地址中的实参,但是地址不会变。

int reset(int i) {
    i *= 2;
    return i;
}

void reset1(int* pi) {
    *pi *= 2;
    pi = 0;
}

[展开全文]

授课教师

SIKI学院老师

课程特色

下载资料(1)
视频(43)