函数与结构体

本文详细介绍了C++中的函数声明、定义和调用,包括传值和引用参数传递,以及数组、默认值参数和递归函数的使用。通过示例展示了如何在函数中交换两个整数的值,并探讨了传值传递与引用传递的区别。此外,还讨论了结构体的定义、初始化和成员访问,以及结构体作为函数参数的情况。最后,提供了两个实际的编程示例,分别是寻找数组中最大值的函数和汉诺塔问题的解决方案。
摘要由CSDN通过智能技术生成

函数的声明

  • 函数的声明是为了告诉编译器如何调用这个函数,形式如下:

    返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, ..., 参数n类型 参数n);
    
    • 返回值类型:一个函数可以返回一个值,返回值类型是函数返回的值的数据类型。
      • 有些函数执行所需的操作而不返回任何值,此时的返回值类型是void
    • 函数名:这是函数的实际名称
      • 一般会按照函数功能取名
    • 参数:声明时的参数称为形式参数,类似于占位符
      • 参数是可选的,函数可能不包含参数,也可以包含很多个参数
      • 在函数被调用之前,我们并不知道形式参数的值是什么

函数的定义

  • C++中定义函数时,需要在声明的基础上写好函数体,函数定义的形式如下:
返回值类型 函数名(参数1类型 参数1, 参数2类型 参数2, ..., 参数n类型 参数n) {
    函数体
}

函数的调用

  • C++中,定义了函数之后,函数里面的代码是不会执行的,只有调用了这个函数,才会去执行函数中的代码。
    • 当函数被调用时,我们向参数传递一个值,这个值被称为**实际参数*。

Tips:如果我们函数的定义在调用前进行的话,也可以省略函数的声明这一步。

举例:调用MyMax函数,返回两个整型数中更大的一个数。

#include <iostream>
using namespace std;

// 定义这个函数,在调用前就定义了,所以可以省略声明
int MyMax(int a, int b) {
    int max_num;
    if (a > b)
        max_num = a;
    else
        max_num = b;
    return max_num;
}

int main() {
    int num1 = 30;
    int num2 = 50;
    // 变量 num3 表示这两个数字中更大的值
    int num3;
    
    // 调用
    num3 = MyMax(num1, num2);
    
    cout << num3 << endl;
    return 0;
}

以上代码以main()函数为入口开始执行,运行到 MyMax(num1, num2) 时会调用MyMax函数。过程如下:

  • num1num2作为实际参数传递给MyMax函数
    • 其中,num1(30)传给形参anum2(50)传给形参b
  • 进入到MyMax函数中执行代码
    • 变量max_num是在函数体中声明的,称为局部变量,只有在这个函数里能访问到这个变量 Tips:如果把max_num声明在函数外,就是一个全局变量,所有函数,包括main()函数都可以访问。
  • 返回一个整型数max_num(50),并离开MyMax函数回到main()函数
    • MyMax(num1, num2)的计算结果为50,返回的结果将被赋值给num3

参数传递: 传值和引用

调用函数时,参数的传递一般分为传值传递引用传递

  • 传值传递
    • 把参数的实际值赋值给函数的形式参数
    • 修改函数内的形式参数对实际参数没有影响
  • 引用传递
    • 该方法把参数的引用赋值给形式参数
    • 函数内通过会引用访问实际参数,若进行修改会改变实际参数的值
#include <iostream>
using namespace std;

// 传值传递
void swap1(int x, int y) {
    cout << "传值传递:" << endl;
    cout << "交换前,x 的值:" << x << endl;
    cout << "交换前,y 的值:" << y << endl;
    
    int temp;
    temp = x; /* 保存 x 的值 */
    x = y;    /* 把 y 赋值给 x */
    y = temp; /* 把 x 赋值给 y */

    cout << "交换后,x 的值:" << x << endl;
    cout << "交换后,y 的值:" << y << endl;

    return;
}

// 引用传递
void swap2(int &x, int &y) {
    cout << "引用传递:" << endl;
    cout << "交换前,x 的值:" << x << endl;
    cout << "交换前,y 的值:" << y << endl;

    int temp;
    temp = x; /* 保存地址 x 的值 */
    x = y;    /* 把地址 y 的值赋值给地址 x */
    y = temp; /* 把地址 x 的值赋值给地址 y  */

    cout << "交换后,x 的值:" << x << endl;
    cout << "交换后,y 的值:" << y << endl;
  
    return;
}

