新闻详情

新闻详情

首页 / 资讯中心 / 详情

【C++ 学习日记 · 9月25日】二维数组、函数、指针三件套,外加两道小鱼算法题

发布时间:2026/9/26 2:08:25来源:尧图网络
【C++ 学习日记 · 9月25日】二维数组、函数、指针三件套,外加两道小鱼算法题
摘要9 月 25 日的 C 学习记录。今天集中攻克三个基础模块——二维数组、函数封装、指针操作把 4 个练习程序全部手敲并跑通最后刷了两道小鱼系列算法题双休游泳里程、游泳用时计算。本文包含完整可运行代码、样例手推过程、复杂度分析以及我实际踩到的 5 个坑。0. 今天干了什么先上清单方便复盘序号模块具体内容代码文件1二维数组3×3 矩阵的输入与求和、行主序内存布局10.cpp2函数冒泡排序与数组打印的函数封装、数组参数退化maopaopaixu.cpp3指针指针遍历数组、const与指针、值传递 vs 指针传递zzhsz.cpp、zhizheng.cpp、zzhhs.cpp4算法题小鱼游泳双休版、小鱼游泳时间8.cpp、9.cpp环境VS Code MinGW-w64 的g工作目录C:\Users\ASUS\Desktop\vs。1. 二维数组3×3 矩阵求和1.1 题目读入一个 3×3 的整数矩阵输出它们的元素之和。1.2 我的代码10.cppcpp复制#include iostream using namespace std; int main() { int s[3][3]; for (int i 0; i 3; i) { for (int j 0; j 3; j) { cin s[i][j]; } } int sum 0; for (int i 0; i 3; i) { for (int j 0; j 3; j) { sum s[i][j]; } cout sum endl; } return 0; }1.3 二维数组的本质数组的数组int s[3][3]不是3 乘 3 的表格而是长度为 3 的数组每个元素是int[3]。所以s[i]的类型是int[3]s[i][j]的类型才是int下标写法s[i][j]完全等价于指针写法*(*(s i) j)在内存里它是连续的行主序排列s[0][0] s[0][1] s[0][2] s[1][0] ... s[2][2]一共 9 个int紧挨着放。这一点在后面讲指针遍历时会用到。顺便sizeof(s)是3 * 3 * 4 36字节sizeof(s[0])是 12 字节sizeof(s[0][0])是 4 字节。1.4 复盘一个很隐蔽的没清零逻辑问题上面这段代码如果输入复制1 2 3 4 5 6 7 8 9实际输出是复制6 21 45而不是我原本以为的45。原因在于sum定义在外层循环之外而cout放在了外层循环之内——于是它打印的不是每行之和而是前 i 行的累计和第一轮1236第二轮6(456)61521第三轮21(789)212445。也就是说第一次循环结束时sum是 6第二次结束是 21所以中间的21看起来既不像行和15也不像总和45非常容易让人误以为是算错了。这个 bug 很有意思代码语法完全正确编译零警告但语义和我的意图不一致。它逼我想清楚了变量该定义在哪个作用域这个平时被忽略的问题。版本 A只求总和推荐cpp复制int sum 0; for (int i 0; i 3; i) for (int j 0; j 3; j) sum s[i][j]; cout sum endl; // 输出 45版本 B每行求和sum必须在外层循环内部清零cpp复制for (int i 0; i 3; i) { int sum 0; // ← 关键每进入新的一行就归零 for (int j 0; j 3; j) { sum s[i][j]; } cout 第 i 1 行之和 sum endl; }配图位置 1贴10.cpp的编辑器截图。1.5 小结二维数组的遍历一定要外层行、内层列顺序写反不会报错但缓存友好度差很多累加器变量的作用域就是它应当被清零的边界cout放循环里还是循环外决定了输出过程值还是最终值。2. 函数把重复逻辑装进盒子2.1 冒泡排序封装maopaopaixu.cppcpp复制#include bits/stdc.h using namespace std; void buccleSort(int *arr, int len) { for (int i 0; i len - 1; i) { for (int j 0; j len - i - 1; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } } void printArray(int *arr, int len) { for (int i 0; i len; i) { cout arr[i] ; } cout endl; } int main() { int arr[10] {4, 5, 6, 4, 5, 3, 23, 45, 65, 34}; int len sizeof(arr) / sizeof(arr[0]); buccleSort(arr, len); printArray(arr, len); return 0; }运行结果复制3 4 4 5 5 6 23 34 45 652.2 三个必须记住的要点要点一数组作参数会退化成指针。void buccleSort(int *arr, int len)里的arr已经不是数组了而是一个int *指针。所以函数内部sizeof(arr)得到的是指针的大小64 位下 8 字节不是 40 字节sizeof(arr) / sizeof(arr[0])在函数里会算出8 / 4 2这是一个经典到可以进教科书的错误。所以长度必须由调用方显式传进来这就是len参数存在的唯一理由。位置sizeof(arr)sizeof(arr)/sizeof(arr[0])main中的int arr[10]4010 ✅函数参数int *arr82 ❌要点二函数参数是值传递。arr这个指针是按值复制进来的函数里改arr arr 1不影响外面。但arr[j] ...改的是指针指向的内存那块内存在main的栈上所以外面的数组真的被改动了。这是值传递却修改了实参的唯一解释改的不是指针是指针指的东西。要点三取名要准。函数名buccleSort我敲错了正确拼写是bubbleSort冒泡。虽然不影响运行但一周后回看会很别扭当场改掉cpp复制void bubbleSort(int *arr, int len)2.3 一个小优化冒泡排序最好的情况已经有序本可以只跑一趟。加一个flag就实现了提前退出cpp复制void bubbleSort(int *arr, int len) { for (int i 0; i len - 1; i) { bool swapped false; for (int j 0; j len - i - 1; j) { if (arr[j] arr[j 1]) { swap(arr[j], arr[j 1]); // 标准库自带 swap swapped true; } } if (!swapped) break; // 本轮无交换 → 已经有序 } }最坏 / 平均时间复杂度O(n²)最好情况已有序O(n)空间复杂度O(1)原地排序稳定性相等元素不交换稳定排序配图位置 2贴maopaopaixu.cpp的编辑器截图。3. 指针C 的分水岭3.1 数组名就是首元素地址zzhsz.cppcpp复制#include bits/stdc.h using namespace std; int main() { int arr[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout 第一个元素为 arr[0] endl; int *p arr; // 数组名退化为首元素地址 cout 利用指针访问第一个元素为 *p endl; p; // 指针后移一个 int4 字节 cout 利用指针访问第二个元素为 *p endl; cout 利用指针遍历数组为 endl; int *p2 arr; for (int i 0; i 10; i) { // cout arr[i] endl; // 下标法等价写法 cout *p2 endl; // 指针法 p2; } return 0; }输出复制第一个元素为1 利用指针访问第一个元素为1 利用指针访问第二个元素为2 利用指针遍历数组为 1 2 ... 10三个关键结论arr在表达式中会隐式转换为arr[0]所以int *p arr;合法p不是加 1 字节而是加sizeof(int) 4字节——指针的算术运算自带类型步长循环里的*p2与arr[i]完全等价arr[i]就是*(arr i)的语法糖。3.2const与指针的三种组合zhizheng.cppcpp复制#include bits/stdc.h using namespace std; int main() { int a 10; int b 20; const int *p a; // p 指向const int即 *p 不能被改 p b; // 但 p 自己可以被改指向别处 cout *p endl; // 输出 20 return 0; }输出20。这说明const int *p里const修饰的是*p不是p。三种组合一定要分清口诀是const 在*左边管值在*右边管指针写法能否改*p能否改p记忆const int *p等价int const *p❌✅指向常量的指针int * const p✅❌指针常量必须在定义时初始化const int * const p❌❌都锁死const int *p最常见的用途是函数参数void print(const int *arr, int len)—— 向调用者承诺我只读不改你的数组同时让函数能接收const数组。配图位置 3贴zhizheng.cpp的编辑器截图以及终端输出20的那一屏。3.3 值传递 vs 指针传递zzhhs.cpp—— 今天最有收获的一段cpp复制#include bits/stdc.h using namespace std; void swap01(int a, int b) { // 值传递操作的是副本 int temp a; a b; b temp; cout a a endl; // 10 20 → 这里打印 20 cout b b endl; // 这里打印 10 } void swap02(int *a, int *b) { // 指针传递操作的是原变量 int temp *a; *a *b; *b temp; cout *a *a endl; cout *b *b endl; } int main() { int a 10; int b 20; swap01(a, b); cout a a endl; // 仍然是 10 ← 没换成功 cout b b endl; // 仍然是 20 swap02(a, b); cout a a endl; // 20 ← 成功 cout b b endl; // 10 }实际输出共 8 行复制a20 ← swap01 内部副本被换过来了 b10 a10 ← 回到 main原变量纹丝不动 b20 *a20 ← swap02 内部通过地址改的就是本体 *b10 a20 ← 回到 main真的换成了 b10swap01是最典型的看起来成功了陷阱函数内部打印的确是交换后的结果很容易让人以为大功告成但一出函数main里的a、b纹丝不动。因为swap01拿到的是两个副本副本怎么折腾都与本体无关。内存层面的解释swap01(a, b)形参a、b是main里a、b的拷贝各自占独立内存。交换副本本体不动。swap02(a, b)传进去的是地址。形参*a解引用后直接命中main的变量*a *b改的是本体内存所以真的换成了。延伸C 更推荐的写法是引用。cpp复制void swap03(int a, int b) { // 引用实参的别名无需解引用 int temp a; a b; b temp; } // 调用swap03(a, b); —— 和值传递写法一样干净但真的能改引用写法兼具指针的能力和值传递的简洁这也是为什么 C 标准库的std::swap用的是引用。配图位置 4贴zzhhs.cpp的编辑器截图含swap01/swap02两段。3.4 顺手解决的一个环境问题终端中文乱码在 VS Code 的 PowerShell 终端里跑zzhsz.exe中文输出会变成乱码类似掰弯弯 消回匣 ...这种。原因是源码是 UTF-8而 Windows 终端默认是 GBK代码页 936。三种解决办法临时先执行chcp 65001切到 UTF-8 代码页一劳永逸在 VS Code 的settings.json里设置terminal.integrated.defaultProfile.windows对应的 profile 参数或直接在终端配置里加chcp 65001学习阶段最省事调试输出先用英文等逻辑跑通再换中文。编译运行的命令也记一下powershell复制g zzhsz.cpp -o zzhsz # 编译 .\zzhsz # 运行PowerShell 里必须带 .\4. 算法题一小鱼游泳双休版4.1 题目有一只小鱼它平日每天游泳 250 公里周末休息实行双休日。假设从周 x 开始算起过了 n 天以后小鱼一共累计游泳了多少公里输入两个正整数x, n1 ≤ x ≤ 71 ≤ n ≤ 10⁶表示从周 x 算起经过 n 天。输出一个整数表示累计游泳公里数。样例输入3 10→ 输出2000。4.2 解法一模拟8.cppcpp复制#include bits/stdc.h using namespace std; int main() { int x, n; cin x n; int ans 0; for (int i 0; i n; i) { int day (x i - 1) % 7 1; // 1~7 表示 周一~周日 if (day ! 6 day ! 7) { // 6,7 为周六、周日 ans 250; } } cout ans endl; return 0; }核心就一行(x i - 1) % 7 1。i 0时结果是(x - 1) % 7 1 x对得上起点当x 7周日时(7 - 1) % 7 1 7不会溢出成 0也不会变成 8。这个先减一、取模、再加一的写法是把1~7这种 1-based 循环编号映射到[0, 6]的通用套路值得背下来。样例手推x 3 表示周三n 10i0123456789星期三四五六日一二三四五是否游泳✅✅✅❌❌✅✅✅✅✅共 8 天游泳8 × 250 2000与样例一致。复杂度时间O(n)n ≤ 10⁶完全够用空间O(1)。4.3 解法二数学法O(1)把这 n 天拆成完整的周 零头每 7 天必定是 5 个工作日零头最多 6 天直接枚举零头即可。cpp复制#include bits/stdc.h using namespace std; int main() { int x, n; cin x n; int start (x - 1) % 7; // 0周一 ... 6周日 long long weeks n / 7; int rem n % 7; long long ans weeks * 5LL * 250; // 每个完整周 5 天 for (int i 0; i rem; i) { // 零头最多 6 天 if ((start i) % 7 5) ans 250; } cout ans endl; return 0; }为什么不直接用闭式公式因为零头里有几个工作日要分start落在周一~周五还是周末讨论很容易写错边界。枚举至多 6 次既保证O(1)又不需要分类讨论——这是竞赛里非常实用的常数级枚举替代分类讨论技巧。两种解法对比解法时间复杂度空间复杂度适用场景逐天模拟O(n)O(1)n 小时最直观不易错整周 零头O(1)O(1)n 很大如 10¹⁸时必须用为了确认两种解法完全等价我把它们写成两个函数做了对拍枚举x 1…7、n 1…2000共14000 组数据不一致数为 0另外x 1, n 10⁶时两者都得178571500。写题时养成换一种思路验证一遍的习惯比对着样例改半天靠谱得多。4.4 易错点周末是周六 周日两天别只减一天x的起点是从周 x 算起也就是第 1 天就是周 x不是从周 x 的第二天算起ans最大约2.5 × 10⁸int装得下int上限约2.1 × 10⁹但数据范围一旦放大到10¹⁸就必须用long long养成习惯更好。5. 算法题二小鱼游泳时间5.1 题目小鱼从a时b分一直游泳到当天的c时d分24 小时制求它这天一共游了多少小时多少分钟。输入一行四个整数a, b, c, d。输出两个整数e和f依次表示小时数和分钟数其中f 60。样例输入12 50 19 10→ 输出6 20。数据范围0 ≤ a, c ≤ 240 ≤ b, d ≤ 60且结束时间一定晚于开始时间。5.2 代码9.cppcpp复制#include bits/stdc.h using namespace std; int main() { int a, b, c, d; cin a b c d; int num1, num2; num1 a * 60 b; // 开始时刻转成从 0 点起的分钟数 num2 c * 60 d; // 结束时刻同样转成分钟数 int ans num2 - num1; // 总时长分钟 cout ans / 60 ans % 60 endl; return 0; }5.3 思路统一单位时间差问题的通用套路是先化成同一个最小单位算完再拆回去把a 时 b 分化成a * 60 b分钟两个分钟数相减得到总分钟数ansans / 60取整数商 小时数整数除法自动向下取整ans % 60取余 剩余分钟数天然满足f 60。样例验证12:50 → 12 × 60 50 77019:10 → 19 × 60 10 11501150 - 770 380分钟380 / 60 6380 % 60 20输出6 20与样例一致 ✅5.4 易错点别用(c - a)和(d - b)分开算样例里19 - 12 7小时、10 - 50 -40分钟还得处理借位非常容易写错。统一成分钟就完全没有借位问题ans / 60与ans % 60的顺序必须都基于同一个原始ans计算不能先算/再用结果算%输出格式两个数之间一个空格题目特别强调f 60这正好是取模运算免费带来的保证本题保证结束时间晚于开始时间所以不用处理跨天。但如果遇到c a的跨天情况只需补一句if (num2 num1) num2 24 * 60;。6. 今日踩坑清单Top 5#坑现象修复1累加器作用域放错矩阵求和输出6 / 15 / 45而非45明确清零边界整体求和放循环外按行求和放循环内2函数里算数组长度sizeof(arr)/sizeof(arr[0])在函数内得到 2数组作参数会退化为指针长度必须显式传参3误以为swap01交换成功函数内打印已交换main里没变值传递只操作副本改用指针或引用4误读const int *p以为p b会编译报错const修饰*pconst在*左边管值右边管指针5终端中文乱码输出掰弯弯 消回匣 ...chcp 65001或调试期先用英文输出7. 知识点速查二维数组s[i][j]≡*(*(s i) j)内存行主序连续遍历顺序先行后列累加器清零边界 它的作用域。函数数组作参数退化为指针长度必须显式传递C 参数默认值传递要改实参用指针或引用推荐引用函数名/变量名拼写要准bubbleSort不是buccleSort。指针数组名退化为首元素地址p按sizeof(T)步进const int *p/int * const p/const int * const p三者含义不同指针传参能改实参是因为改的是指向的内存而不是指针本身。算法1-based 循环编号映射(x i - 1) % 7 1时间差统一换算成最小单位分钟再拆回n很大时用整周期 零头枚举把O(n)降到O(1)。8. 明日计划把bubbleSort的flag优化版重写一遍并用随机数据对拍验证学const引用const int 把printArray改成更安全的void printArray(const int *arr, int len)用指针重写二维数组的遍历*(*(s i) j)形式加深数组的数组这一层理解再刷 2 道循环 / 模拟类入门题重点练周期拆分这个套路。本文为个人 C 学习记录。全部代码均在本地 MinGW-w64g 16.1.0-stdc17下编译运行通过文中的输入输出结果为实际运行结果两道算法题的双解法已做 14000 组数据对拍验证。若有错误或更好的写法欢迎在评论区指出一起进步 标签建议C二维数组指针函数算法入门学习笔记
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

