火龙信奥
  • 分享
  • 课程
  • 在线题库
  • CSES
    • GESP
    • CSP
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 知识课堂
  • 在线比赛
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

四级 - 结构体、高级排序与文件操作

作者: 作者的头像   huolong , 时间:2026-10-05 11:34:02 , 所有人可见, 阅读  10

CCF GESP 考级专项讲义:结构体、高级排序与文件操作


一、 结构体(struct)的定义与使用

在实际编程中,一个人的信息往往包含多种数据类型(年龄是整数、性别是布尔值、姓名是字符数组、体重是浮点数)。单纯用一维数组无法满足需求,此时必须使用结构体。

1. 结构体的定义

struct people {
    int age;          // 年龄
    bool sex;         // 性别(1代表男,0代表女)
    char name[100];   // 姓名
    double weight;    // 体重
};
  • 关键字:struct
  • 结构体变量声明:代码中定义了全局数组 people t[10];,代表最多可以存 10 个 people 对象。

二、 结合一维数组的输入输出与格式化函数

我们可以将结构体与一维数组结合,通过循环实现多组数据的批量读入与输出。

1. 使用 cin 读入多个数据

利用 for 循环和 cin,可以依次给数组中的每个结构体成员赋值:

for(int i = 0; i < 5; i++) {
    cin >> t[i].age >> t[i].sex >> t[i].name >> t[i].weight;
}

2. 编写独立的 print 函数输出信息(应用 const 引用)

为了让代码结构更清晰,我们可以把打印单个结构体信息的逻辑封装成一个函数。


三、 补充知识:函数参数的传递方式(重点:const 引用)

在处理结构体(struct)、类或大体积数据时,盲目使用“值传递”会复制整个结构体,造成内存和时间的浪费。

1. 引用传递(&)与常量引用(const)

  • 引用传递:在参数类型后加 &(如 people &p),函数内部操作的是实参本身,不发生数据复制。
  • const 修饰符:加上 const 后(如 const people &p),既享受了引用的高效(不复制),又保证了数据绝对安全(函数内无法修改 p 的成员)。

在 print 函数和 sort 的 cmp 函数中,我们强烈推荐使用 const 引用:

// 打印函数:使用常量引用,高效且安全
void print(const people &p) {
    cout << "==========个人信息=========" << endl;
    cout << "年龄:" << p.age << endl;
    cout << "性别:" << (p.sex == 1 ? "男" : "女") << endl; 
    cout << "姓名:" << p.name << endl;
    cout << "体重:" << p.weight << endl;
}

四、 sort 排序与自定义 cmp 函数(多关键字排序)

当我们需要对结构体数组进行排序时,必须通过自定义比较函数(cmp)来告诉 sort 排序规则。

多关键字排序(优先级排序)

在考试中经常遇到“先按条件A排序,如果条件A相同,再按条件B排序”的题型。 例如:要求先按年龄从大到小排序;如果年龄相同,则按体重从大到小排序。

// cmp 比较函数也必须使用 const 引用,保证效率和安全性
bool cmp1(const people &a, const people &b) {
    if(a.age != b.age) {
        return a.age > b.age; // 第一关键字:年龄不同,按年龄降序
    }
    return a.weight > b.weight; // 第二关键字:年龄相同,按体重降序
}
  • 调用方式:sort(t, t + 5, cmp1);

五、 freopen 文件重定向

在 GESP 考试中,有时需要从文件中读取数据,并输出到文件中。 * 语法:freopen("文件名", "模式", 标准流); * 模式:"r" 代表读(Read),"w" 代表写(Write)。 * 代码应用: cpp // 将标准输出重定向到 "个人信息.txt" 文件中 freopen("个人信息.txt", "w", stdout);


六、 完整综合代码总览

#include <bits/stdc++.h>
using namespace std;

struct people {
    int age;
    bool sex;
    char name[100];
    double weight;
} t[10];

// 使用 const 引用传递参数
void print(const people &p) {
    cout << "==========个人信息=========" << endl;
    cout << "年龄:" << p.age << endl;
    cout << "性别:" << (p.sex == 1 ? "男" : "女") << endl;
    cout << "姓名:" << p.name << endl;
    cout << "体重:" << p.weight << endl;
}

