初学者无痛C转C++

初学者无痛C转C++

文章目录

为什么要转C++

首先,对于C语言,它初见虽然简单,但是深入后确实非常的难并且不方便的。

例如C语言使用排序qsort必须要写排序函数,但是用C++的std::sort就很方便,而且对于一些常见的数据结构C++也有相对应的STL容器如:queue,stack,vector
最重要的还是C++在C++11之前和C语言相差不大,如果仅仅是打算法竞赛那么C++=C + STL,转起语言来几乎完全没有压力

C++语言基础

对于初学者而言,我们只需要记住如下代码

#include<bits/stdc++.h>usingnamespace std;intmain(void){return0;}

初看这个和C语言极为相似除了using namespace std;和#include <bits/stdc++.h>
对于using namespace std;我们只需要记住不需要了解,如果有人想了解的话可以去搜下C++的命名空间

然后对于#include <bits/stdc++.h>是C++的万能头(竞赛专用,你下的gcc里面是没有这个的,需要额外配置),后续内容中如果学习C++只为了打算法竞赛,那么后续所有头文件都不需要记忆

C++如何输入输出

#include<iostream>#include<string>usingnamespace std;intmain(void){int n; string s; cin >> n; cin >> s; cout << n <<"\n"<< s << endl;}

上述头文件的iostream就相当于C的stdio.h,而string是C++特有的字符串对象
其中C输入为scanf而且还需要记住类似于%d,%s之类的格式化符号,而C++之间cin就可以了,输出的话直接cout

C++string相关

对于C语言我们处理字符串很痛苦(虽然C++也很痛苦),但C++处理字符串却比C语言简单多了

以下列举一些本人常用的字符串处理方法

去除前导空格

#include<iostream>#include<string>usingnamespace std;intmain(void){ string s;while(getline(cin , s)){int pos = s.find_first_not_of(" "); s.erase(0, pos); std::cout << s <<"\n";} std::cout <<"hello , world";}

提示:C++的cin会自动去除掉前导空格
如果是去除前导0的话直接把" "换成"0"就可以了

提取和拼接子串

#include<iostream>#include<string>usingnamespace std;intmain(void){ string s ="hello , world";//从第0个位置开始截取长度为5的子串 string s1 = s.substr(0,5);//从第6个位置开始截取后面的所有字符 string s2 = s.substr(6);//将s1和s2拼接位一个字符串 string s3 = s1 + s2;//运行下二者输出的结果相同 cout << s1 << s2 <<"\n"; cout << s3;}

string截取子串的成员函数为substr相关解释已经在注释当中

一些常用的C++操作

C++sort(排序函数的用法)

#include<algorithm>#include<iostream>#include<string>usingnamespace std;boolcomp(int& a ,int& b){return a > b;}intmain(void){int a[1000]={0,1,1,4,5,1,4};//这个sort第一个参数是这是你要排序的起始位置,第二个参数是终止位置sort(a +1, a +1+6);for(int i =1; i <=6; i++) cout << a[i];//C++排序默认的升序 std::cout <<"\n";//如果我们要用降序的话可以添加第三个参数,也就是我们的自定义比较函数sort(a +1, a +1+6, comp);for(int i =1; i <=6; i++) cout << a[i];}

C++的sort排序的时间复杂度是O(nlogn)比大家常用的冒泡排序快速多了,所有如果要有排序的话推荐一直用这个,至于comp函数,我这里使用了&也就是引用,这样可以避免复制数值,但是大家在平时使用时不添加引用符也可以正常运行

数组去重

#include<algorithm>#include<iostream>#include<string>#include<vector>usingnamespace std;intmain(void){//使用原始数组的方法//数组去重需要我们先排序int a[1000]={0,1,1,4,5,1,4};sort(a +1, a +1+6);//这里去重int* pos =unique(a +1, a +1+6);//这里计算去重后的数组个数int new_count = pos -(a +1);for(int i =1; i <= new_count; i++) std::cout << a[i]<<" ";}//如果不打算了解C++进阶相关,这下面部分可以不看#include<algorithm>#include<iostream>#include<vector>intmain(void){//使用vector(动态数组的做法)  std::vector<int>arr ={0,1,1,4,5,1,4};//这里至于为什么使用arr.begin(),这里暂不讲解,在进阶部分再讲解 std::sort(arr.begin()+1, arr.begin()+1+6);//这里返回的是一个迭代器auto pos =unique(arr.begin()+1, arr.begin()+1+6); arr.erase(pos , arr.end());return0;}

