学习方向: C++ / 数据结构基础
今日主题: 嵌套循环、变量初始化、累加与计数、指针遍历、条件判断
一、数字三角形与累加器
今天的第一道练习是使用两层 for 循环输出数字三角形,同时计算每行的数字之和与全部数字的总和。
输入:
4
预期输出:
1 行和:1
12 行和:3
123 行和:6
1234 行和:10
总和:20
1. 最初代码中的问题
最初使用了两个累加器:
int rowSum = 0;
int totalSum = 0;
循环主体:
for (int i = 1; i <= n; i++)
{
rowSum = i;
for (int k = 1; k <= i; k++)
{
cout << k << "行和:" << rowSum << endl;
totalSum += k;
}
}
外层和内层循环的条件都是正确的,但 rowSum 的赋值与输出语句的位置存在问题。
2. 修正后的完整代码
#include <iostream>
using namespace std;
int main()
{
int rowSum = 0;
int totalSum = 0;
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
rowSum = 0;
for (int k = 1; k <= i; k++)
{
cout << k;
rowSum += k;
totalSum += k;
}
cout << " 行和:" << rowSum << endl;
}
cout << "总和:" << totalSum << endl;
return 0;
}
3. 遇到的问题
问题一:混淆了赋值和累加
最初写的是:
rowSum = i;
这表示直接将当前行数赋值给 rowSum,而不是计算该行数字之和。
例如第三行输出 123,实际需要计算:
rowSum = 0 + 1 + 2 + 3 = 6
因此应该使用:
rowSum += k;
问题二:没有正确处理每行的初始化
rowSum 和 totalSum 的作用不同。
rowSum = 0;
应该放在外层循环内部、内层循环之前。
每开始新的一行,都重新计算这一行的总和。
但:
int totalSum = 0;
只需要在整个循环开始之前初始化一次。
因为 totalSum 要保存所有行的累计结果。
问题三:输出语句放错了位置
最初写的是:
cout << k << "行和:" << rowSum << endl;
并将其放在内层循环中。
这意味着每输出一个数字都会立即换行。
正确做法是先在内层循环中输出数字:
cout << k;
等内层循环全部结束,再输出当前行的总和:
cout << " 行和:" << rowSum << endl;
4. 理解与收获
这道题让我进一步理解了两个累加器的区别:
rowSum:保存当前行的总和,每行重新清零。totalSum:保存所有行的总和,始终累加。
同时,也需要特别注意循环体花括号的位置。
同样一条语句,放在内层循环中和放在内层循环结束后,执行次数可能完全不同。
二、数组平均值与条件统计
第二道练习主要巩固两个独立循环的执行顺序。
已知数组:
int arr[6] = {5, 9, 3, 11, 7, 13};
要求计算数组总和、平均值,并找出所有大于平均值的元素及其数量。
1. 修正后的完整代码
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
int arr[6] = {5, 9, 3, 11, 7, 13};
int sum = 0;
double average = 0;
int count = 0;
int find;
int* p = arr;
// 第一次循环:计算总和
for (int i = 0; i < 6; i++)
{
sum += *p;
p++;
}
// 计算平均值
average = static_cast<double>(sum) / std::size(arr);
// 将指针重新指向数组开头
p = arr;
cout << "总和:" << sum << endl;
cout << "平均数:" << average << endl;
// 第二次循环:筛选元素并计数
for (int i = 0; i < 6; i++)
{
find = *p;
if (find > average)
{
cout << "大于平均值的元素:" << find << endl;
count++;
}
p++;
}
cout << "元素个数:" << count << endl;
return 0;
}
输出:
总和:48
平均数:8
大于平均值的元素:9
大于平均值的元素:11
大于平均值的元素:13
元素个数:3
2. 遇到的问题
问题一:计数器未初始化
最初写的是:
int maxvalue, find;
之后直接执行:
maxvalue++;
问题在于 maxvalue 没有初始值。
对于这里的局部变量,读取未初始化的 int 会产生不可靠的程序行为。
正确写法:
int count = 0;
因为程序需要从零开始统计满足条件的元素数量。
另外,原来的 maxvalue 名称容易让人误认为它用于保存最大值,修改为 count 更符合其实际用途。
问题二:平均值计算中存在整数除法问题
最初写的是:
double average = 0;
average = sum / std::size(arr);
虽然 average 是 double,但除法两侧均为整数类型,计算时会先执行整数除法。
例如:
int sum = 10;
double average = sum / 3;
得到的是 3.0,而不是 3.333...。
正确做法:
average = static_cast<double>(sum) / std::size(arr);
这样可以在除法之前把一个操作数转换为浮点数。
3. 本次已经正确掌握的内容
相比昨天相似的题目,这次有几处明显改进。
第一:两个循环不再错误嵌套。
for (int i = 0; i < 6; i++)
{
sum += *p;
p++;
}
average = static_cast<double>(sum) / std::size(arr);
p = arr;
for (int i = 0; i < 6; i++)
{
// 比较与计数
}
这次已经能正确安排:
第一次循环
↓
计算平均值
↓
重置指针
↓
第二次循环
第二:正确重置了指针。
p = arr;
由于第一次遍历中使用了 p++,指针已经移动到了数组末尾之后的位置。
第二次遍历前,必须让它重新指向数组首元素。
第三:条件判断正确。
if (find > average)
这次已经能够正确地比较当前数组元素与平均值,不再混淆计数器与被比较的值。
4. 理解与收获
这道题进一步强化了:
- 两个独立循环的执行顺序。
p++对指针位置的影响。- 指针重置。
- 计数器初始化。
- 整数除法与浮点除法的区别。
与之前相比,程序整体结构已经更加合理,主要问题集中在变量初始化和数据类型转换方面。
三、正数、负数的分类统计
第三道题要求在一次循环中完成多个统计任务。
给定数组:
int arr[8] = {-3, 5, 0, -7, 12, 8, -2, 4};
需要计算:
- 正数个数。
- 负数个数。
- 正数总和。
- 负数总和。
其中,0 既不是正数,也不是负数。
1. 最初代码中的问题
这道题一开始已经正确初始化了所有统计变量:
int Positive = 0;
int Negative = 0;
int Psum = 0;
int Nsum = 0;
随后使用:
value = *p;
读取当前数组元素。
正数判断部分:
if (value > 0)
{
Psum += value;
Positive++;
}
这一部分完全正确。
但是负数判断写成了:
else(value < 0);
{
Nsum += value;
Negative++;
}
这里出现了 else 语法使用错误。
2. 修正后的完整代码
#include <iostream>
using namespace std;
int main()
{
int arr[8] = {-3, 5, 0, -7, 12, 8, -2, 4};
int* p = arr;
int Positive = 0;
int Negative = 0;
int Psum = 0;
int Nsum = 0;
int value;
for (int i = 0; i < 8; i++)
{
value = *p;
if (value > 0)
{
Psum += value;
Positive++;
}
else if (value < 0)
{
Nsum += value;
Negative++;
}
p++;
}
cout << "正数个数:" << Positive << endl;
cout << "负数个数:" << Negative << endl;
cout << "正数总和:" << Psum << endl;
cout << "负数总和:" << Nsum << endl;
return 0;
}
输出:
正数个数:4
负数个数:3
正数总和:29
负数总和:-12
3. 遇到的问题
问题一:混淆 else 和 else if
最初写的是:
else(value < 0);
但 else 后面不能直接附加判断条件。
如果需要判断第二种情况,应使用:
else if (value < 0)
完整结构:
if (条件1)
{
// 条件1成立时执行
}
else if (条件2)
{
// 条件1不成立且条件2成立时执行
}
else
{
// 前面的条件都不成立时执行
}
本题中不需要最后的 else,因为数组元素为 0 时,不应该更新任何正负数统计变量。
问题二:多余的分号可能破坏条件判断
原来的:
else(value < 0);
{
Nsum += value;
Negative++;
}
可以被 C++ 解释为 else 执行一个表达式语句,而后面的 {} 成为独立代码块。
结果负数统计代码不再受 else 控制,每次循环都会执行。
对于当前数组,如果保留原写法,负数计数会变成 8,负数总和会变成 17,而不是正确的 3 和 -12。
因此需要特别注意条件判断语句中的分号和花括号。
4. 本题的进步
相比前两道题,这次所有计数器和累加器都正确初始化为 0。
另外,已经能够在一个循环中同时完成四项统计:
Psum += value;
Positive++;
Nsum += value;
Negative++;
其中:
Psum:累加正数的值。Positive:统计正数出现的次数。Nsum:累加负数的值。Negative:统计负数出现的次数。
这说明对累加器和计数器的区别已经有了更明确的认识。
四、今日知识点总结
for嵌套循环外层控制整体重复,内层执行具体操作rowSum = 0每行重新初始化当前行的总和totalSum += k保留并更新全部行的累计值count++统计满足条件的元素个数sum += *p将指针指向的元素累加p++将指针移动到下一个元素p = arr重置指针,使其指向数组首元素if / else if按条件执行不同的代码分支static_cast<double>()显式转换数据类型std::size(arr)获取固定数组的元素数量五、三次 Coding 训练进度对比
Day 1|11 月 8 日
主要内容:
- 偶数统计与累加。
- 嵌套循环数字三角形。
- 指针遍历数组。
- 使用指针寻找最大值。
主要问题:
- 不熟悉累加表达式。
- 嵌套循环难以独立编写。
- 多次出现
i <= 5的越界错误。 - 刚开始理解
*(p + i)与p++。
Day 2|11 月 10 日
主要内容:
- 指针寻找最小值及下标。
- 双指针反转数组。
- 数组平均值与条件统计。
进步:
- 循环边界明显改善。
- 独立完成双指针数组反转。
- 掌握
while (left < right)的基本应用。 - 能够使用多个变量进行统计。
主要问题:
- 变量初始化容易遗漏。
- 多个独立循环容易错误地嵌套。
- 平均值计算和变量更新顺序不够清晰。
Day 3|11 月 11 日
主要内容:
- 嵌套循环与双累加器。
- 两次数组遍历与平均值统计。
- 一次遍历完成正负数分类统计。
进步:
- 能够独立编写正确的嵌套循环结构。
- 能够正确使用两个顺序执行的循环。
- 能够主动重置指针。
- 能够在一个循环中完成多个统计任务。
- 第三题的计数器和累加器全部正确初始化。
仍然存在的问题:
- 累加器清零的位置。
- 输出语句所属的循环层级。
- 少数变量初始化遗漏。
else if等条件判断语法。- 整数除法与浮点除法的区别。
六、下一阶段学习计划
下一次计划进行 Day 4:循环与指针综合测验。
不再提前提供完整代码框架,主要检查能否独立实现以下内容:
- 使用嵌套循环完成输出与累加。
- 使用数组和指针完成多条件统计。
- 正确初始化并更新多个变量。
- 独立确定循环边界和执行顺序。
- 避免指针越界和错误的数据类型转换。
测验重点不是掌握多少新的语法,而是能否在没有提示的情况下,把已经学过的知识组织成一个完整程序。
通过基础综合测试后,下一阶段将进入数据结构中的单链表,进一步学习节点、指针连接、遍历和插入操作。
七、今日总结
今天的三道题中,第一题的主要问题是行累加器与输出位置;第二题的程序结构已经基本正确,仅存在计数器初始化和整数除法问题;第三题的核心算法正确,只出现了 else if 语法错误。
相比第一次训练,已经不再频繁出现数组遍历边界错误,也能够更熟练地使用指针进行数组操作。
目前最大的不足已经从单个语法概念转向了多步骤算法的组织、变量状态管理以及代码细节检查。
接下来的训练应继续坚持独立编写,并重点检查每个变量的初始化、每一层循环的职责以及条件判断是否正确。
学习原则:原理理解 → 独立 Coding → 调试纠错 → 总结记录 → 综合应用。