【C++】批量任务处理
for循环
for循环逻辑图

for循环代码
for (初始化表达式; 条件表达式; 更新表达式) {
// 循环体
//也就是要重复执行的代码
}

注意!,在C++新版本中初始化的作用域在for循环内部

continue
continue语句用于在循环中跳过当前迭代并继续执行下一次迭代。这对于在特定条件下希望跳过循环体中的某些部分非常有用。

break
break语句用于立即终止所在的循环结构的执行,并跳出循环体。

嵌套循环
嵌套循环是指在一个循环体内嵌套另一个循环。嵌套循环可以有多层,但常见的通常是两层或三层。

无限循环
通常情况下,for循环用于遍历一个有限范围,但你可以通过
省略条件表达式来创建一个无限循环。
跳出循环则使用
break;

while 循环
while循环逻辑图

while循环代码
while(条件表达式)
{
循环体;
}

continue

break

无限循环

基于while循环的支持ls的shell项目
system执行系统命令
system("cd");进入当前路径

类型转换
string.c_str()用于将 std::string 对象转换为const char* 类型的指针

system("dir") 显示当前目录的文件和子目录列表。

cin输入
cin不能读取空格以后的内容
输入:`1``(空格)``2`
输出:`1`

cin.rdbuf()->in_avail() 是 C++ 中用于检查标准输入流(std::cin)中当前可用字符数的方法。它依赖于流缓冲区stream buffer的概念.
rdbuf() 是 std::istream 类的一个成员函数,它返回一个指向流缓冲区的指针,类型为 std::streambuf*。
in_avail() 是 std::streambuf 类的一个成员函数,它返回一个整数,表示当前在输入缓冲区中可用的字符数。

该代码执行逻辑如下
输入 1 2 然后按下 Enter:
输入流 std::cin 将包含字符串
"1 2\n",其中\n是 Enter 键产生的换行符。
std::cin >> a;:
提取运算符 >> 会从输入流中读取第一个整数,这里是 1,并将其存储在变量 a 中。
读取 1 后,输入流中剩余的内容是" 2\n"。
std::cout << "in_avail = " << std::cin.rdbuf()->in_avail() << std::endl;
这行代码输出输入缓冲区中剩余的可用字符数。
在读取 1 后,输入缓冲区中还有" 2\n"。因此,in_avail() 将返回3,因为有三个个字符(空格,2和\n)仍然在缓冲区中等待处理。
因此,当缓冲区还有内容时,将内容存下来并继续进入cin存入a中

注意!此处只解决了一个空格的问题,如果有多个空格等其他问题,此处不做处理
掌握了基础知识,我们来写shell通过用户输入后,执行system命令
项目代码
需求如下
实现一个在windows上支持ls命令的shell
使用cin接收用户输入
使用system调用dir命令模拟ls
支持ls不传参数和传输传递
用户输入exit和quit退出
容错处理
代码如下

功能测试
1.容错处理:输入错误的代码会进行提示
std::cerr是 C++ 标准库中的一个输出流对象,专门用于输出错误消息或诊断信息。因为它是未缓冲的(unbuffered),这意味着数据会立即被发送到输出设备(通常是控制台或终端),而不是先存储在缓冲区中。这对于输出错误消息非常重要,因为你通常希望立即看到错误信息,以便快速诊断问题。

2.控制台退出

3.输入ls会默认输出当前路径

4.输入ls c:会输出C盘路径

数组
C++中的数组类型:栈区数组,堆区数组,容器数组vector
| 栈区数组 | 堆区数组 | 容器数组 | |
|---|---|---|---|
| 定义与存储位置 | 栈区(Stack)中分配的数组,其生命周期与所在函数或代码块的执行周期相同。栈区内存由系统自动管理,分配和释放速度快,无法动态调整大小 |
在堆区(Heap)中分配的数组,其生命周期由程序员控制。堆区内存由程序员手动分配和释放,灵活性高,但管理复杂。 |
容器数组是指使用某种容器(如std::vector、std::list、std::array等)来存储和管理数组元素的数组。容器数组可以位于栈区或堆区,具体取决于容器的实现和存储的数据类型。 |
| 内存管理 | 系统自动完成,无需干预。当函数执行完毕后,栈区数组的内存会被自动释放。 |
由程序员负责手动分配和释放内存。如果不释放,可能导致内存泄漏。 |
容器数组的内存管理由容器本身负责,容器会根据需要自动调整内存大小,并提供方便的接口来访问和操作数组元素。 |
| 生命周期 | 所在函数或代码块的执行周期 | 程序员控制 | 取决于容器的实现和存储的数据类型。如果容器在栈区分配,其生命周期与所在函数或对象的生命周期相同;如果容器在堆区分配,则需要程序员手动销毁。 |
| 性能特点 | 访问速度快,因为栈区内存通常位于CPU的高速缓存附近。栈区数组的大小固定,无法动态调整。 |
访问速度相对较慢,因为堆区内存可能不连续,且需要额外的内存管理开销。但堆区数组的大小可以动态调整,灵活性高。 |
取决于容器的实现和存储的数据类型。一些容器(如std::vector)提供了快速的随机访问性能,而另一些容器(如std::list)则提供了快速的插入和删除性能。 |
栈区数组
初始化,不赋值默认全为零