unique函数返回的是检查范围的数据,如果有相同的则移到传入的末尾,之后直接计算剩余元素数量后使用去重过后的数组就行了,详细操作见上述代码

二分查找

在这里插入图片描述
#include<algorithm>#include<iostream>#include<vector>#include<stack>#include<queue>#include<map>#include<set>usingnamespace std;intmain(void){//这里为了演示,我这边就直接用有序数组了int a[105];for(int i =1; i <=100; i++) a[i]= i;//查找第一个小于等于25的元素int* lb1 = std::lower_bound(a +1, a +101,25);int index1 = lb1 - a;// 计算索引 std::cout <<"elem is"<<*(lb1)<<" index is"<< index1 << endl;//查找第一个大于25的元素int* lb2 = std::upper_bound(a +1, a +101,25);int index2 = lb2 - a;// 计算索引 std::cout <<"elem is"<<*(lb2)<<" index is"<< index2 << endl;int* result = std::lower_bound(a +1, a +101,101);//二分超出范围的话if(result == a +101){ std::cout <<"lower_bound(101) return a+101\n";// 因为数组中没有不小于101的元素}return0;}

STL容器相关

常见的STL容器使用

这部分设计数据结构,例如:栈,队列,红黑树,二叉搜索树

常见队列

#include<algorithm>#include<iostream>#include<queue>#include<vector>intmain(void){ std::queue<int>q;//这里模拟插入数据for(int i =0; i <10; i++) q.push(i);//一般我们是不知道队列里面的元素个数的,所以我们一般用while语句来处理//这里的empty返回的是一个bool变量,如果不了可以理解为true = 1(判断为真),false = 0(判断为假)while(!q.empty()){//队列可以查看队头和队尾的元素//其中队头的元素是第一个被插入的元素 std::cout << q.front()<<" "<< q.back()<<"\n";//这里默认弹出队头元素 q.pop();}//双端队列和普通队列的区别就是可以弹出和插入元素到队头和队尾的任意一部分 std::deque<int>qu;for(int i =0; i <10; i++){ qu.push_back(i);//qu.push_front(i);}while(!qu.empty()){ std::cout << qu.front()<<" "<< qu.back()<<"\n";//弹出队尾 qu.pop_back();//弹出队首 qu.pop_front();}}

C++的队列使用和声明极为简单,其中内部实现为一个数组,是根据先进先出(FIFO)思想设计的,所有上述操作时间复杂度都为O(1)
如果使用了using namespace std;,那么上述的的"std::"可以去掉

#include<algorithm>#include<iostream>#include<vector>#include<stack>#include<queue>usingnamespace std;intmain(void){ stack<int>s;for(int i =0; i <10; i++) s.push(i);while(!s.empty()){//默认弹出最后一个元素 std::cout << s.top()<<" "; s.pop();}}

栈和队列的使用方式差不多,最具有分辨力的区别是:栈是根据先进后出(FILO)的思想设计的

map(键值对)

键值对又称字典,是一个相互进行映射(一个键对应一个值)的STL容器,内部实现为红黑树或(二叉搜索树),其插入的时间复杂度为O(logn)是一个在算法竞赛中很实用的STL容器

