【c++】开发环境&IDE、常见调试方法(gdb等)、基础c++语法特性、算法OJ刷题、入门c++项目【持续更新】

1 开发环境&IDE

基本就是如下3款,个人使用体验:
vscode:优点-轻量化,插件多,便于远程调试,缺点-配置复杂
clion:优点-集成环境,最易于上手,缺点-商业软件,收费
visual studio:优点-开发大项目如qt等较为友好 ,缺点-软件太臃肿,太大,不能远程debug

1.1 vscode

vscode配置C/C++环境(超详细保姆级教学)
VSCode上搭建C/C++开发环境(vscode配置c/c++环境)Windows系统—保姆级教程

1.2 clion

CLion安装、配置、使用、调试(完全小白向)

1.3 visual studio

编程小白必看!Visual Studio 2022详细安装使用教程(C/C++编译器)
Visual Studio 2022基础使用操作总结

2 常见调试方法(gdb等)

2.1 debug入门

这个博主视频很不错,入门到深度均有涉及

c++调试技术

2.2 远程debug (以Mit 6.S081为例)

2.2.1 vscode远程debug

参考文献:
Mit6.s081环境配置踩坑之旅WSL2+VScode

步骤1:虚拟机网络配置

主要参考:
SSH连接linux虚拟机详细步骤(超详细)
其他参考:
【环境配置】【保姆级教程】VSCode SSH 连接 VMware虚拟机Linux Ubuntu 22.04 配置

步骤2:XV6及qemu环境搭建

qemu搭建完毕如下代表qemu成功:
在这里插入图片描述
复制xv6源码到本地,make qemu,如下代表xv6系统编译成功,ctrl+a松开后再按x退出qemu。
在这里插入图片描述
如上一个源码系统,如果我们不采用现代工具进行debug,使用原生shell进行debug,基本上就是要开两个shell,一个shell执行make qemu-gdb,也就是以debug模式打开qemu, 另一个shell用来调试,打断点之类的。
具体可参考:
课程翻译-3.9 XV6 启动过程
MIT 6S081 qemu-gdb debug调试新手指南!!!
这样做配置很复杂,对新手不友好。
具体过程:
设置gdb信任文件,我这里将所有都放开了,然后按照上面教程调试操作,这样每次都得手动搞一次,且查看源码很不方便。
在这里插入图片描述
在这里插入图片描述

步骤3:Vscode远程调试

上述gdb shell原生方式对新手不友好,所以直接使用vscode插件远程调试,这样既优雅又方便。
参考文档:
哈工大2022年 OS 图形化调试指南

VSCode调试xv6内核代码

2.2.2 clion远程debug

【持续更新…】

3 基础c++语法特性

基础入门:c++菜鸟博客
c++ 指针:除了印度口音以外,目前见到的讲的最好的教程

【强推】通俗易懂C/C++中的指针

c++ 菜鸟教程重点笔记:

比较好的面试题 b站up 码农mark 里面很多c++ 面试代码、csdn和google c++常见面试汇总