// 多关键字排序:年龄降序,年龄相同时体重降序
bool cmp1(const people &a, const people &b) {
    if(a.age != b.age) {
        return a.age > b.age;
    }
    return a.weight > b.weight;
}

int main() {
    freopen("个人信息.txt", "w", stdout);

    for(int i = 0; i < 5; i++) {
        cin >> t[i].age >> t[i].sex >> t[i].name >> t[i].weight;
    }

    sort(t, t + 5, cmp1);

    for(int i = 0; i < 5; i++) {
        print(t[i]);
    }

    return 0;
}

七、 课后巩固练习题

一、 选择题

1. 关于 C++ 中结构体(struct),以下说法错误的是? A. 结构体可以包含不同类型的数据成员(如 int, double, char 等)。
B. 结构体数组的一维数组下标也是从 0 开始的。
C. 结构体变量不能作为数组的元素。
D. 可以通过 . 运算符访问结构体变量中的成员。

2. 在编写 sort 函数的自定义比较函数 cmp 时,参数通常采用 const 结构体类型 &a, const 结构体类型 &b 的形式,这样做的好处不包括? A. 避免了结构体复制带来的内存和时间开销,提高程序运行效率。
B. 防止在比较函数内部不小心修改了原结构体的数据,保证安全性。
C. 可以让 sort 函数自动支持降序排序,不需要写具体的比较逻辑。
D. 语法规范,符合大对象传递的最佳实践。

3. 关于代码 freopen("output.txt", "w", stdout); 的作用,下列说法正确的是? A. 从 output.txt 文件中读取输入数据。
B. 将标准输出(如 cout 的内容)重定向写入到 output.txt 文件中。
C. 关闭文件输出流。
D. 清空屏幕上的所有显示内容。


二、 代码阅读题

阅读以下代码片段,并回答问题:

#include <iostream>
#include <algorithm>
using namespace std;

struct Student {
    int id;
    int score;
};

bool cmp(const Student &a, const Student &b) {
    if (a.score != b.score) {
        return a.score > b.score; // 成绩从高到低
    }
    return a.id < b.id; // 学号从低到高
}

int main() {
    Student s[3] = {{101, 85}, {102, 90}, {103, 85}};
    sort(s, s + 3, cmp);
    cout << s[0].id << " " << s[1].id << " " << s[2].id << endl;
    return 0;
}

问题: 1. 请问程序运行后,终端或输出文件中打印的结果是什么? 2. 在 cmp 函数中,如果将 return a.score > b.score; 改为 return a.score < b.score;,第一名(即排序后的第一个元素 s[0])会是谁(写出其学号)?


参考答案与解析

一、 选择题答案

  1. C
  2. 解析:结构体完全可以作为数组的元素(例如本文中的 people t[10];),因此选项 C 说法错误。
  3. C
  4. 解析:const 引用和降序逻辑无关,降序需要我们在函数内部明确写出 >. 选项 C 错误。
  5. B
  6. 解析:参数 "w" 代表 Write(写),stdout 代表标准输出。因此是将 cout 写入文件。

二、 代码阅读题答案

  1. 输出结果:102 101 103
  2. 解析:
    • 初始数据:{101, 85}, {102, 90}, {103, 85}。
    • 按 cmp 规则:先按分数从高到低排序。分数最高的是 102(90分),排在第一位。
    • 101 和 103 的分数相同(都是85分),触发第二关键字:学号从低到高排序。因此 101 排在 103 前面。
    • 排序后的顺序为:102 -> 101 -> 103。输出对应的 id 即为 102 101 103。
  3. 学号:101(或 103 中的一个,具体看谁分低)
  4. 解析:如果改成 a.score < b.score,则变成成绩从低到高排序。分数最低的是 85 分的 101 和 103。由于学号从小到大排,所以排在最前面 (s[0]) 的学号是 101。

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

关于火龙

  • 关于我们
  • 学员获奖
  • 预约试听
  • ACM课程
  • CSP课程
  • 学习指南

帮助中心

  • 用户协议
  • 打字练习 HOT
  • 在线画图
  • DevC++下载
  • CSP报名
  • GESP官网

推荐课程

  • C++零基础入门(可试看)
  • C++进阶提升
  • GESP考级辅导
  • GESP打卡
  • CSP-J/S打卡

公众号

火龙信奥公众号二维码

© 2017-2026 义乌市睿码科技有限公司版权所有 浙ICP备2021013995号

火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码