#include<algorithm>#include<iostream>#include<vector>#include<stack>#include<queue>#include<map>usingnamespace std;intmain(void){ std::map<int,int>mp;int temp =114514;for(int i =0; i <10; i++){//插入数据(这两种方法都可以)if(i <4) mp[i]= temp *(10- i);else mp.insert({i , temp *(10- i)});}//遍历mapfor(auto&[key , value]: mp){//这里的key代表第一个也就是键,第二个代表值,这两个可以随意命名 std::cout <<"mp["<< key <<"] = "<< value <<"\n";//遍历是根据键的大小来输出的,也可以自定义排序(属于进阶内容,新手不必要掌握)}//查找操作,其中时间复杂度为O(logn)if(mp.find(2)!= mp.end()) std::cout <<"Yes";if(mp.find(10)== mp.end()) std::cout <<"No"; std::cout <<"\n";int idx =0;while(1){ mp.erase(idx); idx++;if(mp.empty()){ std::cout <<"已弹出所有元素";break;}}return0;}

我们这里只讲map的插入,删除和遍历以及查找这种基础内容

还有一种map是unordered_map,其结构和map很像,这里不再介绍。
unordered_map和map的区别是,map是红黑树,而它的实现为哈希表,查找,插入的速度为O(1),并且unordered_map是无序的

set(集合)

set和map极为相似,你可以把set理解为只有一个value的的map(一般map有键和值),其中时间复杂度和map基本一致,这里不再介绍

#include<algorithm>#include<iostream>#include<vector>#include<stack>#include<queue>#include<map>#include<set>usingnamespace std;intmain(void){ set<int>s;for(int i =0; i <100; i++) s.insert(0); s.insert(5); s.insert(3); s.insert(114514);//set里面是自动有序而且是会自动去重的for(auto i : s) cout << i <<" "; cout <<"\n";if(s.find(3)!= s.end()) cout <<"Yes"<<" ";if(s.find(6)== s.end()) cout <<"No"<<" "; cout <<"\n";//查看集合的大小 cout << s.size()<<"\n";for(auto i : s) s.erase(i); cout << s.size()<<"\n";return0;}

C++进阶相关

标准输入输出加快

 ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);

lambda表达式(无名函数)

 std::vector<int>arr ={1,1,4,5,1,4}; std::sort(arr.begin(), arr.end(),[](int& a ,int& b){return a > b;});

这里只不过是将函数换成了lambda表达式

优先对列自定义排序

structNode{int x , y;booloperator<(Node &a)const{return x < a.x;};};intmain(void){ std::priority_queue<Node>q;}

对于我们自定义的结构体它是无法直接比较大小的,那么直接使用operator进行重载,可以使它们在一个陌生的结构体有明确的大小顺序
由于作者赖的写了,这里简单的介绍下优先队列。优先队列就是我们所说的堆,其中内部是二叉搜索树,插入和弹出都是logn的复杂度,堆顶元素默认是最大(最小)元素

stringstream流

#include<vector>#include<string>#include<sstream>#include<iostream>usingnamespace std;intmain(void){//将字符类型转化为整数 std::string s ="1 2 3 4 5 6"; std::vector<int>arr; stringstream stream(s);int num;while(stream >> num){ arr.push_back(num);}for(auto i : arr) cout << i <<" "; cout <<"\n";//将数据为某个字符串分割 string data ="apple,banana,orange,grape"; stringstream ss(data); string fruit;while(getline(ss, fruit,',')) cout << fruit << endl;return0;}

结语

以上内容属于C++基础内容,如果以后有从事C++相关行业的话属于基础中的基础,相反则需要掌握一些C++基础内容,虽然文章中分为了基础和进阶,但即便是只打算打一些简单的算法比赛,以上编码技巧也只属于基础内容

Read more

开发兜不住?让数据库来兜底:金仓 SQL 防火墙的工程化实践

开发兜不住?让数据库来兜底:金仓 SQL 防火墙的工程化实践

