C++ Primer Plus 第7章:函数——C++的编程模块

7.1 函数基础

7.1.1 为什么需要函数?

函数是C++程序的基本构建块,使用函数的好处:

  • 代码复用:相同逻辑只写一次,多处调用
  • 模块化:将复杂问题分解为小的、可管理的部分
  • 可维护性:修改一处,全局生效
  • 可读性:函数名本身就是文档

7.1.2 函数的三要素

复制代码
① 函数原型(声明):告诉编译器函数的接口
② 函数定义:实现函数的具体逻辑
③ 函数调用:使用函数
cpp 复制代码
// function_basics.cpp -- 函数三要素示例
#include <iostream>

// ① 函数原型(声明):在main()之前声明
//    格式:返回类型 函数名(参数类型列表);
double square(double x);        // 求平方
void   printLine(int n);        // 打印分隔线
int    add(int a, int b);       // 求和

int main()
{
    using namespace std;

    // ③ 函数调用
    double result = square(5.0);
    cout << "5的平方 = " << result << endl;

    printLine(20);

    cout << "3 + 4 = " << add(3, 4) << endl;

    return 0;
}

// ② 函数定义:实现具体逻辑
double square(double x)
{
    return x * x;
}

void printLine(int n)
{
    for (int i = 0; i < n; i++)
        std::cout << '-';
    std::cout << std::endl;
}

int add(int a, int b)
{
    return a + b;
}

输出:

复制代码
5的平方 = 25
--------------------
3 + 4 = 7

7.1.3 函数原型的作用

cpp 复制代码
// 函数原型让编译器能够:
// 1. 检查参数数量是否正确
// 2. 检查参数类型是否匹配(必要时自动转换)
// 3. 检查返回值类型

double cube(double x);   // 原型

int main()
{
    // 编译器根据原型检查调用是否正确
    double v1 = cube(3.0);      // ✅ 正确
    double v2 = cube(3);        // ✅ int自动转换为double
    // double v3 = cube(3.0, 2.0); // ❌ 参数数量错误,编译报错
    return 0;
}

double cube(double x) { return x * x * x; }

7.2 函数参数与返回值

7.2.1 按值传递(Pass by Value)

按值传递 :函数接收的是实参的副本,函数内部修改不影响原变量。

cpp 复制代码
// pass_by_value.cpp -- 按值传递示例
#include <iostream>

// 尝试交换两个变量(按值传递,无效!)
void swap_wrong(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
    // a和b是副本,修改不影响原变量
    std::cout << "函数内:a=" << a << " b=" << b << std::endl;
}