C++ 数据类型:const/volatile/mutable;C++11 新增类型;派生数据类型;类型别名;标准库类型;类型转换(基类指针对象可以访问派生类对象中的重写方法-因为原函数预制了虚函数(里面只是print这种),但是不能访问其他特有成员,派生类指针则可以访问派生类中各类函数)
C++ 变量作用域:类作用域
C++ 修饰符类型:C++ 中的类型限定符(const、volatile、restrict、mutable、static等实例)
C++ 存储类:extern、mutable 、thread_local (可见不同存储类说明符的实例)、static 存储类、extern 存储类、mutable 存储类、thread_local 存储类
C++ 函数:函数参数(传值调用、指针调用、引用调用)[指针调用 存入了指针变量,引用调用直接给了变量的内存地址,没有指针变量]
C++ 中数组:指向数组的指针、传递数组给函数、从函数返回数组(局部数组会被释放、函数内部分配的动态分配数组在函数结束时不会自动释放,注意内存泄露)
C++ 指针:C++ 指针详解-C++ 指针的算术运算(指针算术运算会根据指针的类型和大小来决定移动的距离)、C++ 指针 vs 数组(var[MAX]这样不能直接var++)、C++ 指针数组、C++ 指向指针的指针(多级间接寻址)、C++ 传递指针给函数、C++ 从函数返回指针
C++ 引用:C++ 引用 vs 指针、把引用作为参数、把引用作为返回值(注意对静态变量的引用)
C++ 基本的输入输出:标准输入流(cin)、标准错误流(cerr)、标准日志流(clog)
C++ 结构体(struct):结构体与类的区别
C++ vector 容器
C++ 数据结构
C++ 类 & 对象:类 & 对象详解(里面的每一种使用方式)c++拷贝构造函数【关注第二个例子,为什么是这样的输出结果,可以豆包问下,原因在于①拷贝构造函数的触发场景:通过已存在的对象初始化新对象(如 Line line2 = line1)、函数参数按值传递(如 display(line1))②深拷贝的实现:拷贝构造函数中为 ptr 分配新内存(ptr = new int),避免多个对象共享同一块内存。每个对象的 ptr 指向独立的内存地址,析构时不会导致双重释放。③析构函数的调用时机:临时对象(函数参数)在函数结束时销毁。局部对象(如 line1 和 line2)在作用域结束时销毁。】c++友元函数【可以问下豆包具体的例子,原文的例子不友好,友元函数是 C++ 中一种特殊的函数,它可以访问类的私有(private)和保护(protected)成员,打破了类的封装性。虽然这看似违背了面向对象的封装原则,但在某些场景下非常实用。友元函数是 C++ 中打破封装的 “特殊通道”,主要用于:实现类之间的高效数据交互、简化运算符重载(如输入输出)、让外部函数直接操作类的内部状态】、c++内联函数【C++ 内联函数详解在 C++ 中,内联函数(Inline Function)是一种特殊的函数,编译器会尝试将其代码直接嵌入到调用处,而非通过常规的函数调用机制(如压栈、跳转、返回)执行。这样可以减少函数调用的开销,提高程序执行效率。内联函数的核心特点:编译时展开:编译器会将函数体直接替换到调用处,类似于宏(Macro)。减少调用开销:避免了压栈、跳转和返回等操作,适合短小频繁的函数。保持函数特性:与普通函数一样有类型检查、作用域等特性,比宏更安全。建议性关键字:inline 只是对编译器的建议,是否真正内联由编译器决定。】C++ 类的静态成员【静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。】 上面哪个c++特性最重要

C++ 继承:访问控制和继承、继承类型
C++ 重载运算符和重载函数:C++ 中的运算符重载【直接豆包,本身文章写得不好,让自定义类型的操作更符合直觉(如 a + b 替代 add(a, b))。重载运算符的参数:①成员函数:隐含 this 指针,参数个数比运算符操作数少一个(如 operator+ 只需一个参数)。②非成员函数(通常为友元):需要显式指定所有参数(如 operator<< 需要两个参数)。】运算符重载实例【太细节零碎了,没有看】
C++ 多态:纯虚函数【具体看文章倒数部分下面的详细讲解】、实例1【虚析构函数】
C++ 数据抽象:文章中的内容不需要了解,只需要知道-抽象把代码分离为接口和实现,如果改变底层实现,接口都不会受到影响,只需要将最新的实现重新编译即可。
C++ 接口(抽象类):文章中的内容不需要了解,只需要知道-如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类
C++ 文件和流
C++ 异常处理:定义新的异常
C++ 动态内存:对象的动态内存分配
C++ 命名空间:using 指令、嵌套的命名空间
C++ 模板:函数模板、类模板
C++ 预处理器:条件编译、C++ 中的预定义宏
C++ 信号处理:signal() 函数、raise() 函数【注意SIGINT 对应 2是因为Linux系统中常见的信号量对应的值】
C++ 多线程:全部的内容,但是这块写的不详细需要自己找其他资料学习 上面哪个c++特性最重要