int main () {
    // 局部变量声明
    int a = 100;
    int b = 200;

    cout << "交换前,a 的值:" << a << endl;
    cout << "交换前,b 的值:" << b << endl;

    // 调用传值传递的函数来交换值
    swap1(a, b);

    cout << "传值传递交换后,a 的值:" << a << endl;
    cout << "传值传递交换后,b 的值:" << b << endl;

    // 调用引用传递的函数来交换值
    swap2(a, b);

    cout << "引用传递交换后,a 的值:" << a << endl;
    cout << "引用传递交换后,b 的值:" << b << endl;

    return 0;
}
//交换前,a 的值:100
//交换前,b 的值:200
//传值传递:
//交换前,x 的值:100
//交换前,y 的值:200
//交换后,x 的值:200
//交换后,y 的值:100
//传值传递交换后,a 的值:100
//传值传递交换后,b 的值:200
//引用传递:
//交换前,x 的值:100
//交换前,y 的值:200
//交换后,x 的值:200
//交换后,y 的值:100
//引用传递交换后,a 的值:200
//引用传递交换后,b 的值:100

参数传递: 数组参数

  • 数组名表示的是数组的地址,所以这时候我们传递的参数实际上是数组的地址。
    • 在函数中修改数组里的某一个值,会在内存中直接修改这个数组。
#include <iostream>
using namespace std;

// TODO 补充第一个参数:整型数组a
int MyMax(int a[], int len) {
    int max_num = 0;
    for (int i=0; i<len; i++) {
        if (a[i] > max_num)
            max_num = a[i];
    }
    return max_num;
}

int main() {
    int nums[10] = {3, 2, 1, 1, 2, 3, 3, 2, 1, 0};
    cout << MyMax(nums, 10) << endl;
    return 0;
}
//3

参数传递:参数默认值

  • 函数定义时,我们可以给函数的参数设置默认值
    • 这样我们调用函数时,可以选择不传递参数,选择默认的参数。

举例:比较两个数大小返回最大值的函数,我们可以把形式参数b的默认值设置为100。

设置参数默认值的程序段

// 定义这个函数,在调用前就定义了,所以可以省略声明
int MyMax(int a, int b = 100) {
    int max_num;
    if (a>b)
        max_num = a;
    else
        max_num = b;
    return max_num;
}
  • 在调用函数时,如果只传递一个参数a,比如MyMax(30),函数就会默认b的值为100,效果等同于MyMax(30, 100)
  • 如果调用函数时,还是传递了两个参数,比如MyMax(30, 80),那么就不使用b的默认值。

Tips:若给某一参数设置了默认值,那么在参数列表中,位于该参数之后的所有参数都必须也设置默认值。

递归函数

递归函数的两个基本要素

  • 递归函数的写法有两个基本要素:

    • 递归关系

      • 问题规模为n时与问题规模为n-1时之间的转换关系
      • 计算某个数字的阶乘,递归的关系就是:数字n的阶乘 = 数字n * 数字n-1的阶乘
      • 这个函数可以写成: 递归关系的程序段
      int factorial(int n) {
          return n * factorial(n-1);
      }
      

      Tips:只知道递归关系是不够的,比如上面这个函数,就会无休止的一直套娃套下去,没有尽头。

    • 递归的终止条件

      • 递归关系需要有一个递归终止的条件。
      • 在计算阶乘中,递归终止的条件是计算到数字1的阶乘的时候,函数可以直接返回数字1的阶乘就是1
      • 补充上这个条件: 递归终止条件的程序段
      int factorial(int n) {
          if (n == 1)
              return 1;
          else
              return n * factorial(n-1);
      }
      

      Tips:更严谨的,我们可以在n小于1的时候,输出错误操作。

🌰

汉诺塔
左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间需要遵循以下原则:

一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤。若将A最上面的盘子移动到B上,则可表示为 "A -> B"。

输入描述:

一行,一个整数n (n <= 20)。

输出描述:

若干行,每行代表一次操作。

比如:

A -> B

示例 1:
输入:
2
输出:
A -> B
A -> C
B -> C
#include <bits/stdc++.h>
using namespace std; 

void hanoi(int N, char source, char relay, char destination){
    if(N==1)
        cout << source << " -> " << destination << endl;
    else{
        hanoi(N-1, source, destination, relay);
        cout << source << " -> " << destination << endl;
        hanoi(N-1,relay,source,destination);
    }
}
int main() {
    // 请补全代码,实现题目功能
    int n;
    cin >> n;
    hanoi(n,'A','B','C');
    return 0;
}

结构体

结构体的定义

  • 结构体有很多个不同类型的变量,用于表示这个结构体的属性,称之为结构体的成员变量
  • 在使用结构体之前,我们需要在代码中定义结构体,定义方式如下:
struct 结构体名称 {
    数据类型1 变量名1;
    数据类型2 变量名2, 变量名3;
    ...
    数据类型n 变量名m;
};