// 计算阶乘(按值传递,正确使用)
int factorial(int n)
{
    int result = 1;
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

int main()
{
    using namespace std;

    int x = 10, y = 20;
    cout << "交换前:x=" << x << " y=" << y << endl;
    swap_wrong(x, y);
    cout << "交换后:x=" << x << " y=" << y << endl;
    // x和y没有改变!

    cout << "\n5! = " << factorial(5) << endl;   // 120
    cout << "10! = " << factorial(10) << endl;  // 3628800

    return 0;
}

输出:

复制代码
交换前:x=10 y=20
函数内:a=20 b=10
交换后:x=10 y=20    ← 原变量未改变!

7.2.2 多个参数与返回值

cpp 复制代码
// multi_params.cpp -- 多参数函数示例
#include <iostream>
#include <cmath>

// 计算两点之间的距离
double distance(double x1, double y1, double x2, double y2)
{
    double dx = x2 - x1;
    double dy = y2 - y1;
    return sqrt(dx * dx + dy * dy);
}

// 判断是否为闰年
bool isLeapYear(int year)
{
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 返回两数中的较大值
int maxOf(int a, int b)
{
    return (a > b) ? a : b;
}

int main()
{
    using namespace std;

    cout << "两点距离:" << distance(0, 0, 3, 4) << endl;   // 5

    cout << boolalpha;
    cout << "2024年是闰年:" << isLeapYear(2024) << endl;   // true
    cout << "2023年是闰年:" << isLeapYear(2023) << endl;   // false

    cout << "max(15, 28) = " << maxOf(15, 28) << endl;      // 28

    return 0;
}

7.3 函数与数组

7.3.1 将数组传递给函数

数组名本质是指针,传递数组时传递的是首元素的地址,不是数组的副本。因此函数内修改数组会影响原数组。

cpp 复制代码
// array_func.cpp -- 数组作为函数参数
#include <iostream>

// 方式1:int arr[](等价于 int* arr)
// 必须同时传入数组大小!
double average(int arr[], int size)
{
    double sum = 0;
    for (int i = 0; i < size; i++)
        sum += arr[i];
    return sum / size;
}

// 方式2:int* arr(与方式1完全等价)
int findMax(int* arr, int size)
{
    int maxVal = arr[0];
    for (int i = 1; i < size; i++)
        if (arr[i] > maxVal)
            maxVal = arr[i];
    return maxVal;
}

// 修改数组内容(函数内修改会影响原数组)
void doubleArray(int arr[], int size)
{
    for (int i = 0; i < size; i++)
        arr[i] *= 2;
}

int main()
{
    using namespace std;

    int scores[] = {85, 92, 78, 96, 88, 73, 91};
    int size = sizeof(scores) / sizeof(scores[0]);   // 7

    cout << "平均分:" << average(scores, size) << endl;
    cout << "最高分:" << findMax(scores, size) << endl;

    cout << "\n原数组:";
    for (int i = 0; i < size; i++)
        cout << scores[i] << " ";
    cout << endl;

    doubleArray(scores, size);   // 修改原数组

    cout << "翻倍后:";
    for (int i = 0; i < size; i++)
        cout << scores[i] << " ";
    cout << endl;

    return 0;
}

7.3.2 使用 const 保护数组

cpp 复制代码
// const_array.cpp -- const保护数组参数
#include <iostream>

// const 防止函数意外修改数组
void printArray(const int arr[], int size)
{
    for (int i = 0; i < size; i++)
        std::cout << arr[i] << " ";
    std::cout << std::endl;
    // arr[0] = 999;  // ❌ 编译错误!const保护
}

// 计算总和(只读,加const)
int sumArray(const int* arr, int size)
{
    int sum = 0;
    for (int i = 0; i < size; i++)
        sum += arr[i];
    return sum;
}

int main()
{
    int data[] = {1, 2, 3, 4, 5};
    printArray(data, 5);
    std::cout << "总和:" << sumArray(data, 5) << std::endl;
    return 0;
}

💡 最佳实践 :如果函数不需要修改数组,始终加 const,这样既保护数据,又明确了函数的意图。


7.3.3 使用指针范围传递数组

cpp 复制代码
// pointer_range.cpp -- 用指针范围传递数组
#include <iostream>

// 传入首指针和尾后指针(类似STL风格)
double sumRange(const double* begin, const double* end)
{
    double sum = 0;
    for (const double* p = begin; p != end; p++)
        sum += *p;
    return sum;
}

int main()
{
    using namespace std;

    double prices[] = {9.9, 15.5, 23.0, 8.8, 12.3};
    int size = 5;

    // 传入首地址和尾后地址
    double total = sumRange(prices, prices + size);
    cout << "总价:" << total << endl;

    // 只计算前3个
    double partial = sumRange(prices, prices + 3);
    cout << "前3个总价:" << partial << endl;

    return 0;
}

7.4 函数与二维数组

cpp 复制代码
// 2d_array_func.cpp -- 二维数组作为函数参数
#include <iostream>

const int COLS = 4;   // 列数必须是常量

// 二维数组参数:必须指定列数
int sumMatrix(int matrix[][COLS], int rows)
{
    int sum = 0;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < COLS; j++)
            sum += matrix[i][j];
    return sum;
}

void printMatrix(const int matrix[][COLS], int rows)
{
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            std::cout.width(5);
            std::cout << matrix[i][j];
        }
        std::cout << std::endl;
    }
}