4 算法OJ刷题

4.1 推荐刷题网站

基础:数据结构
博客:
十年所学,终成《代码随想录》
labuladong 的算法笔记
github leetcode关键字搜索

4.2 Clion leetcode本地debug刷题指南

leetcode 官方需要开会员才能进行debug调试,不方便,可以直接使用本地clion进行插件OJ。
主要参考文献:
CLion安装、配置、使用、调试(完全小白向)
技巧篇|周末使用Clion愉快刷题 Leetcode(C++)吧
其余参考:
github-aiyolo/leetcode-debug
使用clion刷leetcode
CLion的leetcode插件本地调试方法
使用Clion中的LeetCode刷题插件步骤及常见错误
CLion 配置,LeetCode配置,调试配置

https://blog.csdn.net/philamar/article/details/119752087
https://blog.csdn.net/qq_40114716/article/details/123351936
https://blog.csdn.net/csdnzzt/article/details/133008645

4.2.1 leetcode插件&debug插件安装

安装leetcode官方插件和C/C++ Single File Execution(为了单文件调试方便–在 CMake 项目中,如果想要构建和运行单个 c/cpp 文件,需要在 CMakeLists.txt 需要配置声明 add_executable() ,使用这个插件可以轻松构建和运行单个文件)
在这里插入图片描述
安装完了之后,插件输入leetcode账号ak,sk,同时设置本地tempfile地址(用于下载leetcode题目),此时插件安装完毕
在这里插入图片描述

4.2.2 基础clion 配置

步骤1:将工具链设置成内置mingGW
在这里插入图片描述
步骤2:新建刷题项目,建议c++ 17
在这里插入图片描述
步骤3:在自己项目的目录下,新建如下2个文件
leetcode.h 基础数据结构和来自于Leetcode Playground方便我们将测试用例字符转化为正确的参数。
stdc.h 大家用了都说好的"万能头"文件,主要为了方便主动导入,也可以自己按照所需维护一个头文件替代。
文件git下载地址
在这里插入图片描述
步骤4:配置 Leetcode Editor 模板
配置如下3处:
(1):Custom Template 需要勾选 True
(2):Code FileName = leetcode_num_${question.frontendQuestionId}
(3):Code Template复制以下的代码,简单分析一下就是我们通过导入 stdc.h 和 leetcode.h(在stdc.h中被导入)头文件,避免了我们需要根据代码手动导入头文件,由于 leetcode 中的题目大部分都是定义了一个 Solution 类,如果在一个项目中引入多个题目会导致类重复定义错误,所以我们根据题号创建不同的 namespace ,这样就避免了重复定义,并使用了 using 语法简化了调用,美中不足的是我们并没有自动构建对题目的调用和对测试用例的代码编写,这就是需要我们手动参与的地方,不过有了 leetcode.h 的加持,这一些也不是难事,在下文我们会展示如何使用。【转载–简绘Android】

//import universal *.h
\#include "../../../stdc.h"

using namespace std;


${question.content}

namespace solution${question.frontendQuestionId}{
    ${question.code}
}

using namespace solution${question.frontendQuestionId};
int main() {
    Solution solution = Solution();

    return 0;
}

在这里插入图片描述

4.2.3 刷题以及debug

步骤1:插件加载题目
配置完成后,点击任意题目后,就会生成下图所示的目录结构(这是按照Java的目录结构生成的,对我们并不影响)
,观察生成的源代码文件,这个题目需要定义结构体 ListNode 在这里并没有出现警告,因为我们的 leetcode.h 已经包含了定义,这时候我们只要右键选择 Add executable for single c/c++ 按钮并点击 CMake 刷新按钮,就可以在上方的运行按钮看到一个新的可运行 CMake Application,到这里你就可以愉快的利用 IDE 的代码提示开心的刷题了。
在这里插入图片描述
利用编辑栏的悬浮窗口,你可以测试和提交自己的代码,如下图所示。
在这里插入图片描述

