C++学习笔记(基于learn-cxx)(1)

本文是个人用于学习cpp时的笔记和记录。基于GitHub - InfiniTensor/learning-cxx · GitHub

00_hello_world

参考章节:

stdin, stdout, stderr - cppreference.com

输入/输出操纵符 - cppreference.com

std::format - cppreference.com

1.stdin, stdout, stderr

stdin: 与标准输入流关联,用于读取约定的输入。

stdout: 与标准输出流关联,用于写入约定的输出。

stderr: 与标准错误流关联,用于写入诊断输出。

2.输入/输出操纵符

操纵符是能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。

这里我们先记几个常用的。比如调整浮点数输出、输出换行、控制输出宽度之类的

换行使用endl

3.std::format

c++20引入。可以便捷的格式化字符串。

比如,用变量占位,格式控制

cpp 复制代码
#include <format>
#include <iostream>

int main() {
    // {} 就是"占位符",会被后面的参数替换
    std::string s = std::format("Hello {}!", "world");
    std::cout << s; // 输出: Hello world!

    // 多个占位符,按顺序填入
    std::string s2 = std::format("{} + {} = {}", 1, 2, 3);
    std::cout << s2; // 输出: 1 + 2 = 3

    // 也可以指定顺序(用数字索引)
    std::string s3 = std::format("{1} before {0}", "world", "hello");
    std::cout << s3; // 输出: hello before world
}
cpp 复制代码
// 数字控制
std::format("{:.2f}", 3.14159);  // "3.14"  (保留2位小数)
std::format("{:#06x}", 255);     // "0x00ff"(16进制,补零到6位)

// 字符串对齐
std::format("{:>10}", "hi");     // "        hi"(右对齐,占10格)
std::format("{:*^10}", "hi");    // "****hi****"(居中,用*填充)

// 数字千分位
std::format("{:L}", 1234567);    // "1,234,567"(需要设置locale)

此外,这个会在编译时进行检查,与参数部匹配就报错。

另外,format只能使用常量。若使用运行时变量,请使用std::vformat

cpp 复制代码
std::string user_fmt = "Hello {}!";
// std::format(user_fmt, "world");  // ❌ 编译错误(非常量)
std::vformat(user_fmt, std::make_format_args("world"));  // ✅ 正确

4.练习解析

本章使用cout和操纵符输出和换行即可

cpp 复制代码
int main(int argc, char **argv) {
    // TODO: 在控制台输出 "Hello, InfiniTensor!" 并换行
    std::cout << "Hello, InfiniTensor!" << std::endl;
    return 0;
}

01_variable&add

参考章节:

表达式 - cppreference.com

1.变量定义

前面类型后面变量名。可以赋初值。不赘述

2.表达式

运算符和操作数的序列。可以指定一个计算。

运算符很多种,基础的就**+** , - , * , / 等,比较,位运算等也都是。特殊点的比如new , delete ,sizeof

3.练习解析

用 类型+变量名,定义x变量

cpp 复制代码
 int x = 0;//改这一行
 std::cout << x << " + " << x << " = " << x + x << std::endl;
 return 0;

02_function

参考章节:

​​​​​​​声明 - cppreference.com

解释复杂声明符 | Microsoft Learn

1.函数声明

如果函数在主函数前,,无需声明。在后面,你需要在前面弄上"返回类型 函数名(参数类型)"的声明。

2.返回

return可以返回你要返回的值。注意类型要与定义的类型一样。

3.练习解析

添加声明,返回a + b.

cpp 复制代码
int add(int a, int b);

int main(int argc, char **argv) {
    ASSERT(add(123, 456) == 123 + 456, "add(123, 456) should be 123 + 456");

    auto x = 1, y = 2;
    std::cout << x << " + " << y << " = " << add(x, y) << std::endl;
    return 0;
}

int add(int a, int b) {
    // TODO: 补全函数定义,但不要移动代码行
    return a + b;
}

03_argument&parameter

参考章节:

1.形参和实参

实际传递进函数的值,是实际参数。

跳转到函数内后,你对接收的变量,进行修改,不影响原先传进去的值。

2.主函数的参数

是的,主函数也有形参。

argc --- Argument Count

  • 类型:int

  • 含义:命令行参数的个数(包括程序名本身)

argv --- Argument Vector

  • 类型:char**(字符串数组)

  • 含义:每个命令行参数的内容

你在命令行里,添加参数,就会传进argv数组内。

bash 复制代码
./exercise hello world

