当前位置: 首页 > news >正文

C++学习:六个月从基础到就业——C++基础语法回顾:控制流语句

C++学习:六个月从基础到就业——C++基础语法回顾:控制流语句

本文是我C++学习之旅系列的第三篇技术文章,主要回顾C++中的控制流语句,包括条件语句、循环语句以及跳转语句,并分享一些实用技巧和最佳实践。查看完整系列目录了解更多内容。

引言

控制流语句是编程语言的核心组成部分,它们决定了程序执行的路径和顺序。无论是简单的判断、重复执行特定代码块,还是在特定条件下跳转到程序的其他部分,控制流语句都扮演着至关重要的角色。本文将详细介绍C++中的各种控制流语句,包括条件语句、循环语句和跳转语句,并提供一些实用的编程技巧和最佳实践。

条件语句

条件语句允许程序根据条件的真假来决定执行哪段代码。C++提供了多种条件语句,包括if语句、if-else语句、if-else if-else语句和switch语句。

if语句

if语句是最基本的条件语句,当条件为真时执行指定的代码块:

if (condition) {
    // 当condition为真时执行的代码
}

示例:

int age = 20;
if (age >= 18) {
    std::cout << "您已成年,可以投票。" << std::endl;
}

注意:虽然当代码块只有一行时可以省略花括号,但为了代码的可读性和避免潜在的错误,建议始终使用花括号。

if-else语句

if-else语句在条件为真时执行一个代码块,在条件为假时执行另一个代码块:

if (condition) {
    // 当condition为真时执行的代码
} else {
    // 当condition为假时执行的代码
}

示例:

int age = 16;
if (age >= 18) {
    std::cout << "您已成年,可以投票。" << std::endl;
} else {
    std::cout << "您未成年,不能投票。" << std::endl;
}

if-else if-else语句

if-else if-else语句用于测试多个条件,并在满足第一个为真的条件时执行相应的代码块:

if (condition1) {
    // 当condition1为真时执行的代码
} else if (condition2) {
    // 当condition1为假且condition2为真时执行的代码
} else {
    // 当所有条件都为假时执行的代码
}

示例:

int score = 85;
if (score >= 90) {
    std::cout << "优秀" << std::endl;
} else if (score >= 80) {
    std::cout << "良好" << std::endl;
} else if (score >= 60) {
    std::cout << "及格" << std::endl;
} else {
    std::cout << "不及格" << std::endl;
}

嵌套if语句

在C++中,可以在一个if或else语句内部嵌套另一个if或else语句:

if (condition1) {
    if (condition2) {
        // 当condition1和condition2都为真时执行的代码
    } else {
        // 当condition1为真但condition2为假时执行的代码
    }
} else {
    // 当condition1为假时执行的代码
}

示例:

int age = 20;
bool hasID = true;

if (age >= 18) {
    if (hasID) {
        std::cout << "您可以进入。" << std::endl;
    } else {
        std::cout << "请出示您的身份证。" << std::endl;
    }
} else {
    std::cout << "未成年人不得入内。" << std::endl;
}

条件运算符(三元运算符)

条件运算符是if-else语句的简写形式,特别适用于简单的条件判断:

condition ? expression1 : expression2;

如果条件为真,整个表达式的值为expression1;如果条件为假,整个表达式的值为expression2。

示例:

int age = 20;
std::string status = (age >= 18) ? "成年" : "未成年";
std::cout << "状态:" << status << std::endl;

嵌套条件运算符

条件运算符可以嵌套使用,但可能会降低代码的可读性:

int score = 85;
std::string grade = (score >= 90) ? "A" : 
                    (score >= 80) ? "B" : 
                    (score >= 70) ? "C" : 
                    (score >= 60) ? "D" : "F";

在复杂条件判断中,使用if-else if-else语句通常更为清晰。

switch语句

switch语句提供了一种根据表达式的值选择多个代码路径的方法:

switch (expression) {
    case constant1:
        // 当expression等于constant1时执行的代码
        break;
    case constant2:
        // 当expression等于constant2时执行的代码
        break;
    // 更多case语句
    default:
        // 当expression不匹配任何常量时执行的代码
        break;
}

示例:

int day = 3;
switch (day) {
    case 1:
        std::cout << "星期一" << std::endl;
        break;
    case 2:
        std::cout << "星期二" << std::endl;
        break;
    case 3:
        std::cout << "星期三" << std::endl;
        break;
    case 4:
        std::cout << "星期四" << std::endl;
        break;
    case 5:
        std::cout << "星期五" << std::endl;
        break;
    case 6:
        std::cout << "星期六" << std::endl;
        break;
    case 7:
        std::cout << "星期日" << std::endl;
        break;
    default:
        std::cout << "无效的日期" << std::endl;
        break;
}

注意事项

  1. break语句:每个case后面的break语句是必要的,除非您希望执行"贯穿"多个case。没有break语句,控制流将会"贯穿"到下一个case,直到遇到break或switch语句结束。
int day = 3;
switch (day) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        std::cout << "工作日" << std::endl;
        break;
    case 6:
    case 7:
        std::cout << "周末" << std::endl;
        break;
    default:
        std::cout << "无效的日期" << std::endl;
        break;
}
  1. default语句:default语句是可选的,但建议始终包含它以处理未预期的情况。

  2. 表达式类型:switch表达式必须是整数类型(包括枚举)或可以隐式转换为整数类型的值。

  3. case常量:case标签必须是常量表达式,不能是变量或函数调用结果。

C++17的增强:带初始化的if和switch语句

从C++17开始,if和switch语句可以包含一个初始化语句,类似于for循环:

if (initialization; condition) {
    // 代码
}

switch (initialization; expression) {
    // case语句
}

这种语法允许您在条件检查的范围内创建临时变量,提高了代码的局部性和可读性:

// C++17之前
{
    auto result = getValue();
    if (result.success()) {
        useValue(result.value());
    }
}

// C++17
if (auto result = getValue(); result.success()) {
    useValue(result.value());
}

使用switch的示例:

switch (auto value = getUserInput(); value) {
    case 1:
        processOption1(value);
        break;
    case 2:
        processOption2(value);
        break;
    default:
        handleInvalidInput(value);
        break;
}

循环语句

循环语句允许重复执行代码块,直到满足特定条件。C++提供了几种类型的循环:while循环、do-while循环、for循环和范围for循环(C++11)。

while循环

while循环在条件为真的情况下重复执行代码块:

while (condition) {
    // 当condition为真时重复执行的代码
}

示例:

int count = 0;
while (count < 5) {
    std::cout << count << " ";
    count++;
}
// 输出:0 1 2 3 4

注意:条件在每次迭代开始前检查。如果初始条件为假,循环体一次也不会执行。

do-while循环

do-while循环至少执行一次循环体,然后在条件为真的情况下继续执行:

do {
    // 至少执行一次的代码
} while (condition);

示例:

int count = 0;
do {
    std::cout << count << " ";
    count++;
} while (count < 5);
// 输出:0 1 2 3 4

do-while循环特别适用于至少需要执行一次操作的情况,例如用户输入验证:

int number;
do {
    std::cout << "请输入一个正数:";
    std::cin >> number;
} while (number <= 0);

for循环

for循环提供了一种更结构化的循环方式,特别适合已知迭代次数的情况:

for (initialization; condition; update) {
    // 循环体
}

for循环的执行流程:

  1. 执行initialization(只执行一次)
  2. 检查condition(如果为真,执行循环体;如果为假,跳出循环)
  3. 执行循环体
  4. 执行update
  5. 返回步骤2

示例:

for (int i = 0; i < 5; i++) {
    std::cout << i << " ";
}
// 输出:0 1 2 3 4

for循环的变体

  1. 省略初始化
int i = 0;
for (; i < 5; i++) {
    std::cout << i << " ";
}
  1. 省略条件(创建无限循环,需要内部break):
for (int i = 0; ; i++) {
    if (i >= 5) break;
    std::cout << i << " ";
}
  1. 省略更新
for (int i = 0; i < 5; ) {
    std::cout << i << " ";
    i++;
}
  1. 省略所有部分(创建无限循环):
for (;;) {
    // 无限循环,需要内部break
    if (someCondition) break;
}
  1. 多个初始化和更新表达式
for (int i = 0, j = 10; i < 5; i++, j--) {
    std::cout << i << "," << j << " ";
}
// 输出:0,10 1,9 2,8 3,7 4,6

范围for循环(C++11)

C++11引入了范围for循环,简化了对容器和数组的遍历:

for (declaration : expression) {
    // 循环体
}

示例:

std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
    std::cout << num << " ";
}
// 输出:1 2 3 4 5

使用auto关键字可以更灵活地处理不同类型的容器:

std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 35}};
for (const auto& pair : ages) {
    std::cout << pair.first << ": " << pair.second << std::endl;
}

引用与值的使用

  • 使用引用可以避免不必要的复制,提高性能:
// 使用引用(推荐,避免复制)
for (const auto& num : numbers) {
    std::cout << num << " ";
}

// 使用值(会复制每个元素)
for (auto num : numbers) {
    std::cout << num << " ";
}
  • 如果需要修改元素,使用非const引用:
for (auto& num : numbers) {
    num *= 2;  // 将所有元素乘以2
}

嵌套循环

循环可以嵌套使用,创建多维迭代:

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        std::cout << "(" << i << "," << j << ") ";
    }
    std::cout << std::endl;
}

输出:

(0,0) (0,1) (0,2) 
(1,0) (1,1) (1,2) 
(2,0) (2,1) (2,2) 

跳转语句

跳转语句允许程序改变正常的控制流程,跳到代码的其他部分。

break语句

break语句用于终止最内层的循环或switch语句,并继续执行循环或switch之后的语句:

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;  // 当i等于5时终止循环
    }
    std::cout << i << " ";
}
// 输出:0 1 2 3 4

在嵌套循环中,break只会终止包含它的最内层循环:

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) {
            break;  // 只跳出内层循环
        }
        std::cout << "(" << i << "," << j << ") ";
    }
    std::cout << std::endl;
}

输出:

(0,0) (0,1) (0,2) 
(1,0) 
(2,0) (2,1) (2,2) 

continue语句

continue语句跳过当前迭代的剩余部分,直接进入下一次迭代:

for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue;  // 跳过偶数
    }
    std::cout << i << " ";
}
// 输出:1 3 5 7 9

在不同类型的循环中continue的行为:

  • 在for循环中,控制流跳到更新表达式,然后检查条件
  • 在while和do-while循环中,控制流直接跳到条件检查

goto语句

goto语句提供了无条件跳转到程序中标记位置的能力:

goto label;
// 跳过的代码
label:
// 执行的代码

示例:

int i = 0;
start:
if (i < 5) {
    std::cout << i << " ";
    i++;
    goto start;
}
// 输出:0 1 2 3 4

注意:goto语句通常被认为是不良的编程实践,因为它会使代码的控制流难以理解和维护。在大多数情况下,循环和条件语句是更好的选择。

return语句

return语句终止当前函数的执行,并可选地返回一个值:

int sum(int a, int b) {
    return a + b;  // 返回两数之和并终止函数
}

在void函数中,return可以用来提前终止函数:

void printPositive(int number) {
    if (number <= 0) {
        return;  // 如果数字不是正数,提前终止函数
    }
    std::cout << "正数:" << number << std::endl;
}

控制流的最佳实践

1. 避免深层嵌套

深层嵌套的条件和循环会使代码难以阅读和维护:

// 不好的示例:深度嵌套
if (condition1) {
    if (condition2) {
        if (condition3) {
            // 代码
        }
    }
}

// 更好的示例:提前返回
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;
// 代码

2. 使用卫语句简化逻辑

卫语句(guard clauses)可以减少嵌套并提高代码的可读性:

// 使用卫语句
bool processOrder(Order order) {
    if (!order.isValid()) {
        logError("无效订单");
        return false;
    }
    
    if (!order.hasInventory()) {
        logError("库存不足");
        return false;
    }
    
    // 处理有效订单的代码
    return true;
}

3. 优化循环

  • 将不变的计算移出循环
// 不好的示例
for (int i = 0; i < vector.size(); i++) {  // size()在每次迭代中计算
    // 代码
}

// 更好的示例
const size_t size = vector.size();  // 计算一次
for (int i = 0; i < size; i++) {
    // 代码
}
  • 尽可能使用范围for循环
// 冗长的传统for循环
for (auto it = container.begin(); it != container.end(); ++it) {
    std::cout << *it << " ";
}

// 更简洁的范围for循环
for (const auto& item : container) {
    std::cout << item << " ";
}

4. 合理使用switch与if-else

  • 当有多个离散值需要比较时,使用switch
  • 当需要测试范围或不同条件时,使用if-else
