从零到一学习c++(基础篇--筑基期九-语句)

ops/2025/2/22 21:30:46/

  从零到一学习C++(基础篇) 作者:羡鱼肘子

温馨提示1:本篇是记录我的学习经历,会有不少片面的认知,万分期待您的指正。

 温馨提示2:本篇会尽量用更加通俗的语言介绍c++的基础,用通俗的语言去解释术语,但不会再大白话了哦。常见,常看,常想,渐渐的就会发现术语也是很简单滴。

 温馨提示3:看本篇前可以先了解前篇的内容,知识体系会更加完整哦。

从零到一学习c++(基础篇--筑基期八-表达式)-CSDN博客

温馨提示4:个人感觉对环境的适应还是挺重要的。

一、基础语句类型

1. 表达式语句:就是做一件事

简单来说:就像你每天做的小任务,比如“倒一杯水”“关灯”。
代码本质:任何表达式后加 ; 就是一个语句。

int x = 5;       // 赋值表达式语句
x++;             // 自增表达式语句
cout << "Hi";    // 输出表达式语句

2. 复合语句(块):打包多个任务

简单理解:把多个任务装进一个“盒子”({}),比如“早晨流程”:{刷牙 → 洗脸 → 吃早餐}。
代码本质:用 {} 包裹多个语句,形成独立作用域。

{ // 开始一个块int x = 10;        // 这个 x 只在块内有效cout << x << endl; // 输出 10
} // 块结束,x 被销毁
// cout << x;         // 这里会报错,x 不存在了

3. 选择语句:条件判断

(1) if-else:二选一 

一个栗子:如果温度大于30° → 开空调;否则 → 不开。

还可以是这样if-else if-else (理论上可以有很多的else if 但是不建议这样写哦) 

int temperature = 25;
if (temperature > 30) {cout << "开空调!";
} else if (temperature < 10) {cout << "穿羽绒服!";
} else {cout << "出门散步~";
}

(2) switch:多选一

我们来看看饮料机:选择饮料机按钮:1→可乐,2→雪碧,其他→水。

int choice = 2;
switch (choice) {case 1:cout << "可乐";break;  // 必须写 break,否则会继续执行下一个 case!case 2:cout << "雪碧";break;default:cout << "水";
}

4. 迭代语句:重复做某件事

(1) for 循环:明确次数

就像:做 10 个俯卧撑 → 从1数到 10 。

for (int i = 0; i < 10; i++) { // i从0到9cout << "第 " << i+1 << " 个俯卧撑!" << endl;
}

(2) while 循环:条件满足就一直做

就像:只要没吃饱 → 继续吃

int hunger = 80; // 饥饿值(0-100)
while (hunger > 30) {cout << "吃一口饭..." << endl;hunger -= 20;
}

do-while:条件循环

就像:先吃一口看看饱了没,只要没吃饱 → 继续吃

do { /*...*/ } while (cond);

温馨小贴士:while VS do-while

核心区别

特性while 循环do-while 循环
执行顺序先检查条件,条件满足才执行循环体先执行一次循环体,再检查条件
最少执行次数0 次(条件不满足时直接跳过)至少 1 次(无论如何都会先执行一次)
适用场景需要先检查条件再执行的情况必须至少执行一次的情况
语法while (条件) { ... }do { ... } while (条件);(注意分号)

对比

1. while 循环:先检查,后行动

  • 你准备去超市买苹果,但先检查钱包是否有钱

    • 有钱 → 进去买苹果。

    • 没钱 → 直接回家,不进去。

2. do-while 循环:先行动,后检查

  • 先冲进超市拿苹果,然后到收银台检查钱包:

    • 有钱 → 结账离开。

    • 没钱 → 放下苹果离开,但已经拿过苹果了。


场景1:用户输入验证

1. while 循环

要求用户必须输入正整数,否则重新输入:

int num;
cout << "请输入一个正整数:";
cin >> num;// 先检查输入是否合法,不合法就循环要求重新输入
while (num <= 0) {cout << "输入错误!请重新输入:";cin >> num;
}

需求:需要先写一遍输入代码,导致重复!


2. do-while 循环

优化代码,避免重复:

int num;
do {cout << "请输入一个正整数:";cin >> num;
} while (num <= 0); // 输入后检查条件

优势:无论用户第一次输入是否正确,至少会执行一次输入操作,代码更简洁。


关键细节

  1. do-while 末尾必须有分号

    do { ... } while (条件); // 分号不可少!
  2. 避免无限循环
    确保循环体内有改变条件的代码,例如:

    int i = 0;
    do {cout << i << endl;i++; // 必须修改条件,否则无限循环!
    } while (i < 5);