int main()
{
    int mat[3][COLS] = {
        { 1,  2,  3,  4},
        { 5,  6,  7,  8},
        { 9, 10, 11, 12}
    };

    std::cout << "矩阵内容:" << std::endl;
    printMatrix(mat, 3);
    std::cout << "元素总和:" << sumMatrix(mat, 3) << std::endl;

    return 0;
}

7.5 函数与字符串

cpp 复制代码
// string_func.cpp -- 字符串作为函数参数
#include <iostream>
#include <cstring>
#include <cctype>
#include <string>

// C风格字符串:传入char指针
int countVowels(const char* str)
{
    int count = 0;
    while (*str)
    {
        char c = tolower(*str);
        if (c=='a' || c=='e' || c=='i' || c=='o' || c=='u')
            count++;
        str++;
    }
    return count;
}

// string类:按值传递(会复制)
std::string toUpperStr(std::string s)
{
    for (char& c : s)
        c = toupper(c);
    return s;
}

// string类:按引用传递(不复制,效率高)
void reverseStr(std::string& s)
{
    int left = 0, right = s.size() - 1;
    while (left < right)
    {
        std::swap(s[left], s[right]);
        left++;
        right--;
    }
}

int main()
{
    using namespace std;

    const char* cstr = "Hello, World!";
    cout << "元音字母数:" << countVowels(cstr) << endl;   // 3

    string str = "hello cpp";
    cout << "转大写:" << toUpperStr(str) << endl;
    cout << "原字符串:" << str << endl;   // 未改变

    reverseStr(str);
    cout << "反转后:" << str << endl;

    return 0;
}

7.6 函数与结构体

cpp 复制代码
// struct_func.cpp -- 结构体作为函数参数
#include <iostream>
#include <string>
#include <cmath>

struct Point {
    double x;
    double y;
};

struct Rectangle {
    double width;
    double height;
};

// 按值传递结构体(会复制整个结构体)
double distanceBetween(Point p1, Point p2)
{
    double dx = p2.x - p1.x;
    double dy = p2.y - p1.y;
    return sqrt(dx * dx + dy * dy);
}

// 按const引用传递(避免复制,推荐)
double area(const Rectangle& rect)
{
    return rect.width * rect.height;
}

double perimeter(const Rectangle& rect)
{
    return 2 * (rect.width + rect.height);
}

// 返回结构体
Point midpoint(Point p1, Point p2)
{
    return {(p1.x + p2.x) / 2, (p1.y + p2.y) / 2};
}

int main()
{
    using namespace std;

    Point a = {0.0, 0.0};
    Point b = {3.0, 4.0};
    cout << "两点距离:" << distanceBetween(a, b) << endl;   // 5

    Point mid = midpoint(a, b);
    cout << "中点:(" << mid.x << ", " << mid.y << ")" << endl;

    Rectangle rect = {5.0, 3.0};
    cout << "面积:" << area(rect) << endl;         // 15
    cout << "周长:" << perimeter(rect) << endl;    // 16

    return 0;
}

7.7 函数指针

7.7.1 什么是函数指针?

函数指针是指向函数的指针,可以将函数作为参数传递,实现回调机制。

复制代码
函数指针声明格式:
返回类型 (*指针名)(参数类型列表);

例如:指向 double func(int) 的指针:
double (*pf)(int);
cpp 复制代码
// func_pointer.cpp -- 函数指针基础
#include <iostream>

double square(double x) { return x * x; }
double cube(double x)   { return x * x * x; }
double squareRoot(double x) { return sqrt(x); }

// 接受函数指针作为参数
void applyAndPrint(double x, double (*func)(double))
{
    std::cout << "结果:" << func(x) << std::endl;
}

int main()
{
    using namespace std;

    // 声明函数指针
    double (*pf)(double);

    // 赋值:函数名就是函数地址
    pf = square;
    cout << "square(5) = " << pf(5) << endl;   // 25

    pf = cube;
    cout << "cube(3)   = " << pf(3) << endl;   // 27

    // 将函数指针作为参数传递
    cout << "\n对 4.0 应用不同函数:" << endl;
    applyAndPrint(4.0, square);      // 16
    applyAndPrint(4.0, cube);        // 64

    // 函数指针数组
    double (*funcs[])(double) = {square, cube};
    string names[] = {"square", "cube"};

    cout << "\n函数指针数组:" << endl;
    for (int i = 0; i < 2; i++)
        cout << names[i] << "(3) = " << funcs[i](3) << endl;

    return 0;
}

