第6章 循环和关系表达式 循环语句的基本概念 循环语句用于重复执行一段代码,直到满足特定条件为止。C++提供了三种主要的循环语句:while、do-while和for。
while 循环 基本语法 执行流程 检查条件表达式 如果条件为真,执行循环体 重复步骤1和2,直到条件为假 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int sum = 0 ;int i = 1 ;while (i <= 100 ) { sum += i; i++; } std::cout << "Sum: " << sum << std::endl; int number;std::cout << "Enter numbers (0 to stop): " << std::endl; while (true ) { std::cin >> number; if (number == 0 ) { break ; } std::cout << "You entered: " << number << std::endl; }
do-while 循环 基本语法 1 2 3 do { } while (condition);
执行流程 执行循环体 检查条件表达式 如果条件为真,重复步骤1和2 如果条件为假,结束循环 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int sum = 0 ;int i = 1 ;do { sum += i; i++; } while (i <= 100 ); std::cout << "Sum: " << sum << std::endl; int age;do { std::cout << "Enter your age: " << std::endl; std::cin >> age; if (std::cin.fail ()) { std::cin.clear (); std::cin.ignore (std::numeric_limits<std::streamsize>::max (), '\n' ); std::cout << "Invalid input. Please try again." << std::endl; } } while (age < 0 || age > 120 ); std::cout << "Your age is: " << age << std::endl;
for 循环 基本语法 1 2 3 for (initialization; condition; update) { }
执行流程 执行初始化语句 检查条件表达式 如果条件为假,结束循环 如果条件为真,执行循环体 执行更新语句 重复步骤2到5 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int sum = 0 ;for (int i = 1 ; i <= 100 ; i++) { sum += i; } std::cout << "Sum: " << sum << std::endl; int arr[] = {1 , 2 , 3 , 4 , 5 };int size = sizeof (arr) / sizeof (arr[0 ]);for (int i = 0 ; i < size; i++) { std::cout << "arr[" << i << "] = " << arr[i] << std::endl; } for (int i = 1 ; i <= 9 ; i++) { for (int j = 1 ; j <= i; j++) { std::cout << j << "*" << i << "=" << i*j << "\t" ; } std::cout << std::endl; }
范围 for 循环(C++11+) 基本语法 1 2 3 for (declaration : collection) { }
示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 int arr[] = {1 , 2 , 3 , 4 , 5 };for (int num : arr) { std::cout << num << " " ; } std::cout << std::endl; std::vector<int > vec = {10 , 20 , 30 , 40 , 50 }; for (auto value : vec) { std::cout << value << " " ; } std::cout << std::endl; std::string str = "Hello" ; for (char c : str) { std::cout << c << " " ; } std::cout << std::endl; for (int & value : vec) { value *= 2 ; } for (const auto & value : vec) { std::cout << value << " " ; } std::cout << std::endl;
范围 for 循环的初始化语句(C++20+) C++20引入了范围for循环的初始化语句,允许在循环开始前声明和初始化变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 for (int i = 0 ; auto & num : vec) { std::cout << "Index " << i << ": " << num << std::endl; i++; } for (auto temp = createTemporaryData (); auto & item : temp) { processItem (item); } std::map<std::string, int > scores = { {"Alice" , 95 }, {"Bob" , 87 }, {"Charlie" , 92 } }; for (auto it = scores.begin (); auto & [name, score] : scores) { std::cout << "Rank " << std::distance (scores.begin (), it) + 1 << ": " << name << " - " << score << std::endl; ++it; }
范围 for 循环与结构化绑定(C++17+) 结合结构化绑定,范围for循环可以更方便地遍历键值对和复杂类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 std::map<std::string, int > scores = { {"Alice" , 95 }, {"Bob" , 87 }, {"Charlie" , 92 } }; for (const auto & [name, score] : scores) { std::cout << name << ": " << score << std::endl; } std::vector<std::tuple<std::string, int , double >> students = { {"Alice" , 20 , 3.8 }, {"Bob" , 21 , 3.5 }, {"Charlie" , 19 , 3.9 } }; for (const auto & [name, age, gpa] : students) { std::cout << "Name: " << name << ", Age: " << age << ", GPA: " << gpa << std::endl; } struct Point { int x; int y; }; std::vector<Point> points = { {1 , 2 }, {3 , 4 }, {5 , 6 } }; for (const auto & [x, y] : points) { std::cout << "Point: (" << x << ", " << y << ")" << std::endl; }
范围 for 循环与视图(C++20+) 结合C++20的Ranges库,范围for循环可以更灵活地处理数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <ranges> #include <vector> #include <iostream> int main () { std::vector<int > numbers = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; auto evenDoubled = numbers | std::views::filter ([](int n) { return n % 2 == 0 ; }) | std::views::transform ([](int n) { return n * 2 ; }); for (int num : evenDoubled) { std::cout << num << " " ; } auto reversed = numbers | std::views::reverse; for (int num : reversed) { std::cout << num << " " ; } auto sliced = numbers | std::views::drop (2 ) | std::views::take (5 ); for (int num : sliced) { std::cout << num << " " ; } return 0 ; }
循环控制语句 break 语句 break语句用于提前结束循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 std::vector<int > numbers = {10 , 50 , 150 , 200 , 250 }; for (int num : numbers) { if (num > 100 ) { std::cout << "First number greater than 100: " << num << std::endl; break ; } } for (int i = 0 ; i < 5 ; i++) { for (int j = 0 ; j < 5 ; j++) { if (i == 2 && j == 2 ) { std::cout << "Breaking at i=" << i << ", j=" << j << std::endl; break ; } std::cout << "i=" << i << ", j=" << j << std::endl; } }
continue 语句 continue语句用于跳过本次循环的剩余部分,直接进入下一次循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 for (int i = 1 ; i <= 10 ; i++) { if (i % 2 == 0 ) { continue ; } std::cout << i << " " ; } std::cout << std::endl; std::vector<int > numbers = {10 , -5 , 20 , -15 , 30 }; int sum = 0 ;for (int num : numbers) { if (num < 0 ) { continue ; } sum += num; } std::cout << "Sum of non-negative numbers: " << sum << std::endl;
goto 语句 goto语句可以无条件跳转到循环内的标签:
1 2 3 4 5 6 7 8 9 10 11 for (int i = 0 ; i < 5 ; i++) { for (int j = 0 ; j < 5 ; j++) { if (i == 2 && j == 2 ) { goto endLoop; } std::cout << "i=" << i << ", j=" << j << std::endl; } } endLoop: std::cout << "Loop ended" << std::endl;
注意 :尽量避免使用goto语句,因为它会使代码结构混乱。
关系表达式 关系运算符 运算符 描述 示例 结果 < 小于 5 < 3 false <= 小于等于 5 <= 5 true > 大于 5 > 3 true >= 大于等于 5 >= 10 false == 等于 5 == 5 true != 不等于 5 != 3 true
关系表达式的返回值 关系表达式返回布尔值:
1 2 3 4 5 6 7 8 9 10 bool result1 = (5 > 3 ); bool result2 = (5 == 3 ); bool result3 = (5 != 3 ); int a = 5 ;int b = 3 ;int result4 = (a > b); int result5 = (a < b);
关系运算符的优先级 关系运算符的优先级高于逻辑运算符(除了!),低于算术运算符:
1 2 3 bool result = (a + b > c && d - e < f);
循环的常见应用 1. 数值计算 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int factorial (int n) { int result = 1 ; for (int i = 1 ; i <= n; i++) { result *= i; } return result; } void printFibonacci (int n) { int a = 0 , b = 1 ; std::cout << "Fibonacci sequence: " ; for (int i = 0 ; i < n; i++) { std::cout << a << " " ; int next = a + b; a = b; b = next; } std::cout << std::endl; }
2. 数组和容器操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int findMax (const int arr[], int size) { int max = arr[0 ]; for (int i = 1 ; i < size; i++) { if (arr[i] > max) { max = arr[i]; } } return max; } std::string reverseString (const std::string& str) { std::string reversed; for (int i = str.length () - 1 ; i >= 0 ; i--) { reversed += str[i]; } return reversed; }
3. 输入验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int readInteger () { int value; while (true ) { std::cout << "Enter an integer: " ; std::cin >> value; if (std::cin.good ()) { break ; } std::cin.clear (); std::cin.ignore (std::numeric_limits<std::streamsize>::max (), '\n' ); std::cout << "Invalid input. Please try again." << std::endl; } return value; }
4. 图形输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 int height = 5 ;for (int i = 1 ; i <= height; i++) { for (int j = 1 ; j <= i; j++) { std::cout << "* " ; } std::cout << std::endl; } int size = 5 ;for (int i = 1 ; i <= size; i++) { for (int j = 1 ; j <= size - i; j++) { std::cout << " " ; } for (int j = 1 ; j <= 2 * i - 1 ; j++) { std::cout << "*" ; } std::cout << std::endl; } for (int i = size - 1 ; i >= 1 ; i--) { for (int j = 1 ; j <= size - i; j++) { std::cout << " " ; } for (int j = 1 ; j <= 2 * i - 1 ; j++) { std::cout << "*" ; } std::cout << std::endl; }
现代C++中的循环技巧 STL算法的使用 STL(标准模板库)提供了许多算法,可以替代传统的循环,使代码更简洁、更易读、更高效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <algorithm> #include <vector> #include <iostream> int main () { std::vector<int > numbers = {5 , 2 , 8 , 1 , 9 , 3 }; std::sort (numbers.begin (), numbers.end ()); auto it = std::find (numbers.begin (), numbers.end (), 5 ); if (it != numbers.end ()) { std::cout << "Found 5 at position: " << std::distance (numbers.begin (), it) << std::endl; } int count = std::count (numbers.begin (), numbers.end (), 3 ); std::cout << "Count of 3: " << count << std::endl; int evenCount = std::count_if (numbers.begin (), numbers.end (), [](int n) { return n % 2 == 0 ; }); std::cout << "Count of even numbers: " << evenCount << std::endl; std::vector<double > doubled (numbers.size()) ; std::transform (numbers.begin (), numbers.end (), doubled.begin (), [](int n) { return n * 2.0 ; }); int sum = std::accumulate (numbers.begin (), numbers.end (), 0 ); std::cout << "Sum: " << sum << std::endl; auto minIt = std::min_element (numbers.begin (), numbers.end ()); auto maxIt = std::max_element (numbers.begin (), numbers.end ()); std::cout << "Min: " << *minIt << ", Max: " << *maxIt << std::endl; return 0 ; }
并行算法(C++17+) C++17引入了并行算法,利用多核处理器提高性能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <algorithm> #include <execution> #include <vector> #include <iostream> int main () { std::vector<int > numbers (1000000 ) ; std::iota (numbers.begin (), numbers.end (), 1 ); std::sort (std::execution::par, numbers.begin (), numbers.end ()); std::vector<double > doubled (numbers.size()) ; std::transform (std::execution::par, numbers.begin (), numbers.end (), doubled.begin (), [](int n) { return n * 2.0 ; }); int sum = std::reduce (std::execution::par, numbers.begin (), numbers.end (), 0 ); std::cout << "Sum: " << sum << std::endl; return 0 ; }
范围库的使用(C++20+) C++20引入的范围库提供了更简洁、更灵活的循环方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <ranges> #include <vector> #include <iostream> int main () { std::vector<int > numbers = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; auto result = numbers | std::views::filter ([](int n) { return n % 2 == 0 ; }) | std::views::transform ([](int n) { return n * 2 ; }) | std::views::take (3 ); for (int num : result) { std::cout << num << " " ; } std::cout << std::endl; auto chained = numbers | std::views::reverse | std::views::filter ([](int n) { return n > 5 ; }) | std::views::transform ([](int n) { return n * n; }); for (int num : chained) { std::cout << num << " " ; } std::cout << std::endl; return 0 ; }
循环的最佳实践 1. 循环条件 明确的终止条件 :确保循环有明确的终止条件,避免无限循环避免复杂条件 :保持循环条件简单明了使用括号 :即使循环体只有一条语句,也使用大括号包围2. 循环变量 初始化 :在循环开始前正确初始化循环变量更新 :确保循环变量在每次迭代中正确更新作用域 :将循环变量的作用域限制在循环内部(使用for循环的初始化部分)3. 循环体 简洁 :保持循环体简洁,只包含与循环相关的代码单一职责 :每个循环只做一件事避免副作用 :循环体不应该修改循环条件中使用的外部变量(除非是有意的)4. 性能考虑 减少循环内计算 :将循环不变的计算移到循环外避免循环内的内存分配 :在循环外分配内存使用合适的循环类型 :根据具体情况选择while、do-while或for循环考虑使用STL算法 :对于常见的循环模式,使用STL算法考虑并行算法 :对于大型数据集,使用并行算法提高性能5. 可读性 缩进 :使用一致的缩进风格注释 :为复杂的循环添加注释,说明循环的目的变量命名 :使用有意义的变量名使用现代C++特性 :优先使用范围for循环、STL算法和范围库,提高代码可读性常见错误和陷阱 1. 无限循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 while (true ) { std::cout << "Hello" << std::endl; } for (int i = 0 ; i < 10 ; ) { std::cout << i << std::endl; } int i = 0 ;while (i < 10 ) { std::cout << i << std::endl; }
2. 循环变量的作用域 1 2 3 4 5 6 7 8 9 10 11 12 for (int i = 0 ; i < 10 ; i++) { std::cout << i << std::endl; } std::cout << "Final value of i: " << i << std::endl; int i;for (i = 0 ; i < 10 ; i++) { std::cout << i << std::endl; } std::cout << "Final value of i: " << i << std::endl;
3. 数组越界 1 2 3 4 5 6 7 8 9 10 int arr[5 ];for (int i = 0 ; i <= 5 ; i++) { arr[i] = i; } for (int i = 0 ; i < 5 ; i++) { arr[i] = i; }
4. 浮点数精度问题 1 2 3 4 5 6 7 8 9 10 11 12 double x = 0.1 ;while (x != 1.0 ) { std::cout << x << std::endl; x += 0.1 ; } while (x < 1.0 ) { std::cout << x << std::endl; x += 0.1 ; }
5. 循环内的条件判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int number = 5 ;while (number > 0 ) { std::cout << number << std::endl; if (number % 2 == 0 ) { number /= 2 ; } } while (number > 0 ) { std::cout << number << std::endl; if (number % 2 == 0 ) { number /= 2 ; } else { number -= 1 ; } }
小结 本章介绍了C++中的循环语句和关系表达式,包括:
while 循环 :先判断条件,再执行循环体do-while 循环 :先执行循环体,再判断条件for 循环 :适用于已知循环次数的情况范围 for 循环 :C++11引入,用于遍历容器和数组循环控制语句 :break、continue和goto关系表达式 :使用关系运算符比较值循环的常见应用 :数值计算、数组操作、输入验证等循环的最佳实践 :循环条件、循环变量、循环体、性能和可读性常见错误和陷阱 :无限循环、循环变量作用域、数组越界等循环是C++程序的重要组成部分,掌握好循环的使用方法对于编写高效、可靠的程序至关重要。在后续章节中,我们将学习更高级的C++特性,如数组、指针、类等,这些特性将与循环结合使用,帮助我们构建更复杂、更强大的程序。