// 适合switch的情况
switch (day) {
    case 1: /* ... */ break;
    case 2: /* ... */ break;
    // ...
}

// 适合if-else的情况
if (score >= 90) {
    // A级
} else if (score >= 80) {
    // B级
} else {
    // ...
}

5. 避免神秘数字(magic numbers)

使用命名常量代替硬编码的数字:

// 不好的示例
if (age >= 18) {  // 18是什么?为什么是18?
    // 代码
}

// 更好的示例
const int LEGAL_ADULT_AGE = 18;
if (age >= LEGAL_ADULT_AGE) {
    // 代码
}

6. 使用花括号保持一致性

即使代码块只有一行,也建议使用花括号,以避免潜在的逻辑错误:

// 容易出错
if (condition)
    doSomething();
    doSomethingElse();  // 这行总是执行,不受if条件影响

// 更清晰、更安全
if (condition) {
    doSomething();
}
doSomethingElse();  // 明确不在if块内

高级控制流技巧

1. 状态机模式

使用switch语句实现简单的状态机:

enum State { IDLE, RUNNING, PAUSED, STOPPED };

State current_state = IDLE;

void processEvent(Event event) {
    switch (current_state) {
        case IDLE:
            if (event == START) {
                current_state = RUNNING;
                startOperation();
            }
            break;
        case RUNNING:
            if (event == PAUSE) {
                current_state = PAUSED;
                pauseOperation();
            } else if (event == STOP) {
                current_state = STOPPED;
                stopOperation();
            }
            break;
        // 其他状态处理
    }
}

2. 使用lambda简化控制流

C++11引入的lambda表达式可以简化某些控制流情况:

// 使用lambda处理条件分支
auto process = [&](int value) {
    if (value < 0) {
        handleNegative(value);
    } else if (value > 0) {
        handlePositive(value);
    } else {
        handleZero();
    }
};

// 调用lambda
process(userInput);

3. 表驱动方法

对于复杂的条件逻辑,使用查找表可以简化代码:

// 一个表驱动的日期验证示例
const int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool isValidDate(int year, int month, int day) {
    if (month < 1 || month > 12) return false;
    
    // 处理闰年二月
    int maxDays = daysInMonth[month];
    if (month == 2 && isLeapYear(year)) {
        maxDays = 29;
    }
    
    return day >= 1 && day <= maxDays;
}

4. C++17的结构化绑定与控制流

结合C++17的结构化绑定和带初始化的if语句:

std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}, {"Charlie", 92}};

if (auto [iter, inserted] = scores.insert({"David", 88}); inserted) {
    std::cout << "添加了新学生" << std::endl;
} else {
    std::cout << "学生已存在,分数为" << iter->second << std::endl;
}

实际案例分析

菜单驱动程序

#include <iostream>
#include <string>

void showMenu() {
    std::cout << "\n==== 主菜单 ====\n";
    std::cout << "1. 添加新记录\n";
    std::cout << "2. 显示所有记录\n";
    std::cout << "3. 搜索记录\n";
    std::cout << "4. 删除记录\n";
    std::cout << "0. 退出\n";
    std::cout << "请选择操作: ";
}

int main() {
    int choice;
    bool running = true;
    
    while (running) {
        showMenu();
        std::cin >> choice;
        
        switch (choice) {
            case 0:
                std::cout << "感谢使用,再见!\n";
                running = false;
                break;
            case 1:
                std::cout << "添加新记录功能\n";
                // 添加记录代码
                break;
            case 2:
                std::cout << "显示所有记录功能\n";
                // 显示记录代码
                break;
            case 3:
                std::cout << "搜索记录功能\n";
                // 搜索记录代码
                break;
            case 4:
                std::cout << "删除记录功能\n";
                // 删除记录代码
                break;
            default:
                std::cout << "无效选择,请重试\n";
                break;
        }
    }
    
    return 0;
}

简单游戏循环

#include <iostream>
#include <chrono>
#include <thread>
#include <random>

enum class GameState { MENU, PLAYING, PAUSED, GAME_OVER };