小结:如何选择?

  • 用 while:当可能不需要执行循环体时(例如遍历链表前检查是否为空)。

  • 用 do-while:当必须至少执行一次循环体时(例如菜单交互、输入验证)。

一句话记住

  • while:“先看路,再开车”。

  • do-while:“先开车,再看路”。

(3) 范围 for(C++11 现代特性)

就像:自动遍历购物清单里的每个商品。

vector<string> list = {"苹果", "牛奶", "面包"};
for (const auto& item : list) { // 自动遍历容器cout << "买了:" << item << endl;
}

5. 跳转语句:改变执行顺序

(1) break:立刻停止

for (int i = 0; i < 100; i++) {if (i == 5) {break; // 当i=5时,直接跳出循环}cout << i << endl; // 只会输出0-4
}

(2) continue:跳过当前,继续下次

for (int i = 0; i < 5; i++) {if (i == 2) {continue; // 跳过i=2的情况}cout << i << endl; // 输出0,1,3,4
}

(3) return:从函数返回

int add(int a, int b) {return a + b; // 返回结果,函数结束
}

二、现代C++特性增强

1. 范围 for 循环(C++11)(底层是迭代器)

简化容器遍历,支持自定义类型(需实现 begin()/end()):

std::vector<int> vec{1, 2, 3};
for (const auto& elem : vec) {  // 只读用 const auto&std::cout << elem;
}

2. 带初始化的 if/switch(C++17)

限制变量作用域,增强代码安全性:

if (auto it = m.find(key); it != m.end()) {// it 仅在块内可见
}
switch (int x = compute(); x) { /*...*/ }

 温馨小贴士:

我们先来看看代码吧

1. 带初始化的 if 语句

if (auto it = m.find(key); it != m.end()) {// it 仅在块内可见
}
  • 功能:在 if 的条件部分声明变量并判断条件。

  • 关键点

    1. 变量初始化auto it = m.find(key) 在条件中初始化迭代器 it(假设 m 是 map 或类似容器)。

    2. 条件判断it != m.end() 检查是否找到键值对。

    3. 作用域限制it 仅在 if 块内可见,外部无法访问,避免命名污染。(这里是关键哦)

  • 对比传统写法

    auto it = m.find(key); // 变量暴露在外部作用域
    if (it != m.end()) {// ...
    }

2. 带初始化的 switch 语句

switch (int x = compute(); x) {case 1: /*...*/ break;case 2: /*...*/ break;default: /*...*/
}
  • 功能:在 switch 的条件部分初始化变量并作为判断依据。

  • 关键点

    1. 变量初始化int x = compute() 执行函数 compute() 并将返回值赋给 x

    2. 判断依据switch 根据 x 的值跳转到对应 case

    3. 作用域限制x 仅在 switch 块内可见。(这里很重要)

  • 对比传统写法

    int x = compute(); // 变量暴露在外部作用域
    switch (x) {// ...
    }

现代C++特性(C++17)(强化认知阶段)

1. 带初始化的条件语句

  • 允许在 if/switch 的条件中声明变量,语法为:
    if (初始化语句; 条件) { ... }
    switch (初始化语句; 变量) { ... }

  • 核心优势

    • 作用域限制:变量仅在条件语句块内有效,避免命名冲突。

    • 代码简洁性:将变量声明与条件判断合并,逻辑更紧凑。

    • 安全性:防止变量在外部被误用。

2. 应用场景

  • if 语句:适用于需要临时变量进行条件判断的场景(如查找容器元素)。

  • switch 语句:适用于需要根据计算结果进行多分支选择的场景。


示例对比(传统 vs 现代)

传统写法

// if 示例
auto it = m.find(key); // 变量在外部作用域
if (it != m.end()) {// ...
}
// 此处仍可访问 it,可能引发误操作!// switch 示例
int x = compute(); // 变量在外部作用域
switch (x) {case 1: /*...*/ break;
}
// 此处仍可访问 x

现代写法(C++17)

// if 示例
if (auto it = m.find(key); it != m.end()) {// 仅在此块内可访问 it
}
// 此处无法访问 it,避免误用// switch 示例
switch (int x = compute(); x) {case 1: /*...*/ break;
}
// 此处无法访问 x

小结一下:

  • 作用域控制:通过将变量声明限制在条件语句内,提升代码安全性。

  • 代码可读性:将变量初始化与条件判断合并,逻辑更清晰。

  • 适用性:适用于需要临时变量的条件判断场景。

3. constexpr if(C++17)(目前作为了解内容,后续会结合项目来演示学习

编译期条件判断,简化模板代码:

template <typename T>
void process(T val) {if constexpr (std::is_integral_v<T>) {// 仅对整型编译此分支} else {// 其他类型}
}

4. 结构化绑定(C++17)(这个很重要哦)

解包元组或结构体,常用于范围 for

pair<string, int> student = {"Tom", 85};
auto& [name, score] = student; // 解包 pair
cout << name << "得了" << score << "分";

5. 异常处理改进(作为了解,就是提到的话自己知道有这个东西就行)

  • noexcept 说明符(C++11):声明函数不抛出异常。

  • try/catch:现代C++推荐用智能指针等资源管理技术替代裸 new/delete,减少异常风险。

温馨小贴士:(初步认知阶段,会有一点的困难,但是不要放弃哦,坚持下去会有结果的)

一、noexcept 说明符(C++11)

1. 核心作用

  • 声明函数不抛出异常:告知编译器该函数不会抛出异常,允许编译器进行优化。

  • 优化性能:编译器无需为noexcept函数生成异常处理代码,减少二进制体积。

  • 接口约束:调用方可以依赖此声明,无需处理该函数抛出的异常。

2. 语法与规则

void func() noexcept;      // 不抛出任何异常
void func() noexcept(true); // 等价于 noexcept
void func() noexcept(false); // 可能抛出异常

3. 示例分析

#include <stdexcept>// 传统函数可能抛出异常
int unsafe_divide(int a, int b) {if (b == 0) throw std::invalid_argument("除数不能为0");return a / b;
}// 使用 noexcept 声明不抛异常(但实际可能抛出,需谨慎!)
int safe_divide(int a, int b) noexcept {return a / b; // 若b=0,触发未定义行为(程序终止)
}int main() {try {// unsafe_divide(10, 0); // 抛出异常,可以被捕获safe_divide(10, 0);     // noexcept函数抛出异常,程序终止} catch (const std::exception& e) {std::cerr << "捕获异常: " << e.what() << std::endl;}return 0;
}

4. 适用场景

  • 移动构造函数/赋值运算符:标准库容器在重新分配内存时优先使用noexcept移动操作。

  • 高性能关键路径:确保函数不会因异常影响性能。

  • 明确接口行为:例如析构函数默认noexcept,手动声明可增强可读性。


二、智能指针替代 new/delete(后期会单独学习智能指针,这个是内存管理的基础是非常非常重要的)

1. 核心改进

  • 资源自动释放:通过RAII(资源获取即初始化)管理内存,避免因异常导致内存泄漏。

  • 异常安全:即使异常发生,智能指针的析构函数仍会释放资源。

2. 对比示例

传统写法(裸指针 + try/catch

void process_file() {int* data = new int[100]; // 动态分配内存try {// 可能抛出异常的操作read_file(data);       // 假设 read_file 可能抛出异常process(data);} catch (const std::exception& e) {delete[] data;         // 必须手动释放!throw;                 // 重新抛出异常}delete[] data;             // 正常流程释放
}

问题:若read_fileprocess抛出异常且未在catch块中释放内存,会导致内存泄漏。


现代写法(智能指针)

#include <memory>void process_file() {auto data = std::make_unique<int[]>(100); // 使用 unique_ptrtry {read_file(data.get());process(data.get());} catch (const std::exception& e) {// 无需手动释放内存!unique_ptr 会在退出作用域时自动释放throw;}
}

优势:无论是否发生异常,unique_ptr都会在离开作用域时自动释放内存。


3. 智能指针类型

类型

用途

异常安全性

std::unique_ptr

独占所有权,不可复制

离开作用域时自动释放内存

std::shared_ptr

共享所有权,引用计数管理

引用计数归零时自动释放内存

std::weak_ptr

解决 shared_ptr 循环引用问题

不增加引用计数


三、综合应用示例

场景:读取文件并解析数据

#include <memory>
#include <fstream>
#include <vector>
#include <stdexcept>// 使用 unique_ptr 管理文件资源
void read_and_process(const std::string& filename) {auto file = std::make_unique<std::ifstream>(filename);if (!file->is_open()) {throw std::runtime_error("无法打开文件");}std::vector<int> data;int value;while (*file >> value) {data.push_back(value);}if (data.empty()) {throw std::runtime_error("文件内容为空");}// 处理数据(假设 process_data 可能抛出异常)process_data(data); // noexcept(false)
}int main() {try {read_and_process("data.txt");} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;return 1;}return 0;
}

关键点分析

  1. 资源管理std::ifstreamunique_ptr管理,即使异常发生,文件句柄也会正确关闭。

  2. 异常传播:所有可能的错误(如文件打开失败、数据为空)通过异常向上传递,由main统一处理。

  3. 代码简洁性:无需在多个catch块中重复释放资源。


四、小结一下

1. noexcept 的核心价值

  • 性能优化:减少异常处理开销。

  • 接口清晰化:明确函数是否可能抛出异常。

2. 智能指针的核心价值

  • 资源安全:杜绝因异常导致的内存/资源泄漏。

  • 代码简洁:避免手动try/catch和资源释放逻辑。

3. 现代C++最佳实践

  • 优先使用智能指针:替代裸new/delete

  • 合理使用 noexcept:在明确不抛异常的函数上标记,但避免滥用。

  • 减少显式 try/catch:依赖RAII和异常传播机制,而非深层嵌套的异常捕获。

6. 协程支持(C++20)(了解就好)

  • co_await/co_return:异步编程模型(需编译器支持)。

    generator<int> seq() {for (int i=0; ; ++i) {co_yield i; // 生成值并暂停}
    }

三、一些建议

  1. 优先使用范围 for:简化遍历,避免迭代器错误。

  2. 限制变量作用域:如用带初始化的 if/switch

  3. 编译期分支优化:用 constexpr if 替代运行时条件。

  4. 避免 goto:用函数或结构化的控制流替代。

一句话理解语句

  • 表达式语句:做一件小事(x = 5;)。

  • 复合语句:打包一组任务({...})。

  • 选择语句:根据条件选择路线(if/switch)。

  • 循环语句:重复执行直到满足条件(for/while)。

  • 跳转语句:改变执行顺序(break/return)。

 喔吼吼,又学完了一部分,太棒了!!!一起去在下一篇学习函数吧😀

 

 

 

 

 

 

 


http://www.ppmy.cn/ops/159830.html

相关文章

智能协同:数据集成平台与DeepSeek驱动的数据分析与智能调度革新

前言 企业面临着海量数据的挑战与机遇。如何高效地整合多源数据、精准分析并智能决策&#xff0c;成为企业提升竞争力的关键。本文解析轻易云数据集成平台与DeepSeek技术结合在数据分析和智能调度方面的创新应用&#xff0c;揭示其为企业带来的高效、智能与精准的业务价值。 …

2025-02-18 学习记录--C/C++-PTA 7-24 约分最简分式

一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h>int main() {int fenZi 0, // 分子fenMu 0; // 分母scanf("%d/%d",&fenZi,&fenMu);// 定义分子、分母两者中较小的那个值为minint min fenZi > fenMu ? fenMu…

华为昇腾 910B 部署 DeepSeek-R1 蒸馏系列模型详细指南

本文记录 在 华为昇腾 910B(65GB) * 8 上 部署 DeepSeekR1 蒸馏系列模型&#xff08;14B、32B&#xff09;全过程与测试结果。 NPU&#xff1a;910B3 (65GB) * 8 &#xff08;910B 有三个版本 910B1、2、3&#xff09; 模型&#xff1a;DeepSeek-R1-Distill-Qwen-14B、DeepSeek…

domain 网络安全

文章目录 1、域的概述 1.1、工作组与域1.2、域的特点1.3、域的组成1.4、域的部署概述1.5、活动目录1.6、组策略GPO 2、域的部署实验 2.1、建立局域网&#xff0c;配置IP2.2、安装活动目录2.3、添加用户到指定域2.4、将PC加入域2.5、实验常见问题 3、OU&#xff08;组织单位…

C#中的静态类以及常见用途

在C#中&#xff0c;静态类&#xff08;Static Class&#xff09; 是一种特殊的类&#xff0c;它不能被实例化&#xff0c;也不能被继承。静态类主要用于包含静态成员&#xff08;如静态方法、静态属性、静态字段等&#xff09;&#xff0c;这些成员可以直接通过类名访问&#x…

【CS.SE】优化 Redis 商户号池分配设计:高并发与内存管理

优化 Redis 商户号池分配设计&#xff1a;高并发与内存管理 背景 在分布式交易系统中&#xff0c;商户号池管理是核心模块之一。传统的商户号生成方式&#xff0c;依赖数据库预分配号段&#xff0c;导致大量号段浪费&#xff0c;并且在高并发请求下&#xff0c;性能难以满足需…

spring boot知识点2

1.spring boot 要开启一些特性&#xff0c;可通过什么方式开启 a.通过Enable注解&#xff0c;可启动定时服务 b.通过application.properties可设置端口号等地址信息 2.什么是热部署&#xff0c;以及spring boot通过什么方式进行热部署 热部署这个概念&#xff0c;我知道。就…

文本操作基础知识:正则表达式

目录 摘要&#xff1a; 一、语法 二、匹配模式pattern 1、普通字符[ ] 2、限定字符 3、定位字符 4、运算字符( ) 三、修饰符flags 四、各语言的正则使用 1、Python的re 参考资料&#xff1a; 摘要&#xff1a; 常用匹配&#xff1a;[A-C]、[^A-C]、\w、\d、\n、\r、…