PostgreSQL日志分析器pgBadger:从慢SQL排查到性能调优实践指南 2026/9/26 2:51:27

PostgreSQL日志分析器pgBadger:从慢SQL排查到性能调优实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Skills CLI 速用手册:用 TaoToken 统一 Key 跑通 Agent Skills 配置 2026/9/26 2:51:27

Skills CLI 速用手册:用 TaoToken 统一 Key 跑通 Agent Skills 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
开放数据平台用户信息表设计:字段、索引与扩展性实战 2026/9/26 2:51:27

开放数据平台用户信息表设计:字段、索引与扩展性实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
热缩冷胀隔圈原理与工程应用:光学系统温漂被动补偿技术 2026/9/26 2:51:27

热缩冷胀隔圈原理与工程应用:光学系统温漂被动补偿技术

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
MADDPG多智能体博弈对抗:原理、Python实现与避坑指南 2026/9/26 2:51:20

MADDPG多智能体博弈对抗:原理、Python实现与避坑指南

简介:面向多智能体博弈对抗研究,该资源提供基于MADDPG算法的Python完整实现,适用于计算机、人工智能、通信工程、自动化等专业的毕业设计、课程设计与期末大作业。项目代码包含算法核心模块、神经网络构建、经验回放缓冲区、训练主程序与测试…

阅读更多 →
QGIS工具栏面板不见了?三步找回与防止界面丢失全指南 2026/9/26 2:51:20

QGIS工具栏面板不见了?三步找回与防止界面丢失全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