步骤2:debug题目
如果你提交答案被系统驳回,并告诉了你测试用例,你也可以很容易的去调试它,系统通常给我们的测试用例形如输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] ,观察我们的形参,我们需要组合成 ListNode,对于最后的结果 输出:[8,9,9,9,0,0,0,1]我们最后的返回值为 ListNode ,有了 leetcode.h 现在不需要你去自己构建和翻译链表,stringToListNode 和 listNodeToString轻松帮你搞定这一切。这样,一个题目就轻轻松松的跑起来了。

leetcode题目2参考代码

//import universal *.h
#include "../../../stdc.h"

using namespace std;


//给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 
//
// 请你将两个数相加,并以相同形式返回一个表示和的链表。 
//
// 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 
//
// 
//
// 示例 1: 
// 
// 
//输入:l1 = [2,4,3], l2 = [5,6,4]
//输出:[7,0,8]
//解释:342 + 465 = 807.
// 
//
// 示例 2: 
//
// 
//输入:l1 = [0], l2 = [0]
//输出:[0]
// 
//
// 示例 3: 
//
// 
//输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
//输出:[8,9,9,9,0,0,0,1]
// 
//
// 
//
// 提示: 
//
// 
// 每个链表中的节点数在范围 [1, 100] 内 
// 0 <= Node.val <= 9 
// 题目数据保证列表表示的数字不含前导零 
// 
//
// Related Topics 递归 链表 数学 👍 11150 👎 0


namespace solution2{
    //leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            int len1=1;//记录l1的长度
            int len2=1;//记录l2的长度
            ListNode* p=l1;
            ListNode* q=l2;
            while(p->next!=NULL)//获取l1的长度
            {
                len1++;
                p=p->next;
            }
            while(q->next!=NULL)//获取l2的长度
            {
                len2++;
                q=q->next;
            }
            if(len1>len2)//l1较长,在l2末尾补零
            {
                for(int i=1;i<=len1-len2;i++)
                {
                    q->next=new ListNode(0);
                    q=q->next;
                }
            }
            else//l2较长,在l1末尾补零
            {
                for(int i=1;i<=len2-len1;i++)
                {
                    p->next=new ListNode(0);
                    p=p->next;
                }
            }
            p=l1;
            q=l2;
            bool count=false;//记录进位
            ListNode* l3=new ListNode(-1);//存放结果的链表
            ListNode* w=l3;//l3的移动指针
            int i=0;//记录相加结果
            while(p!=NULL&&q!=NULL)
            {
                i=count+p->val+q->val;
                w->next=new ListNode(i%10);
                count=i>=10?true:false;
                w=w->next;
                p=p->next;
                q=q->next;
            }
            if(count)//若最后还有进位
            {
                w->next=new ListNode(1);
                w=w->next;
            }
            return l3->next;
        }
    };

//leetcode submit region end(Prohibit modification and deletion)

}

using namespace solution2;
#define L1 "[9,9,9,9,9,9,9]"
#define L2 "[9,9,9,9]"
#define RESULT "[8,9,9,9,0,0,0,1]"
int main() {
    Solution solution = Solution();
    ListNode *node=solution.addTwoNumbers(stringToListNode(L1), stringToListNode(L2));
    cout << listNodeToString(node) << endl;
    assert(RESULT == listNodeToString(node));
    return 0;
}

在这里插入图片描述

5 入门c++项目

下面是我工作2年接触到的一些有意思的c++ 项目:
1、CAD方向:
OCCT 开源几何引擎
youtube occt讲解
知乎occt 专业博主推荐的 occt项目
在这里插入图片描述
2、QT:
可以用来自己做一些桌面级开发,一般得visual studio

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值