7.7.2 函数指针的实际应用:排序策略

cpp 复制代码
// sort_strategy.cpp -- 函数指针实现排序策略
#include <iostream>

// 比较函数
bool ascending(int a, int b)  { return a < b; }   // 升序
bool descending(int a, int b) { return a > b; }   // 降序

// 冒泡排序,接受比较函数指针
void bubbleSort(int arr[], int size, bool (*compare)(int, int))
{
    for (int i = 0; i < size - 1; i++)
        for (int j = 0; j < size - i - 1; j++)
            if (!compare(arr[j], arr[j+1]))
                std::swap(arr[j], arr[j+1]);
}

void printArray(const int arr[], int size)
{
    for (int i = 0; i < size; i++)
        std::cout << arr[i] << " ";
    std::cout << std::endl;
}

int main()
{
    using namespace std;

    int data[] = {64, 34, 25, 12, 22, 11, 90};
    int size = 7;

    int asc_data[7], desc_data[7];
    for (int i = 0; i < size; i++)
        asc_data[i] = desc_data[i] = data[i];

    bubbleSort(asc_data,  size, ascending);
    bubbleSort(desc_data, size, descending);

    cout << "升序:"; printArray(asc_data,  size);
    cout << "降序:"; printArray(desc_data, size);

    return 0;
}

7.8 递归函数

7.8.1 递归的基本概念

递归是函数调用自身的技术。每个递归函数必须有:

  1. 基准情形(Base Case):停止递归的条件

  2. 递归情形(Recursive Case):调用自身,向基准情形靠近

    递归调用栈示意(factorial(4)):
    factorial(4)
    └─ 4 * factorial(3)
    └─ 3 * factorial(2)
    └─ 2 * factorial(1)
    └─ 1(基准情形,返回1)
    返回 21 = 2
    返回 3
    2 = 6
    返回 4*6 = 24

cpp 复制代码
// recursion_demo.cpp -- 递归函数示例
#include <iostream>

// 递归求阶乘
long long factorial(int n)
{
    // 基准情形
    if (n <= 1)
        return 1;
    // 递归情形
    return n * factorial(n - 1);
}

