【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_backemplace_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();只扩充内存数量

posted @ 2025-04-11 11:34  plusu  阅读(61)  评论(0)    收藏  举报