定义结构体时需要注意:

  • 使用struct关键字
  • 每个结构体都有自己的名称
    • 例如储存学生信息的结构体可以命名为Student
  • 在结构体内部声明成员变量
    • 例如学生的姓名、学号、出生年份等信息
  • 注意大括号后面需要有分号

举例:定义学生信息的结构体:

学生信息结构体的代码段

struct Student{    
    int number, birth_year;
    string name;
};

结构体变量声明

  • 定义结构体之后,我们就可以声明结构体类型的变量,作为结构体的实例

Tips:声明结构体变量的方式和声明普通变量是一样的,在声明结构体变量的时候,系统就会为它们在内存上分配空间了。

举例:声明Student结构体的实例

  • 声明结构体变量,每个变量都包含具有相同名称的成员变量。

声明结构体变量的程序段

struct Student{    
    int number, birth_year;
    string name;
};

// 声明三个学生
Student zhang_san, li_si, wang_mazi;
  • 另外,我们也可以声明结构体变量的数组,以保存500个学生的信息。

声明结构体变量数组的程序段

// 声明一个学生数组,数组长度为500,可以保存500个学生的信息
Student students[500];

另一种声明结构体变量的方式是:直接在定义结构体时,声明结构体变量。

定义时声明结构体变量的程序段

struct Student{    
    int number, birth_year;
    string name;
} zhang_san, li_si, wang_mazi;

struct Student{    
    int number, birth_year;
    string name;
} students[500];

初始化结构体

  • 对于结构体变量,可以通过两种方式初始化它:使用初始化列表或构造函数。
  • 使用初始化列表和数组的初始化类似,会根据给出的元素依次初始化结构体中的每个成员
    • 如果给出的元素小于成员数量,排在后面的就会保持没有被初始化

使用初始化列表的程序段

struct Student{    
    int number, birth_year;
    string name;
};

// 初始化一个学号为1,2000年出生,名叫 ZhangSan的学生
Student zhang_san = {1, 2000, "ZhangSan"};

Tips:使用初始化列表会有一些问题:比如,如果有某个成员未被初始化,那么在这种情况下,跟随在该成员后面的成员都不能初始化。

  • 采用构造函数初始化,可以在创建一个结构体变量而不向其传递某些成员变量的值时,提供默认值
    • 可以先在结构体内部完成一个构造函数,再调用这个构造函数来初始化结构体变量

结构体成员访问

  • 要访问某一个结构体变量的某个成员,可以使用结构体变量名.结构体成员变量名的方式访问

结构体作为函数参数

结构体变量也可以通过传值传递引用传递给函数。

  • 传值传递意味着需要生成整个原始结构的副本并传递给函数。

Tips:因为不希望浪费时间和空间来复制整个结构体,所以传值传递一般在结构很小时采用。

  • 引用传递意味着函数可以访问原始结构的成员变量,从而可能更改它们
    • 如果不想让函数更改任何成员变量值,那么可以将结构体变量作为一个常量引用传递给函数
    • 常量引用传递需要在参数类型前加上const关键字。

举例:展示学生信息

展示学生信息的程序段

// 定义函数
void showStudent(const Student &student_info) {
    cout << "Student Number : " << student_info.number << endl;
    cout << "Name : " << student_info.name << endl;
    cout << "Birth Year : " << student_info.birth_year << endl;
}

// 调用函数
showStudent(zhang_san);

🌰

年龄最大学员
输入n个学生的信息,包括姓名、性别、年龄,再输出其中年龄最大的学生的信息。(保证最大年龄不重复)

1 <= n <= 10

姓名长度小于等于20

性别为M或F

输入描述:

第一行一个整数n

接下来n行,依次是学生的姓名、性别、年龄。

输出描述:

一行,依次是姓名、性别、年龄,中间用空格隔开。

示例 1:
输入:
2
Kal'tsit F 1000
Amiya F 14
输出:
Kal'tsit F 1000
#include <iostream>
#include <string>

using namespace std;

struct Student {
    string name;
    char gender;
    int age;
};

int main() {
    int num, max_age, max_age_idx;
    cin >> num;
    
    string n;
    char g;
    int a;
    
    Student students[11];
    for (int i=0; i<num; i++) {
        cin >> n >> g >> a;
        students[i] = {n, g, a};
    }
    
    max_age = 0;
    max_age_idx = 0;
    for (int i=0; i<num; i++) {
        if (students[i].age > max_age) {
            max_age = students[i].age;
            max_age_idx = i;
        }
    }
    cout << students[max_age_idx].name << " " << students[max_age_idx].gender << " " << students[max_age_idx].age;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值