int main() {
    GameState state = GameState::MENU;
    bool running = true;
    int score = 0;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 10);
    
    while (running) {
        switch (state) {
            case GameState::MENU:
                std::cout << "====游戏菜单====\n";
                std::cout << "1. 开始游戏\n";
                std::cout << "2. 退出\n";
                int choice;
                std::cin >> choice;
                if (choice == 1) {
                    state = GameState::PLAYING;
                    score = 0;
                } else if (choice == 2) {
                    running = false;
                }
                break;
                
            case GameState::PLAYING:
                // 简单游戏逻辑
                std::cout << "\n当前得分: " << score << std::endl;
                std::cout << "press 'p' to pause, 'q' to quit: ";
                char input;
                std::cin >> input;
                
                if (input == 'p') {
                    state = GameState::PAUSED;
                } else if (input == 'q') {
                    state = GameState::GAME_OVER;
                } else {
                    // 随机增加分数
                    score += dis(gen);
                }
                
                // 检查游戏结束条件
                if (score > 50) {
                    std::cout << "你赢了!\n";
                    state = GameState::GAME_OVER;
                }
                break;
                
            case GameState::PAUSED:
                std::cout << "游戏已暂停,按'c'继续,'q'退出: ";
                std::cin >> input;
                if (input == 'c') {
                    state = GameState::PLAYING;
                } else if (input == 'q') {
                    state = GameState::GAME_OVER;
                }
                break;
                
            case GameState::GAME_OVER:
                std::cout << "游戏结束!最终得分: " << score << std::endl;
                std::cout << "1. 重新开始\n";
                std::cout << "2. 退出\n";
                std::cin >> choice;
                if (choice == 1) {
                    state = GameState::MENU;
                } else {
                    running = false;
                }
                break;
        }
        
        // 简单的帧率控制
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    std::cout << "感谢游玩!\n";
    return 0;
}

总结

控制流语句是编程的基本构建块,掌握它们对于编写高效、可读和健壮的C++程序至关重要。本文回顾了C++中的各种控制流语句,包括条件语句(if、if-else、switch)、循环语句(while、do-while、for、范围for)和跳转语句(break、continue、goto、return)。

通过理解这些控制流机制并遵循最佳实践,您可以编写出更加清晰和可维护的代码。随着您编程经验的增长,您将逐渐学会在不同情况下选择最合适的控制流结构,并有效地组合它们以解决复杂的问题。

在下一篇文章中,我们将探讨C++中的函数定义与调用,包括函数重载、默认参数、内联函数和Lambda表达式等主题。

参考资料

  1. Bjarne Stroustrup. The C++ Programming Language (4th Edition)
  2. Scott Meyers. Effective C++
  3. cppreference.com - 语句
  4. C++ Core Guidelines - 控制流

这是我C++学习之旅系列的第三篇技术文章。查看完整系列目录了解更多内容。

相关文章:

  • Spark2 之 Expression/Functions
  • Simple-BEV的bilinear_sample 作为view_transformer的解析,核心是3D-2D关联点生成
  • 穿越之程序员周树人的狂人日记Part3__人机共生纪元
  • Extend module 01:Keyboard
  • 具身系列——NLP工程师切入机器人和具身智能方向
  • LabVIEW液压振动锤控制系统
  • 清华大学.智灵动力-《DeepSeek行业应用实践报告》附PPT下载方法
  • 查询操作是否需要使用事务?
  • 软件测试面试:支付功能如何测试?
  • 基于Python的机器学习入门指南
  • 【Pandas】pandas Series plot.line
  • TCP netstat TIME_WAIT CLOSE_WAIT
  • 利用dify打造命令行助手
  • 基于SpringBoot + Vue 的垃圾分类管理系统
  • Qt信号与槽机制入门详解:从基础语法到界面交互实战
  • 测试用例组成及设计方法
  • Zotero·Awesome GPT配置
  • 基于CentOS系统搭建Samba服务
  • 提高库存周转率的重要性
  • 风格混合增强的解纠缠学习在医学图像分割的无监督域自适应中的应用|文献速递-医学影像人工智能进展
  • 澎湃读报丨央媒头版头条集中刊发:大国应有的样子
  • 据报特斯拉寻找新CEO,马斯克财报会议上表态:把更多时间投入特斯拉
  • 五一期间全国高速日均流量6200万辆,同比增长8.1%
  • 新能源车盈利拐点:8家上市车企去年合计净利854亿元,多家扭亏
  • 中央网信办:重点整治违规AI产品、利用AI制作发布谣言等突出问题
  • 复星医药换帅:陈玉卿接棒吴以芳任董事长,吴以芳改任复星国际执行总裁