// 递归求斐波那契数列
int fibonacci(int n)
{
    if (n <= 0) return 0;
    if (n == 1) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// 递归求数组元素之和
int sumArray(const int arr[], int size)
{
    if (size == 0) return 0;                          // 基准情形
    return arr[0] + sumArray(arr + 1, size - 1);      // 递归情形
}

int main()
{
    using namespace std;

    // 阶乘
    for (int i = 0; i <= 10; i++)
        cout << i << "! = " << factorial(i) << endl;

    // 斐波那契
    cout << "\n斐波那契数列前10项:";
    for (int i = 1; i <= 10; i++)
        cout << fibonacci(i) << " ";
    cout << endl;

    // 数组求和
    int arr[] = {1, 2, 3, 4, 5};
    cout << "\n数组求和:" << sumArray(arr, 5) << endl;   // 15

    return 0;
}

7.8.2 递归与迭代的对比

cpp 复制代码
// recursion_vs_iteration.cpp
#include <iostream>

// 递归版本(简洁但有函数调用开销)
long long factRecursive(int n)
{
    return (n <= 1) ? 1 : n * factRecursive(n - 1);
}

// 迭代版本(效率更高)
long long factIterative(int n)
{
    long long result = 1;
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

int main()
{
    using namespace std;

    for (int i = 1; i <= 12; i++)
    {
        cout << i << "! 递归=" << factRecursive(i)
             << " 迭代=" << factIterative(i) << endl;
    }
    return 0;
}

💡 递归 vs 迭代

  • 递归代码更简洁,适合树形结构、分治算法
  • 迭代效率更高,无函数调用开销,无栈溢出风险
  • 能用迭代解决的问题,优先考虑迭代

7.9 内联函数(inline)

内联函数是对编译器的建议 :将函数调用替换为函数体代码,避免函数调用开销,适合短小、频繁调用的函数。

cpp 复制代码
// inline_demo.cpp -- 内联函数示例
#include <iostream>

// 普通函数:有函数调用开销
double square_normal(double x)
{
    return x * x;
}

// 内联函数:编译器可能直接展开代码
inline double square_inline(double x)
{
    return x * x;
}

// 内联函数适合短小的函数
inline int max2(int a, int b)
{
    return (a > b) ? a : b;
}

inline bool isEven(int n)
{
    return n % 2 == 0;
}

int main()
{
    using namespace std;

    // 调用方式与普通函数完全相同
    cout << square_inline(5.0) << endl;   // 25
    cout << max2(10, 20) << endl;         // 20
    cout << boolalpha << isEven(7) << endl;  // false

    // 内联函数在循环中的优势
    double sum = 0;
    for (int i = 1; i <= 1000000; i++)
        sum += square_inline(i);   // 避免百万次函数调用开销

    return 0;
}

💡 inline 注意事项

  • inline 只是对编译器的建议,编译器可以忽略
  • 函数体过长时,内联反而会增大代码体积
  • 递归函数不能内联
  • 通常定义在头文件中

7.10 引用变量与引用参数

7.10.1 引用的基本概念

引用是变量的别名,对引用的操作就是对原变量的操作。

cpp 复制代码
// reference_basic.cpp -- 引用基础
#include <iostream>

int main()
{
    using namespace std;

    int a = 10;
    int& ref = a;   // ref 是 a 的引用(别名)

    cout << "a   = " << a   << endl;   // 10
    cout << "ref = " << ref << endl;   // 10

    ref = 20;   // 修改ref就是修改a
    cout << "修改ref后,a = " << a << endl;   // 20

    // 引用和原变量共享同一地址
    cout << "&a   = " << &a   << endl;
    cout << "&ref = " << &ref << endl;   // 地址相同!

    // 引用必须在声明时初始化,且不能改变绑定
    // int& r;      // ❌ 错误:引用必须初始化
    // ref = b;     // 这是赋值,不是改变引用绑定

    return 0;
}

7.10.2 引用参数(按引用传递)

cpp 复制代码
// pass_by_reference.cpp -- 按引用传递
#include <iostream>

// 按引用传递:可以修改原变量
void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}

// const引用:只读,不修改原变量(高效传递大对象)
double sumVector(const std::vector<double>& v);

// 对比三种传递方式
void byValue(int x)     { x = 999; }   // 修改副本,无效
void byPointer(int* x)  { *x = 999; }  // 修改原值
void byReference(int& x){ x = 999; }   // 修改原值

int main()
{
    using namespace std;

    // 引用传递实现真正的交换
    int x = 10, y = 20;
    cout << "交换前:x=" << x << " y=" << y << endl;
    swap(x, y);
    cout << "交换后:x=" << x << " y=" << y << endl;

    // 三种传递方式对比
    int a = 0, b = 0, c = 0;
    byValue(a);
    byPointer(&b);
    byReference(c);
    cout << "\n按值传递后:a = " << a << endl;     // 0(未改变)
    cout << "按指针传递后:b = " << b << endl;   // 999
    cout << "按引用传递后:c = " << c << endl;   // 999

    return 0;
}

7.10.3 返回引用

cpp 复制代码
// return_reference.cpp -- 返回引用
#include <iostream>

// 返回引用:可以作为左值
int& getElement(int arr[], int index)
{
    return arr[index];   // 返回数组元素的引用
}

int main()
{
    using namespace std;

    int data[] = {10, 20, 30, 40, 50};

    // 返回引用可以作为左值(赋值目标)
    getElement(data, 2) = 999;   // 修改data[2]

    for (int i = 0; i < 5; i++)
        cout << data[i] << " ";
    cout << endl;   // 10 20 999 40 50

    // ⚠️ 不要返回局部变量的引用!
    // int& badRef() {
    //     int local = 10;
    //     return local;   // 危险!local在函数结束后销毁
    // }

    return 0;
}

7.11 默认参数

cpp 复制代码
// default_params.cpp -- 默认参数示例
#include <iostream>
#include <string>

// 默认参数必须从右向左设置
void printInfo(std::string name,
               int age = 18,
               std::string city = "北京")
{
    std::cout << "姓名:" << name
              << " 年龄:" << age
              << " 城市:" << city << std::endl;
}

// 计算幂次(默认平方)
double power(double base, int exp = 2)
{
    double result = 1.0;
    for (int i = 0; i < exp; i++)
        result *= base;
    return result;
}

int main()
{
    using namespace std;

    // 使用默认参数
    printInfo("张三");                    // age=18, city=北京
    printInfo("李四", 25);               // city=北京
    printInfo("王五", 30, "上海");       // 全部指定

    cout << "\npower(3)    = " << power(3)    << endl;   // 9(默认平方)
    cout << "power(3, 3) = " << power(3, 3) << endl;   // 27
    cout << "power(2, 10)= " << power(2, 10) << endl;  // 1024

    return 0;
}

💡 默认参数规则

  • 默认参数必须从右向左连续设置
  • 默认参数通常在函数原型中指定,不在定义中重复
  • 调用时,省略的参数使用默认值

7.12 函数重载

函数重载允许同名函数有不同的参数列表,编译器根据调用时的参数自动选择正确的版本。

cpp 复制代码
// overload_demo.cpp -- 函数重载示例
#include <iostream>
#include <string>

// 同名函数,不同参数类型
void print(int x)
{
    std::cout << "整数:" << x << std::endl;
}

void print(double x)
{
    std::cout << "浮点数:" << x << std::endl;
}

void print(const std::string& s)
{
    std::cout << "字符串:" << s << std::endl;
}

void print(int x, int y)
{
    std::cout << "两个整数:" << x << ", " << y << std::endl;
}

// 重载的实际应用:求绝对值
int    myAbs(int x)    { return (x >= 0) ? x : -x; }
double myAbs(double x) { return (x >= 0) ? x : -x; }

int main()
{
    using namespace std;

    // 编译器根据参数类型自动选择版本
    print(42);              // 调用 print(int)
    print(3.14);            // 调用 print(double)
    print(string("Hello")); // 调用 print(string)
    print(10, 20);          // 调用 print(int, int)

    cout << "\nmyAbs(-5)   = " << myAbs(-5)   << endl;   // 5
    cout << "myAbs(-3.14)= " << myAbs(-3.14) << endl;   // 3.14

    return 0;
}

函数重载的匹配规则:

优先级 匹配类型
1(最高) 完全匹配(类型完全一致)
2 提升匹配(如 char→int,float→double)
3 标准转换(如 int→double)
4(最低) 用户自定义转换

7.13 综合示例:学生成绩管理系统

cpp 复制代码
// grade_system.cpp -- 综合示例
#include <iostream>
#include <string>
#include <fstream>

const int MAX_STUDENTS = 50;

struct Student {
    std::string name;
    int scores[3];   // 语文、数学、英语
    double average;
    char   grade;
};

// 计算平均分
double calcAverage(const int scores[], int n)
{
    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += scores[i];
    return (double)sum / n;
}

// 根据平均分确定等级
char getGrade(double avg)
{
    if (avg >= 90) return 'A';
    if (avg >= 80) return 'B';
    if (avg >= 70) return 'C';
    if (avg >= 60) return 'D';
    return 'F';
}

// 打印单个学生信息
void printStudent(const Student& s)
{
    std::cout << s.name << "\t"
              << s.scores[0] << "\t"
              << s.scores[1] << "\t"
              << s.scores[2] << "\t"
              << s.average   << "\t"
              << s.grade     << std::endl;
}

// 找最高平均分的学生
int findBest(const Student students[], int n)
{
    int best = 0;
    for (int i = 1; i < n; i++)
        if (students[i].average > students[best].average)
            best = i;
    return best;
}

// 保存到文件
void saveToFile(const Student students[], int n,
                const std::string& filename)
{
    std::ofstream file(filename);
    if (!file) { std::cout << "文件创建失败" << std::endl; return; }

    file << "姓名\t语文\t数学\t英语\t平均\t等级" << std::endl;
    for (int i = 0; i < n; i++)
        file << students[i].name    << "\t"
             << students[i].scores[0] << "\t"
             << students[i].scores[1] << "\t"
             << students[i].scores[2] << "\t"
             << students[i].average   << "\t"
             << students[i].grade     << std::endl;

    std::cout << "数据已保存到 " << filename << std::endl;
}

int main()
{
    using namespace std;

    Student students[MAX_STUDENTS];
    int n = 4;

    // 初始化数据
    students[0] = {"张三", {85, 92, 88}};
    students[1] = {"李四", {90, 78, 95}};
    students[2] = {"王五", {72, 85, 80}};
    students[3] = {"赵六", {95, 98, 92}};

    // 计算平均分和等级
    for (int i = 0; i < n; i++)
    {
        students[i].average = calcAverage(students[i].scores, 3);
        students[i].grade   = getGrade(students[i].average);
    }

    // 打印成绩单
    cout << "===== 学生成绩单 =====" << endl;
    cout << "姓名\t语文\t数学\t英语\t平均\t等级" << endl;
    cout << string(50, '-') << endl;
    for (int i = 0; i < n; i++)
        printStudent(students[i]);

    // 找最优学生
    int best = findBest(students, n);
    cout << "\n最优学生:" << students[best].name
         << "(平均分:" << students[best].average << ")" << endl;

    // 保存到文件
    saveToFile(students, n, "grades.txt");

    return 0;
}

输出:

复制代码
===== 学生成绩单 =====
姓名    语文    数学    英语    平均    等级
--------------------------------------------------
张三    85      92      88      88.3333 B
李四    90      78      95      87.6667 B
王五    72      85      80      79      C
赵六    95      98      92      95      A

最优学生:赵六(平均分:95)
数据已保存到 grades.txt

📝 第7章知识点总结

知识点 核心要点
函数三要素 原型(声明)→ 定义(实现)→ 调用,原型让编译器做类型检查
按值传递 传递副本,函数内修改不影响原变量
数组参数 传递首元素地址,函数内可修改原数组,必须同时传入大小
const 参数 只读参数加 const,保护数据并明确意图
结构体参数 小结构体按值传递,大结构体用 const& 引用传递
函数指针 返回类型 (*ptr)(参数类型),可将函数作为参数传递
递归 必须有基准情形,每次调用向基准靠近,注意栈溢出
内联函数 inline 建议编译器展开,适合短小频繁调用的函数
引用参数 传递别名,函数内修改影响原变量,比指针更安全简洁
默认参数 从右向左设置,调用时可省略,通常在原型中声明
函数重载 同名不同参数,编译器根据参数类型自动选择版本
相关推荐
方也_arkling1 小时前
【Java-Day09】继承
java·开发语言
迈巴赫车主1 小时前
蓝桥杯21247弹跳鞋java
java·开发语言·数据结构·算法·职场和发展·蓝桥杯
kebeiovo1 小时前
C++与 Lua的交互
c++·lua
SoftLipaRZC2 小时前
C语言数据在内存中的存储:整型与浮点型的秘密
c语言·开发语言
悟乙己2 小时前
python DoWhy 库使用案例: SaaS 公司的客服案例
开发语言·python
就叫_这个吧2 小时前
JavaScript基础数据类型、运算符、数组、函数的定义及DOM方式应用
开发语言·前端·javascript
basketball6162 小时前
Golang:基本输入输出使用方法总结
开发语言·golang·xcode
Shingmc32 小时前
【Linux】多路转接之epoll
linux·运维·服务器·开发语言·网络
utf8mb4安全女神2 小时前
⽇志管理与深层防⽕墙
java·开发语言·spring boot