初始化,手动赋值

for循环遍历
C++11之前版本

C++11之后版本

数组大小:sizeof(arr)
一个
int占四个字节,4 * 4 = 16

根据数组大小控制循环

栈区数组空间只能用编译时常量,不能用变量和运行时常量

数组是地址连续的空间
直接输出数组即输出数组的首地址

输出数组元素的地址要加取地址符
&

默认为16进制,转成整形,long long确保位数足够

注意,如果一个数组本身 + 2,并不代表其地址 + 2,而是相当于其向后+ 2 int值,其地址+ 8(1 int占四字节
相当于数组的头指针向后移动两位

通过地址访问数组(指针)

堆区数组
初始化

可以使用auto

其存储思路是存储数组的首地址,因此失去了数组的特性,无法使用C++11后的for循环遍历

可以使用C++11前的for循环遍历

同理,因其存储思路,其数组只有指针的大小(x64 64位程序指针8位,x86 32位程序指针4位)

注意!不要忘记对堆区数组占用空间进行释放

数组的复制
memcpy(dest, src, count) 用于从一个内存位置复制指定数量的字节到另一个内存位置。
dest: 指向目标内存位置的指针。
src: 指向源内存位置的指针。
count: 要复制的字节数。

容器数组Vector
首先要调用头文件

调用命名空间std,声明如下

不调用命名空间就加上前缀

设置数组大小

或者只初始化,自动获得数组大小

容器数组的遍历
1.传统的遍历方法

2.vector的迭代器(可以看成指针)
提供
begin()和end()方法,用于获取容器的起始和结束位置。
auto 是类型自动推导关键字,在这种情况下,itr 的类型是std::vector<int>::iterator。

基于范围的 for 循环(C++11 及以上)

容器数组的增加
vector.push_back()方法,在数组结尾插入内容

vector[] =,用数组的方法修改某下标的值

容器数组的查找
auto f = std::find(vector.begin(), vector.end(), target);std::find返回一个迭代器,指向找到的元素target。
注意,此时有元素
如果未找到,则返回异常。

用if防止报出异常
因为.end()并不是指向最后一个元素,而是指向最后一个元素之后的位置。没找到元素时返回.end()会导致未定义行为,因此报出了异常

此时没找到就不会输出,且不会报异常

如何返回下标呢?
迭代器并不支持输出

但是迭代器经过运算后支持输出,不过不能输出多个元素

输出多个只能用传统方法了

容器数组的删除
vector.erase(),由find找到该元素然后删除该元素,因此只能删除一个

要想删除所有的规定元素,就通过循环找到所有的位置,然后删除

但是要注意的是,数组的删除是即时的,当删除第一个元素时,后续元素位置前移,导致后边的元素位置对应不上
如图,位置数组记录
5的位置是6 11,但是当删除第一个5后,该数组最后的5位置就变成10了,导致vi.erase(11) 时访问越界报错

修改代码从后向前删除
vipo.rbegin()和vipo.rend()来从后向前遍历数组
vipo.rbegin()是 C++ 标准库中 std::vector 提供的反向迭代器(reverse iterator)的起始点。它返回一个指向容器最后一个元素的反向迭代器。

容器数组的插入
在数组尾插入还是使用
push_back();

还可以使用
emplace_back();他们之间会有效率的区别

在指定位置插入使用
inset(位置,插入元素);其余元素会依次后移

容器数组的排序
引入头文件
#include<algorithm>

使用
short(迭代器头, 迭代器尾)进行正序排序

使用使用
short(反迭代器头, 反迭代器尾)进行倒序排序

或者使用
std::greater<int>()一个模板实例化,int 是模板参数,表示比较的是整数。当作为第三个参数传递给 std::sort 时,它指示 std::sort 使用降序排序。

Vector数组的插入效率
push_back和emplace_back

简单来说,
push_back先将插入元素放在了容器外部,然后在容器内部分配了对应空间,之后将元素移了过去,具有额外的开销
而
emplace_back()直接就是在内部分配空间并构造的元素,降低了时间和空间的开销
运行程序并进入到汇编窗口,加断点是为了防止程序运行完自动停止

生成指令数量有明显差异

元素空间和内存空间
size()查看存储的元素数量
v1的初始化:
std::vector<int> v1;使用了默认构造函数。
默认构造函数创建一个空的向量,这意味着v1中没有任何元素。
因此,v1.size()返回0。
v2的初始化:
std::vector<int> v2(10);使用了指定大小的构造函数。
这个构造函数创建一个包含10个元素的向量。
因此,v2.size()返回10。
对于int类型,这些元素会被初始化为0(因为 int 的默认值是 0)。

capacity()查看数组实际存储空间

给数组进行手动扩容
resize();扩充元素数量,内存也会随之改变

reserve();只扩充内存数量



浙公网安备 33010602011771号