开发兜不住?让数据库来兜底:金仓 SQL 防火墙的工程化实践 在真实的生产环境中,数据库安全从来不是“写完代码就结束”的问题,而是一个贯穿系统生命周期的持续对抗过程。哪怕你已经严格执行参数化查询、ORM 框架封装、输入校验等规范,仍然无法保证系统绝对无注入风险——遗留系统、动态 SQL、第三方组件、甚至临时脚本,都会成为潜在突破口。 这也是为什么越来越多企业开始将防线下沉到数据库层:既然应用层不可控,那就让数据库成为最后一道“强制执行的安全边界”。 本文结合 KingbaseES 的 SQL 防火墙机制,从原理、模式设计到性能表现,讲清楚它是如何在工程上解决 SQL 注入问题的。 一、SQL 注入的本质:语义劫持,而不是“字符串拼接问题” 很多人对 SQL 注入的理解还停留在“拼接字符串不安全”,但从数据库视角来看,本质其实是: 攻击者篡改了 SQL 的语义结构(

By Ne0inhk

Go语言的主流框架和解决超高并发的三高微服务框架对比分析

在Go语言生态中,主流的Web框架和应对“三高”(高并发、高可用、高可扩展)场景的微服务框架,经过多年的发展已经非常清晰。简单来说,Gin 是目前应用最广泛的通用Web框架,而像 go-zero、Kratos、KiteX 等则是专为“三高”微服务架构设计的“全家桶”式解决方案。 下面为你详细拆解这两大类框架。 一、主流通用Web框架:轻量、灵活、高性能 这类框架主要解决API构建、路由和中间件管理等Web层问题,是构建单体应用或微服务API层的良好基础。 Gin:目前的“默认选项”,性能高、社区庞大、中间件丰富,极易上手。如果你刚开始接触Go或项目需求明确,选择Gin会非常稳妥。 Fiber:受Express.js启发,语法对Node.js开发者很友好。它基于fasthttp构建,在性能基准测试中表现极为出色。适合追求极致性能、且不介意与标准库net/http不完全兼容的场景。 Echo:一个成熟且平衡的框架,

By Ne0inhk
必收藏!小白也能懂:Agent、Skills、MCP和A2A大模型架构完全指南

必收藏!小白也能懂:Agent、Skills、MCP和A2A大模型架构完全指南

文章详解AI Agent四大核心概念:Agent作为智能决策主体,Skills提供原子化能力封装,MCP实现标准化工具调用,A2A支持Agent间协作。这些技术共同构建了从单Agent自主执行到多Agent协同工作的完整技术栈,解决了智能体的自主性、模块化能力、工具调用和互操作等核心问题,助力开发者快速构建专业级AI应用。 一、Agent、Skills、MCP和A2A的核心概念总览 1、Agent (代理/智能体):自主决策与执行的“大脑”。 AI Agent是2026年AI生态的核心概念,是基于人工智能技术构建的、具备感知环境、理解信息、自主推理决策、自主规划与执行动作并持续与环境/其他主体交互,以自主达成预设或动态生成目标的数字智能实体。2026年的智能体不是在回答问题,而是在完成任务。其突破了传统问答式、生成式AI的能力边界,可像人类员工一样独立处理复杂综合性任务。它以大模型为核心引擎,整合规划、记忆、工具调用与行动执行四大能力,形成「感知 - 认知 - 决策 - 执行 - 反馈」的完整智能闭环,

By Ne0inhk
超越Tomcat的Spike (一):使用netty搭建Http服务器

超越Tomcat的Spike (一):使用netty搭建Http服务器

超越Tomcat的Spike (一):使用netty搭建Http服务器 * 🏆 引言 * 🚀 Netty的魅力所在 * 什么是Netty? * Netty vs 传统服务器 * 🏗️ Spike项目架构设计 * 项目结构 * 核心组件架构 * 💻 核心代码实现 * 服务器初始化与启动 * 请求处理逻辑 * ⚡ 性能测试与对比 * 并发处理能力测试 * 内存占用对比 * 📱 应用案例 * 案例一:高并发API网关 * 案例二:实时数据推送服务 * 🎯 核心优势分析 * 1. 非阻塞异步模型 * 2. 零拷贝技术 * 3. 可扩展性强 * 🔮 未来展望 * Spike 2.0 规划 * 应用场景扩展 * 📝 代码优化建议 * 1. 事件循环组优化 * 2. 内存管理优化 * 🏁 总结 🏆 引言 在现代Web应用开发中,HTTP服务器是构建任何网络服务的基础。传统的Tomcat、Jetty等服务器虽然功能强大,但在高性能场景下往往显得力不从

By Ne0inhk