那么:

bash 复制代码
argc = 3

argv[0] = "./exercise"   ← 程序名本身
argv[1] = "hello"        ← 第1个参数
argv[2] = "world"        ← 第2个参数

不带参数,也有一个程序名的参数。

bash 复制代码
./exercise
bash 复制代码
argc = 1
argv[0] = "./exercise"

3.练习解析:

原先代码assert内是空的,需要自己填。这里我们理解形参实参,就可以解决了。

cpp 复制代码
// TODO: 为下列 ASSERT 填写正确的值
int main(int argc, char **argv) {
    auto arg = 99;
    ASSERT(arg == 99, "arg should be ?");
    std::cout << "befor func call: " << arg << std::endl;
    func(arg);
    ASSERT(arg == 99, "arg should be ?");
    std::cout << "after func call: " << arg << std::endl;
    return 0;
}

// TODO: 为下列 ASSERT 填写正确的值
void func(int param) {
    ASSERT(param == 99, "param should be ?");
    std::cout << "befor add: " << param << std::endl;
    param += 1;
    ASSERT(param == 100, "param should be ?");
    std::cout << "after add: " << param << std::endl;
}

04_static

存储类说明符 - cppreference.com

这次先看代码:

cpp 复制代码
#include "../exercise.h"

// READ: `static` 关键字 <https://zh.cppreference.com/w/cpp/language/storage_duration>
// THINK: 这个函数的两个 `static` 各自的作用是什么?
static int func(int param) {
    static int static_ = param;
    // std::cout << "static_ = " << static_ << std::endl;
    return static_++;
}

int main(int argc, char **argv) {
    // TODO: 将下列 `?` 替换为正确的数字
    ASSERT(func(5) == ?, "static variable value incorrect");
    ASSERT(func(4) == ?, "static variable value incorrect");
    ASSERT(func(3) == ?, "static variable value incorrect");
    ASSERT(func(2) == ?, "static variable value incorrect");
    ASSERT(func(1) == ?, "static variable value incorrect");
    return 0;
}

1.两个static有啥区别?

函数的static:限制函数只能在本文件内使用。控制可见域。

变量的static:延长生命周期,此变量活到程序结束。并且只初始化一次!(后面的初始化那一行的赋值全无效)

正常的函数内变量,函数结束就回收。而他会一直在。

所以每次++,会一直记得,另外只初始化一次,所以一直增加

2.a++和++a

++是自增,这里是在变量后面,所以是先返回后自增。所以第一个断言是5

3.练习解析:

第一次变成5,返回,自增。然后以此类推。

cpp 复制代码
#include "../exercise.h"

// READ: `static` 关键字 <https://zh.cppreference.com/w/cpp/language/storage_duration>
// THINK: 这个函数的两个 `static` 各自的作用是什么?
static int func(int param) {
    static int static_ = param;
    // std::cout << "static_ = " << static_ << std::endl;
    return static_++;
}

int main(int argc, char **argv) {
    // TODO: 将下列 `?` 替换为正确的数字
    ASSERT(func(5) == 5, "static variable value incorrect");
    ASSERT(func(4) == 6, "static variable value incorrect");
    ASSERT(func(3) == 7, "static variable value incorrect");
    ASSERT(func(2) == 8, "static variable value incorrect");
    ASSERT(func(1) == 9, "static variable value incorrect");
    return 0;
}
相关推荐
X54先生(人文科技)8 分钟前
社会嵌入式终身学习机器与修复时代-ELR架构和技术演化探讨
人工智能·深度学习·学习·架构·开源协议
电子云与长程纠缠44 分钟前
UE5魂系游戏开发教程05
开发语言·学习·游戏·ui·ue5
syagain_zsx1 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
其实防守也摸鱼1 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
我命由我123451 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
摇滚侠2 小时前
《Java并发编程之美》第 4 章 Java 并发包中原子操作类原理剖析 阅读笔记 7
java·笔记·python
fpcc2 小时前
计算机原理—如何高效的操作文件
c++·计算机原理
kkkkkkkkkk_Z2 小时前
新手自学嵌入式 | 学习日记:Linux驱动复习之系统移植(U-Boot篇)
linux·运维·学习
Rabitebla2 小时前
【系统性学习笔记】Linux 权限篇(二):文件属性、权限修改与目录权限的底层逻辑
linux·c++·笔记·学习·算法
system_error_x2 小时前
C++ 编程基础入门教程
开发语言·c++