目录
5.1 函数声明与定义
函数声明可以写多次,但是定义只能有一次
函数语句声明:数据类型 函数名(参数列表);//参数列表可只写参数的数据类型
函数定义:数据类型 函数名(参数列表){函数体}
例1:函数语句声明
#include<iostream>
using namespace std;
//函数的声明
//比较函数,实现两个整型数字进行比较,返回较大 的值
//函数声明可以写多次,但是定义只能有一次
//提前告诉编译器函数的存在,可以利用函数的声明
int max(int a, int b);
int main() {
int a = 10, b = 20;
cout << max(a, b) << endl;
return 0;
}
//函数定义
int max(int a, int b) {
return a > b ? a : b;
}
例2:先定义函数
#include<iostream>
using namespace std;
//函数的定义
//语法:
//返回值类型 函数名(参数列表) {函数体语句 return 表达式}
//加法函数,实现两个整型相加,并且将相加的结果进行返回
//函数定义时,num1和num2并没有真实数据,他只是一个形式上的参数,简称形参
int add(int num1, int num2) {
return num1 + num2;
}
int main() {
int a = 10, b = 20;
//a和b为 实际参数,简称实参
//当调用函数时候,实参会传递给形参
int sum = add(a, b);
cout << "sum=" << sum << endl;
return 0;
}
5.2 函数参数及返回值
5.2.1:形参与实参
1.定义
形参:带参函数中的参数在函数声明和定义时被称为“形式参数”;
实参:在函数调用时被赋予具体值,具体的值被称为“实际参数”
2.形参与实参的区别:
(1)在定义函数中指定的形参,在没有调用时,不占用内存中的存储单元。只有在函数被调用的时候,函数的形参才被分配内存单元,在调用结束后,形参所占的内存单元也会被释放;
(2)实参是确定的值。在调用时将实参的值赋值给形参,如果形参是指针类型,就将地址值传递给形参;
(3)实参和形参的类型应相同;
(4)实参与形参之间是单项传递,只能由实参传递给形参,而不能由形参传回来给实参。
5.2.2:默认参数
在定义函数默认值参数时,如果函数具有多个参数,应保证默认参数出现在参数列表的右方,如下所示:
int getMax(int x, int y, int z = 0) {
if (x < y) x = y;
if (x < z) x = z;
return x;
}
5.2.3:可变参数
省略号参数代表的含义是函数的参数是不固定的,可以传递一个或多个参数。
对于可变参数,可以使用va_list类型和va_start、va_arg、va_end 3个宏读取传递到函数中的参数值(需引用<STDARG.H> )。
例3:可变参数
#include <iostream>
#include <STDARG.H> //需要包含该头文件
using namespace std;
void OutputInfo(int num, ...) //定义一个省略号参数的函数
{
va_list arguments; //定义va_list类型变量
va_start(arguments, num);
while (num--) //读取所有参数的数据
{
char* pchData = va_arg(arguments, char*); //获取字符串数据
int iData = va_arg(arguments, int); //获取整型数据
cout << pchData << endl; //输出字符串
cout << iData << endl; //输出整数
}
va_end(arguments);
}
void main()
{
OutputInfo(2, "Beijing", 2022, "纯洁的冰雪激情的约会", 2022); //调用OutputInfo函数
}
5.3 函数调用
5.3.1 传值调用
例4:若x<y,则交换x、y.
1.常见误区:传值只是复制变量,未赋值
#include <iostream>
using namespace std;
void swap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int x, y;
cout << "输入两个数" << endl;
cin >> x;
cin >> y;
if (x < y)
swap(x, y);
cout << "x=" << x << endl;
cout << "y=" << y << endl;
return 0;
}
实际结果是x<y,调用函数却没有交换值,是因为swap函数复制了变量x和y的值,而非变量本身。
2.如果将swap写在主函数中:
int main()
{
int x, y;
cout << "输入两个数" << endl;
cin >> x;
cin >> y;
int tmp;
if (x < y) {
tmp = x;
x = y;
y = tmp;
}
cout << "x=" << x << endl;
cout << "y=" << y << endl;
return 0;
}
实际结果交换了两个变量的值
3.使用指针:实际更改变量的值
#include <iostream>
using namespace std;
void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int x, y;
cout << "输入两个数" << endl;
cin >> x;
cin >> y;
if (x < y)
swap(x, y);
cout << "x=" << x << endl;
cout << "y=" << y << endl;
return 0;
}
5.3.2 嵌套调用
一个函数中调用另外一个函数
例5:函数的嵌套调用
#include<iostream>
using namespace std;
void showMessage() {
cout << "The ShowMessage function" << endl;
}
void Display() {
showMessage();
}
int main() {
Display();
return 0;
}
5.3.3 递归调用
直接或间接调用自己的函数被称为递归函数(recursive function)。
缺点:递归的运行效率比较低,无论是从时间角度还是从空间角度都比非递归程序差。
例6:汉诺塔问题
这是一个经典的数学问题:古代有一个梵塔,塔内有3个座A,B,C,开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上。有个老和尚想把这64个盘子从A座移到C座,但每次只允许移动一个盘子,且移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求编程序打印出移动的步骤。
#include <iostream>
using namespace std;
long lCount;
void move(int n, char x, char y, char z)//将n个盘子从x针借助y针移到z针上。
{
if (n == 1)
cout << "Times:" << ++lCount << x << "->" << z << endl;
else
{
move(n - 1, x, z, y);
cout << "Times:" << ++lCount << x << "->" << z << endl;
move(n - 1, y, x, z);
}
}
int main()
{
int n;
lCount = 0;
cout << "please input a number" << endl;
cin >> n;
move(n, 'a', 'b', 'c');
return 0;
}
例7:求n!
1.递归调用
#include <iostream>
using namespace std;
long Fac(int n)
{
if (n == 0)
return 1;
else
return n * Fac(n - 1);
}
int main()
{
int n;
long f;
cout << "please input a number" << endl;
cin >> n;
f = Fac(n);
cout << "Result :" << f << endl;
return 0;
}
2.for循环
#include <iostream>
using namespace std;
typedef unsigned int UINT; //自定义类型
long Fac(const UINT n) //定义函数
{
long ret = 1; //定义结果变量
for (int i = 1; i <= n; i++) //累计乘积
{
ret *= i;
}
return ret; //返回结果
}
int main()
{
int n;
long f;
cout << "please input a number" << endl;
cin >> n;
f = Fac(n);
cout << "Result :" << f << endl;
return 0;
}
5.4 变量作用域
全局变量和局部变量:
(1)全局变量:在函数体内定义的变量;全局变量:在函数体外定义的变量;
(2)全局变量在程序开始的时候,创建并分配空间,在程序结束的时候,释放内存并销毁;
局部变量是在函数调用的时候创建,并在栈中分配内存,在函数调用结束后销毁并释放。
#include<iostream>
using namespace std;
int iTotalCount;//全局变量
int getCount();
int main() {
int iTotalCount = 100;//局部变量
cout << iTotalCount << endl;
cout << getCount() << endl;
return 0;
}
int getCount() {
iTotalCount = 200;//给全局
return iTotalCount;
}
5.5 重载函数
函数的重载(函数名相同,参数类型或个数不同)
#include <iostream>
using namespace std;
int Add(int x, int y) //定义第一个重载函数
{
cout << "int add" << endl; //输出信息
return x + y; //设置函数返回值
}
double Add(double x, double y) //定义第二个重载函数
{
cout << "double add" << endl; //输出信息
return x + y; //设置函数返回值
}
int main()
{
int ivar = Add(5, 2); //调用第一个Add函数
float fvar = Add(10.5, 11.4); //调用第二个Add函数
return 0;
}
例8:重载函数:fun(int a[], int n)与fun(int *p, int n)为同一函数
#include<iostream>
using namespace std;
//函数1
void fun(int a, float x){
cout << "函数1 fun(int a, float x)" << endl;
}
//函数2
void fun(int a, int x){
cout << "函数2 fun(int a, int x)" << endl;
}
//函数3
void fun(float a, float x){
cout << "函数3 fun(float a, float x)" << endl;
}
//函数4
void fun(float a, int x){
cout << "函数4 fun(float a, int x)" << endl;
}
//函数5
void fun(int a[], int n){
cout << "函数5 fun(int a[], int n)" << endl;
}
//函数6
void fun(int *p, int n){
cout << "函数6 fun(int *p, int n)" << endl;
}
int main() {
int a = 1,b=2;
float f = 1.1f;
int *p = &b;
int c[] = { 1,2,3 };
//选项A:函数1和函数2可以构成重载函数
fun(a, f);//函数1
fun(a, b);//函数2
//选项B:函数1和函数4可以构成重载函数
fun(f, a);//函数4
//选项C:函数3和函数4可以构成重载函数
fun(f, f);
//选项D:函数5和函数6可以构成重载函数
fun(c, a);//函数定义或声明中有错误;未调用函数
fun(p, a);//函数定义或声明中有错误;未调用函数
return 0;
}
5.6 内联函数
通过inline关键字可以把函数定义为内联函数,编译器会在每个调用该函数的地方展开一个函数的副本。
#include<iostream>
using namespace std;
inline int integerAdd(int x, int y);
int main() {
int a, b;
cin >> a >> b;
cout << integerAdd(a, b) << endl;
return 0;
}
int integerAdd(int x, int y) {
return x + y;
}
5.7 变量的存储类别
5.7.1:auto变量
auto(自动)变量存储类型是C++语言程序中默认的存储类型。函数中未加存储类型的变量均视为自动变量。
自动变量的特点:
(1)自动变量的作用域,仅限于定义该变量的个体内。
(2)自动变量属于动态存储方式,变量分配的内存是栈中,当函数调用结束后,自动变量的值会被释放。
(3)由于自动变量的作用域和生命期都局限于定义它的个体内(函数或符合语句内),因此不同的个体中允许使用同名的变量而不会混淆。
5.7.2:静态变量
1.在声明变量前加关键字static,可以将变量声明成静态变量。
静态局部变量的值在函数调用结束后不会消失;
静态全局变量的值在函数调用结束后不消失,静态全局变量只能在本源文件中使用。
2.静态变量属于静态存储方式,具有以下特定:
(1)静态变量的生命周期是整个源文件,即程序退出时才释放,整个运行期间都不释放;
(2)静态变量的作用域与自动变量相同;
(3)编译器会为静态局部变量赋予0值。
5.7.3:register变量
register变量(寄存器变量):当需要反复访问内存,花费大量的存取时间。此时使用寄存器变量,使用时不需要访问内存,直接从寄存器中读写。
寄存器变量的说明如下:
(1)寄存器变量属于动态存储方式。凡需要采用静态存储方式的量不能定义为寄存器变量;
(2)编译程序会自动决定哪个变量使用寄存器存储。register起到程序优化作用。
5.7.4:extern变量
在使用其他源文件的全局变量时,只需在本源文件使用extern关键字来声明这个变量就行。
例9:输出不同生命期的变量值
#include<iostream>
using namespace std;
int main()
{
auto int i, j, k;
cout << "input the number:" << endl;
cin >> i >> j;
k = i + j;
if (i != 0 && j != 0)
{
auto int k;
k = i - j;
cout << "k :" << k << endl;//输出变量K的值
}
cout << "k :" << k << endl;//输出变量k的值
return 0;
}
例10:使用静态变量实现累加,求1+2+3+...+n的值
#include<iostream>
using namespace std;
int add(int x)
{
static int n = 0;
n = n + x;
return n;
}
int main()
{
int i, j, sum;
cout << " input the number:" << endl;
cin >> i;
cout << "the result is:" << endl;
for (j = 1; j <= i; j++)
{
sum = add(j);
cout << j << ":" << sum << endl;
}
return 0;
}
世间安得双全法,不负如来不负卿!