├── .gitignore ├── Cpp-Exerceise ├── CMakeLists.txt ├── chap00-经典问题 │ ├── 00-1_constObject.cpp │ ├── 00-2_thisMember.cpp │ ├── 00-3_assignmengCopyConstructor.cpp │ ├── C++进阶(00-1) const 对象.md │ ├── C++进阶(00-2) 成员函数和成员变量都属于具体对象吗?.md │ └── C++进阶(00-3) 赋值.md ├── chap01-封装与继承 │ ├── 01-1_struct.cpp │ ├── C++进阶(1) 面向对象.md │ ├── C++进阶(2) 封装.md │ └── images │ │ ├── image-20200916205403420.png │ │ ├── image-20200916213339665.png │ │ ├── image-20200916213409072.png │ │ └── image-20200916215156993.png ├── chap02-类的形态 │ ├── 02-1_structClass.cpp │ ├── 02-2_operator.cpp │ ├── 02-2_operator.h │ ├── 02-2_operatorMain.cpp │ └── C++进阶(3) 类.md ├── chap03-构造函数 │ ├── 03-1_initialize.cpp │ ├── 03-2_constructor.cpp │ ├── 03-3_constructorWithPara.cpp │ ├── 03-4_intArray.cpp │ ├── 03-4_intArray.h │ ├── 03-4_intArrayMain.cpp │ ├── 03-5_defaultConstructor.cpp │ ├── 03-6_deepCopyVSCopy.cpp │ ├── C++进阶(4) 构造函数.md │ └── images │ │ └── image-20201003085352771.png ├── chap04-初始化列表 │ ├── 04-1_constMember.cpp │ ├── 04-2_InitializeList.cpp │ ├── 04-3_constMemory.cpp │ └── C++进阶(5) 初始化列表.md ├── chap05-对象构造顺序 │ ├── 05-1_LocalVariable.cpp │ ├── 05-2_HeapVariable.cpp │ ├── 05-3_GlobalVariable.cpp │ ├── 05-3_Global_1.cpp │ ├── 05-3_Global_2.cpp │ ├── 05-3_Global_3.cpp │ ├── 05-3_test.h │ └── C++进阶(6) 对象的构造顺序.md ├── chap06-析构函数 │ ├── 06-1_intArray.cpp │ ├── 06-1_intArray.h │ ├── 06-1_intArrayMain.cpp │ ├── 06-2_deconstructor.cpp │ ├── 06-3_deconstructorOrder.cpp │ └── C++进阶(7) 析构函数.md ├── chap07-临时对象 │ ├── 07-1_tempVariable.cpp │ ├── 07-2_initVariable.cpp │ ├── 07-3_tempVariableLiftTime.cpp │ └── C++进阶(8) 临时对象.md ├── chap08-静态成员变量 │ ├── 08-1_countObjectNumber.cpp │ ├── 08-2_staticFunction.cpp │ ├── 08-3_countObjectNumSafe.cpp │ ├── C++进阶(8) 类的静态成员变量与静态成员函数.md │ └── images │ │ └── image-20201005100650197.png ├── chap09-二阶构造模式 │ ├── 09-1_constructorReturn.cpp │ ├── 09-2_intArray.cpp │ ├── 09-2_intArray.h │ ├── 09-2_intArrayMain.cpp │ ├── 09-3_TwoPhaseCons.cpp │ ├── C++进阶(9) 二阶构造模式.md │ └── images │ │ ├── image-20201005104622013.png │ │ └── image-20201005104816838.png ├── chap10-友元 │ ├── 10-1_friendFunction.cpp │ ├── 10-2_friendClass.cpp │ ├── C++进阶(10) 友元.md │ └── images │ │ └── image-20201005111132417.png ├── chap11-函数重载 │ ├── 11-1_overLoading.cpp │ ├── 11-2_extendSystemFunction.cpp │ └── C++进阶(11) 函数重载.md ├── chap12-操作符重载 │ ├── 12-1_ComplexAdd.cpp │ ├── 12-2_operator.cpp │ ├── 12-3_ClassOperator.cpp │ ├── 12-4_Complex.cpp │ ├── 12-4_Complex.h │ ├── 12-4_ComplexMain.cpp │ ├── 12-5_intArray.cpp │ ├── 12-5_intArray.h │ ├── 12-5_intArrayMain.cpp │ └── C++进阶系列(12) 操作符重载.md ├── chap13-智能指针 │ ├── 13-1_MemoryLeak.cpp │ ├── 13-2_autoPointer.cpp │ └── C++进阶(13) 智能指针.md ├── chap14-操作符 │ ├── 14-1_logicalOperator.cpp │ ├── 14-2_trackOfLogicalOperator.cpp │ ├── 14-3_commaOperator.cpp │ ├── 14-4_overloadCommaOperator.cpp │ └── C++进阶(14) 你忽视的操作符.md └── chap15-类型转换 │ ├── 15-1_CTypeTrans.cpp │ ├── 15-2_CppClassTypeTrans.cpp │ ├── 15-3_ClassTypeToBuildType.cpp │ ├── 15-4_TransConstrClassTypeToClassType.cpp │ ├── C++进阶(15) 类型转换.md │ └── images │ └── image-20201019211319320.png ├── Git ├── [Git札记 1] GitHub 使用指南.md ├── [Git札记 2] Github 常用操作及其命令.md ├── [Git札记 3] Git基本概念及其配置.md ├── [Git札记 4] Git提交更新至仓库.md ├── assets │ └── image-20190819080159879.png └── images │ ├── add_ssh.png │ ├── apply.png │ ├── branch.png │ ├── create.png │ ├── create_comp.png │ ├── create_repository.png │ ├── description.png │ ├── desktop.png │ ├── git.png │ ├── git_add.png │ ├── git_commit.png │ ├── git_life.png │ ├── git_staus.png │ ├── new_clone.png │ ├── new_ssh.png │ ├── push.png │ ├── rep_url.png │ ├── setting.png │ ├── sshandgpg.png │ ├── tra_cvs.png │ ├── update_github.png │ ├── upload.png │ └── wechat.png ├── Linux ├── Linux 命令速查手册(一)帮助命令.md ├── Linux 命令速查手册(三)文本处理.md ├── Linux 命令速查手册(二)文件管理及目录管理.md ├── Linux 命令速查手册(五)用户管理工具.md ├── Linux 命令速查手册(四)磁盘管理.md └── [转载] Shell脚本编程30分钟入门.md ├── Others ├── Books │ └── Pro_Git.pdf ├── LinuxProbe.pdf ├── Mac 新手上路.md └── 数据挖掘:概念与技术(第三版)中文版.pdf ├── Python ├── Numpy │ ├── Python核心编程-Numpy系列(一).md │ ├── Python核心编程-Numpy系列(七).md │ ├── Python核心编程-Numpy系列(三).md │ ├── Python核心编程-Numpy系列(二).md │ ├── Python核心编程-Numpy系列(五).md │ ├── Python核心编程-Numpy系列(六).md │ └── Python核心编程-Numpy系列(四).md └── Python基本语法笔记 │ ├── 1. 预备知识.md │ ├── 10. OOP in Python.xmind │ ├── 14. 迭代器协议.xmind │ ├── 2. Python基础语法.md │ ├── 2. Python基础语法_question.md │ ├── 3. Python快速面面观(上).xmind │ ├── 4. Python快速面面观(下).xmind │ ├── 5. 玩转Python中的List.xmind │ ├── 6. Python 中的函数与函数式编程.xmind │ ├── 8. 闭包.xmind │ ├── 9. 装饰器.xmind │ ├── 函数库.xmind │ └── 第三节 Python基础语法.md ├── README.md ├── images └── wechat.png ├── 数据库 └── SQL必知必会 │ ├── SQL学习笔记1-SQL语句.md │ ├── SQL必知必会(13) 索引.md │ ├── images │ ├── image-20200915223249514.png │ ├── image-20200915223618036.png │ ├── image-20200915224105762.png │ ├── image-20200915225428293.png │ ├── image-20200924143802668.png │ ├── image-20200924144457031.png │ ├── image-20200927150049618.png │ ├── image-20201005162519814.png │ └── image-20201013214901671.png │ ├── 搞定SQL系列(1)SQL语句.md │ ├── 搞定SQL系列(10) 游标.md │ ├── 搞定SQL系列(11) 当我们在谈论数据库调优时,我们在谈论什么?.md │ ├── 搞定SQL系列(12) 数据表的范式,你知道么.md │ ├── 搞定SQL系列(2)检索数据.md │ ├── 搞定SQL系列(3) 数据过滤.md │ ├── 搞定SQL系列(4) 聚集函数.md │ ├── 搞定SQL系列(5) 子查询.md │ ├── 搞定SQL系列(6) 连接表.md │ ├── 搞定SQL系列(7) 视图.md │ ├── 搞定SQL系列(8) 存储过程.md │ └── 搞定SQL系列(9) 事务.md ├── 数据结构与算法 ├── images │ ├── image-20201002101803574.png │ └── image-20201005154025200.png ├── 搞定动态规划系列(1) 贪心算法.md ├── 搞定动态规划系列(2) 暴力递归.md ├── 搞定动态规划系列(3) 备忘录.md ├── 搞定动态规划系列(4) 动态规划.md └── 搞定动态规划系列(5) 经典问题.md ├── 笔试面试系列 ├── images │ ├── image-20201007111610236.png │ ├── image-20201007112831433.png │ └── image-20201012221352261.png ├── 如果我是面试官系列(1) C++篇.md ├── 如果我是面试官系列(2) 网络篇.md ├── 如果我是面试官系列(3) 排序算法.md ├── 如果我是面试官系列(4) SQL篇.md └── 校招笔试 │ ├── 01-美团 │ ├── 01-01_satisfyCookie.cpp │ ├── 01-02_numOfPromotion.cpp │ └── 01-03_rotarySushi.cpp │ ├── 02-01_ClockinScenicSpots.cpp │ ├── 03-01_MathPro.cpp │ ├── 03-2_01bag.cpp │ └── CMakeLists.txt └── 网络编程 ├── images ├── image-20201007152244901.png ├── image-20201007164022801.png ├── image-20201007203614107.png └── 四次挥手.pptx ├── 网络编程入门(1) TIME_WAIT.md └── 网络编程入门(2) 远方的你还在嘛?.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Folder view configuration files 2 | .DS_Store 3 | Desktop.ini 4 | 5 | # Thumbnail cache files 6 | # ._* 7 | Thumbs.db 8 | 9 | # Files that might appear on external disks 10 | .Spotlight-V100 11 | .Trashes 12 | 13 | # Compiled Python files 14 | *.pyc 15 | 16 | # Compiled C++ files 17 | *.out 18 | 19 | # Application specific files 20 | venv 21 | node_modules 22 | .sass-cache 23 | 24 | # Temp File 25 | *.swp 26 | *.swa 27 | *.swo 28 | 29 | .idea 30 | .idea/* 31 | 32 | cmake-build-debug/ 33 | 34 | -------------------------------------------------------------------------------- /Cpp-Exerceise/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(Cpp_Exerceise) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | #chapter 00 经典问题 7 | add_executable(00-1_constObject chap00-经典问题/00-1_constObject.cpp) 8 | add_executable(00-2_thisMember chap00-经典问题/00-2_thisMember.cpp) 9 | add_executable(00-3_assignmengCopyConstructor chap00-经典问题/00-3_assignmengCopyConstructor.cpp) 10 | 11 | 12 | add_executable(01-1_struct chap01-封装与继承/01-1_struct.cpp) 13 | 14 | add_executable(02-1_structClass chap02-类的形态/02-1_structClass.cpp) 15 | add_executable(02-2_operatorMain chap02-类的形态/02-2_operator.cpp chap02-类的形态/02-2_operatorMain.cpp) 16 | 17 | add_executable(03-1_initialize chap03-构造函数/03-1_initialize.cpp) 18 | add_executable(03-2_constructor chap03-构造函数/03-2_constructor.cpp) 19 | add_executable(03-3_constructorWithPara chap03-构造函数/03-3_constructorWithPara.cpp) 20 | add_executable(03-4_intArrayMain chap03-构造函数/03-4_intArray.cpp chap03-构造函数/03-4_intArrayMain.cpp) 21 | add_executable(03-5_defaultConstructor chap03-构造函数/03-5_defaultConstructor.cpp) 22 | add_executable(03-6_deepCopyVSCopy "chap03-构造函数/03-6_deepCopyVSCopy.cpp") 23 | 24 | # chapter 04 初始化列表 25 | add_executable(04-1_constMember chap04-初始化列表/04-1_constMember.cpp) 26 | add_executable(04-2_InitializeList chap04-初始化列表/04-2_InitializeList.cpp) 27 | add_executable(04-3_constMemory chap04-初始化列表/04-3_constMemory.cpp) 28 | 29 | # chapter 05 对象构造顺序 30 | add_executable(05-1_LocalVariable chap05-对象构造顺序/05-1_LocalVariable.cpp) 31 | add_executable(05-2_HeapVariable chap05-对象构造顺序/05-2_HeapVariable.cpp) 32 | add_executable(05-3_GlobalVariable chap05-对象构造顺序/05-3_GlobalVariable.cpp 33 | chap05-对象构造顺序/05-3_Global_2.cpp 34 | chap05-对象构造顺序/05-3_Global_1.cpp 35 | chap05-对象构造顺序/05-3_Global_3.cpp) 36 | 37 | # chapter 06 析构函数 38 | add_executable(06-1_intArrayMain chap06-析构函数/06-1_intArrayMain.cpp 39 | chap06-析构函数/06-1_intArray.cpp) 40 | add_executable(06-2_deconstructor chap06-析构函数/06-2_deconstructor.cpp) 41 | add_executable(06-3_deconstructorOrder chap06-析构函数/06-3_deconstructorOrder.cpp) 42 | 43 | # chapter 07 临时对象 44 | add_executable(07-1_tempVariable chap07-临时对象/07-1_tempVariable.cpp) 45 | add_executable(07-2_initVariable chap07-临时对象/07-2_initVariable.cpp) 46 | add_executable(07-3_tempVariableLiftTime chap07-临时对象/07-3_tempVariableLiftTime.cpp) 47 | 48 | # chapter 08 静态成员变量 49 | add_executable(08-1_countObjectNumber chap08-静态成员变量/08-1_countObjectNumber.cpp) 50 | add_executable(08-2_staticFunction chap08-静态成员变量/08-2_staticFunction.cpp) 51 | add_executable(08-3_countObjectNumSafe chap08-静态成员变量/08-3_countObjectNumSafe.cpp) 52 | 53 | # chapter 09 二阶构造模式 54 | add_executable(09-1_constructorReturn chap09-二阶构造模式/09-1_constructorReturn.cpp) 55 | add_executable(09-2_intArrayMain chap09-二阶构造模式/09-2_intArrayMain.cpp 56 | chap09-二阶构造模式/09-2_intArray.cpp) 57 | add_executable(09-3_TwoPhaseCons chap09-二阶构造模式/09-3_TwoPhaseCons.cpp) 58 | 59 | # chapter 10 友元 60 | add_executable(10-1_friendFunction chap10-友元/10-1_friendFunction.cpp) 61 | add_executable(10-2_friendClass chap10-友元/10-2_friendClass.cpp) 62 | 63 | # chapter 11 函数重载 64 | add_executable(11-1_overLoading chap11-函数重载/11-1_overLoading.cpp) 65 | add_executable(11-2_extendSystemFunction chap11-函数重载/11-2_extendSystemFunction.cpp) 66 | 67 | # chapter 12 操作符重载 68 | add_executable(12-1_ComplexAdd chap12-操作符重载/12-1_ComplexAdd.cpp) 69 | add_executable(12-2_operator chap12-操作符重载/12-2_operator.cpp) 70 | add_executable(12-3_ClassOperator chap12-操作符重载/12-3_ClassOperator.cpp) 71 | add_executable(12-4_ComplexMain chap12-操作符重载/12-4_Complex.cpp 72 | chap12-操作符重载/12-4_ComplexMain.cpp) 73 | add_executable(12-5_intArrayMain chap12-操作符重载/12-5_intArray.cpp 74 | chap12-操作符重载/12-5_intArrayMain.cpp) 75 | 76 | 77 | # chapter 13 智能指针 78 | add_executable(13-1_MemoryLeak chap13-智能指针/13-1_MemoryLeak.cpp) 79 | add_executable(13-2_autoPointer chap13-智能指针/13-2_autoPointer.cpp) 80 | 81 | # chapter 15 类型转换 82 | add_executable(15-1_CTypeTrans chap15-类型转换/15-1_CTypeTrans.cpp) 83 | add_executable(15-2_CppClassTypeTrans chap15-类型转换/15-2_CppClassTypeTrans.cpp) 84 | add_executable(15-3_ClassTypeToBuildType chap15-类型转换/15-3_ClassTypeToBuildType.cpp) 85 | add_executable(15-4_TransConstrClassTypeToClassType chap15-类型转换/15-4_TransConstrClassTypeToClassType.cpp) 86 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/00-1_constObject.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/4. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | int mi; 10 | public: 11 | Test(int i); 12 | Test(const Test& t); 13 | int getMi() ; 14 | }; 15 | 16 | Test::Test(int i) 17 | { 18 | mi = i; 19 | } 20 | 21 | Test::Test(const Test& t) 22 | { 23 | // const 对象不能调用非const成员变量 24 | mi = t.getMi(); 25 | } 26 | 27 | int Test::getMi() 28 | { 29 | return mi; 30 | } 31 | 32 | int main() 33 | { 34 | const Test t(1); 35 | // const 对象不能调用非 const 成员函数 36 | printf("t.getMi() = %d\n", t.getMi()); 37 | return 0; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/00-2_thisMember.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/4. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | int mi; 10 | public: 11 | int mj; 12 | Test(int i); 13 | Test(const Test& t); 14 | int getMi(); 15 | void print(); 16 | }; 17 | 18 | Test::Test(int i) 19 | { 20 | mi = i; 21 | } 22 | 23 | Test::Test(const Test& t) 24 | { 25 | mi = t.mi; 26 | } 27 | 28 | int Test::getMi() 29 | { 30 | return mi; 31 | } 32 | 33 | void Test::print() 34 | { 35 | printf("this = %p\n", this); 36 | } 37 | 38 | int main() 39 | { 40 | Test t1(1); 41 | Test t2(2); 42 | Test t3(3); 43 | 44 | printf("t1.getMi() = %d\n", t1.getMi()); 45 | printf("&t1 = %p\n", &t1); 46 | t1.print(); 47 | 48 | printf("t2.getMi() = %d\n", t2.getMi()); 49 | printf("&t2 = %p\n", &t2); 50 | t2.print(); 51 | 52 | printf("t3.getMi() = %d\n", t3.getMi()); 53 | printf("&t3 = %p\n", &t3); 54 | t3.print(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/00-3_assignmengCopyConstructor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/7. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Test 11 | { 12 | int* m_pointer; 13 | public: 14 | Test() 15 | { 16 | m_pointer = NULL; 17 | } 18 | Test(int i) 19 | { 20 | m_pointer = new int(i); 21 | } 22 | 23 | // 拷贝构造函数 24 | Test(const Test& obj) 25 | { 26 | printf("Test(const Test& obj)\n"); 27 | m_pointer = new int(*obj.m_pointer); 28 | } 29 | /* 30 | * 31 | * 赋值操作符重载 32 | * 1. 返回值为引用类型 33 | * 2. 参数为 const 引用类型 34 | * 3. 避免自赋值 35 | * 4. 返回当前对象 36 | * 37 | */ 38 | Test& operator = (const Test& obj) 39 | { 40 | printf("Test& operator = (const Test& obj)\n"); 41 | if( this != &obj ) 42 | { 43 | delete m_pointer; 44 | m_pointer = new int(*obj.m_pointer); 45 | } 46 | 47 | return *this; 48 | } 49 | void print() 50 | { 51 | cout << "m_pointer = " << hex << m_pointer << endl; 52 | } 53 | ~Test() 54 | { 55 | delete m_pointer; 56 | } 57 | }; 58 | 59 | int main() 60 | { 61 | Test t1 = 1; 62 | Test t2 = t1; 63 | 64 | t2 = t1; 65 | 66 | t1.print(); 67 | t2.print(); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/C++进阶(00-1) const 对象.md: -------------------------------------------------------------------------------- 1 | # C++进阶(00-1) const 对象 2 | 3 | ## 1 const 对象 4 | 5 | - const 修饰的对象为只读对象 6 | - 只读对象是编译阶段的概念,运行时无效 7 | 8 |
9 | 10 | ## 2 const 成员函数 11 | 12 | const 成员函数的定义: 13 | 14 | ```C++ 15 | Type ClassName::function(Type p) const 16 | ``` 17 | 18 | - const 对象只能调用const 成员函数 19 | - const 成员函数只能调用const 成员函数 20 | - const 成员函数不能改写成员变量的值 21 | 22 | 实验 const成员函数 23 | 24 | ```C++ 25 | #include 26 | 27 | class Test 28 | { 29 | int mi; 30 | public: 31 | int m_j; 32 | Test(int i); 33 | Test(const Test& t); 34 | int getMi(); 35 | }; 36 | 37 | Test::Test(int i) 38 | { 39 | mi = i; 40 | } 41 | 42 | Test::Test(const Test& t) 43 | { 44 | 45 | } 46 | 47 | int Test::getMi() 48 | { 49 | return mi; 50 | } 51 | 52 | int main() 53 | { 54 | const Test t(1); 55 | t.mj = 1000; // error, const 变量只读 56 | 57 | t.getMi(); // error, const 对象只能调用const 成员函数,需要将getMi() 声明为const 成员函数 58 | return 0; 59 | } 60 | 61 | ``` 62 | 63 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/C++进阶(00-2) 成员函数和成员变量都属于具体对象吗?.md: -------------------------------------------------------------------------------- 1 | # C++进阶(00-2) 成员函数和成员变量都属于具体对象吗? 2 | 3 | 结论:每个对象都有自己成员变量,但所有对象共享一套成员函数。 4 | 5 | 从程序运行角度 6 | 7 | - 对象有数据和函数构成 8 | - 数据位于栈、堆、全局数据区 9 | - 函数只能位于代码段 10 | 11 | 所以, 12 | 13 | - 每一个对象拥有自己的独立属性(成员变量) 14 | - 所有对象共享类的方法(成员函数) 15 | - 成员函数可以直接访问对象的属性 16 | - 方法中隐藏参数 this 用于指代当前对象 17 | 18 | > 实验00-2 :this指针 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap00-经典问题/C++进阶(00-3) 赋值.md: -------------------------------------------------------------------------------- 1 | # C++进阶(00-3) 赋值 2 | 3 | ## 00-3.1 拷贝构造函数与赋值 4 | 5 | - 编译器为每个类默认重载了赋值操作符 6 | - 默认赋值操作符仅完成了浅拷贝 7 | - 需要进行深拷贝时,必须重载赋值操作符 8 | - 赋值操作符与拷贝构造函数有相同的存在意义 9 | 10 | 赋值操作符重载与拷贝构造函数 11 | 12 | 示例1 - 拷贝构造函数用例 13 | 14 | ```C++ 15 | Test t1 = t2; 16 | ``` 17 | 18 | 示例2 - 赋值操作符重载用例 19 | 20 | ```C++ 21 | Test t1(1); 22 | Test t2(t1); // 拷贝构造函数 23 | t2 = t1; // 赋值操作符重载 24 | ``` 25 | 26 | 在创建对象时,无论使用 `()` 还是 `=` ,其调用的是构造函数(带参数构造函数 / 拷贝构造函数)。而在创建后,对对象赋值时,使用操作符重载函数。 27 | 28 | 默认赋值操作符重载函数,仅对对象进行浅拷贝操作。当类中含有动态内存对象时,需要自定义赋值操作符重载函数。 29 | 30 | 31 | 32 | 问题分析: 33 | 34 | image-20201007104642828 35 | 36 | > 当需要进行深拷贝时,必须赋值操作符的重载和拷贝构造函数。 37 | 38 |
39 | 40 | ## 00-3.2 编译器默认提供的函数 41 | 42 | - 默认构造函数(无参构造函数) 43 | - 拷贝构造函数 44 | - 赋值符号函数重载 45 | - 析构函数 46 | 47 | image-20201007105005740 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/01-1_struct.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/26. 3 | // 4 | 5 | #include 6 | 7 | struct Biology 8 | { 9 | bool living; 10 | }; 11 | 12 | struct Animal : Biology 13 | { 14 | bool movable; 15 | 16 | void findFood() 17 | { 18 | } 19 | }; 20 | 21 | struct Plant : Biology 22 | { 23 | bool growable; 24 | }; 25 | 26 | struct Beast : Animal 27 | { 28 | void sleep() 29 | { 30 | } 31 | }; 32 | 33 | struct Human : Animal 34 | { 35 | void sleep() 36 | { 37 | printf("I'm sleeping...\n"); 38 | } 39 | 40 | void work() 41 | { 42 | printf("I'm working...\n"); 43 | } 44 | }; 45 | 46 | struct Girl : Human 47 | { 48 | private: 49 | int age; 50 | int weight; 51 | public: 52 | void print() 53 | { 54 | age = 22; 55 | weight = 48; 56 | 57 | printf("I'm a girl, I'm %d years old.\n", age); 58 | printf("My weight is %d kg.\n", weight); 59 | } 60 | }; 61 | 62 | struct Boy : Human{ 63 | private: 64 | int height; 65 | int salary; 66 | public: 67 | int age; 68 | int weight; 69 | 70 | void print(){ 71 | height = 175; 72 | salary = 9000; 73 | 74 | printf("I'm a boy, my height is %d cm.\n", height); 75 | printf("My salary is %d RMB.\n", salary); 76 | } 77 | }; 78 | 79 | int main(){ 80 | Girl g; 81 | Boy b; 82 | 83 | g.print(); 84 | 85 | b.age = 19; 86 | b.weight = 120; 87 | //b.height = 180; 88 | 89 | b.print(); 90 | 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/C++进阶(1) 面向对象.md: -------------------------------------------------------------------------------- 1 | # C++进阶(1) 面向对象 2 | 3 | ## 1 基本概念 4 | 5 | ### 1.1 类与对象 6 | 7 | - 类:一种模型,通过模型可以创建不同的对象实体。用于描述一类食物所特有的**属性** 和 **行为** 。 8 | - 对象:类模型的一个具体实例。拥有所属类中描述的一切 **属性** 和 **行为** 。 9 | 10 | image-20200916205403420 11 | 12 | 13 | 14 | ### 1.2 对象创建的问题 15 | 16 | - 类 **不一定** 存在实际对象 17 | - 类的对象数目是 **不确定** 的 18 | - 类 **不一定** 来源于现实 19 | - 类不一定是独立的,可能存在关系 20 | - 对象实例不一定只属于一个类 21 | - 对象实例 **不可能** 完全相同 22 | 23 |
24 | 25 | ## 2 类之间的关系 26 | 27 | - 继承 28 | - 从已存在的类细分出来的类和原类之间具有继承关系(is-a) 29 | - 继承的类(子类)拥有父类的所有属性和行为 30 | 31 | image-20200916213409072 32 | 33 | - 组合 34 | - 一些类依赖于其他类 35 | - 组合类在某一个局部上由其他类组成 36 | 37 | image-20200916213339665 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/C++进阶(2) 封装.md: -------------------------------------------------------------------------------- 1 | # C++进阶(2) 封装 2 | 3 | ## 1 类的设计 4 | 5 | 类分为两部分: 6 | 7 | - 类的实现细节 8 | - 类的使用方式 9 | 10 | image-20200916215156993 11 | 12 |
13 | 14 | ## 2 类的封装 15 | 16 | 对不同类型的事物进行抽象,得到其属性及其行为,使用不同的访问权限将其封装。 17 | 18 | - 成员变量:类属性的变量 19 | - 成员函数:类行为的函数 20 | 21 |
22 | 23 | 访问级别 24 | 25 | - public:可以在类内部和外界访问和调用 26 | - private:只能在类内部访问和调用 27 | 28 |
29 | 30 | 31 | 32 | ## 3 成员作用域 33 | 34 | - 类成员的作用域在类的内部,外部无法访问 35 | - 成员函数可以直接访问成员变量和调用成员函数 36 | - 类的外部可以通过类变量访问 public 成员 37 | - 类成员的作用域与访问级别无关 38 | 39 | > C++ 中struct定义的类中所有成员默认为 public。 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/images/image-20200916205403420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap01-封装与继承/images/image-20200916205403420.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/images/image-20200916213339665.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap01-封装与继承/images/image-20200916213339665.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/images/image-20200916213409072.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap01-封装与继承/images/image-20200916213409072.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap01-封装与继承/images/image-20200916215156993.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap01-封装与继承/images/image-20200916215156993.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap02-类的形态/02-1_structClass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/26. 3 | // 4 | 5 | #include 6 | 7 | struct A{ 8 | int i; 9 | int getI(){ 10 | return i; 11 | } 12 | }; 13 | 14 | class B{ 15 | int i; 16 | int getI(){ 17 | return i; 18 | } 19 | }; 20 | 21 | int main(){ 22 | A a; 23 | B b; 24 | a.getI(); 25 | printf("a.getI() = %d", a.getI()); 26 | // printf("b.getI() = %d", b.getI()); // default to private 27 | return 0; 28 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap02-类的形态/02-2_operator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include "02-2_operator.h" 6 | 7 | bool Operator::setOperator(char op) 8 | { 9 | bool ret = false; 10 | 11 | if( (op == '+') || (op == '-') || (op == '*') || (op == '/') ) 12 | { 13 | ret = true; 14 | m_Op = op; 15 | } 16 | else 17 | { 18 | m_Op = '\0'; 19 | } 20 | 21 | return ret; 22 | } 23 | 24 | void Operator::setParameter(double p1, double p2) 25 | { 26 | m_P1 = p1; 27 | m_P2 = p2; 28 | } 29 | 30 | bool Operator::result(double& r) 31 | { 32 | bool ret = true; 33 | 34 | switch( m_Op ) 35 | { 36 | case '/': 37 | if( (-0.000000001 < m_P2) && (m_P2 < 0.000000001) ) 38 | { 39 | ret = false; 40 | } 41 | else 42 | { 43 | r = m_P1 / m_P2; 44 | } 45 | break; 46 | case '+': 47 | r = m_P1 + m_P2; 48 | break; 49 | case '*': 50 | r = m_P1 * m_P2; 51 | break; 52 | case '-': 53 | r = m_P1 - m_P2; 54 | break; 55 | default: 56 | ret = false; 57 | break; 58 | } 59 | 60 | return ret; 61 | } 62 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap02-类的形态/02-2_operator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #ifndef CPP_EXERCEISE_02_2_OPERATOR_H 6 | #define CPP_EXERCEISE_02_2_OPERATOR_H 7 | 8 | class Operator 9 | { 10 | private: 11 | char m_Op; 12 | double m_P1; 13 | double m_P2; 14 | 15 | public: 16 | bool setOperator(char op); 17 | void setParameter(double p1, double p2); 18 | bool result(double& r); 19 | }; 20 | 21 | #endif //CPP_EXERCEISE_02_2_OPERATOR_H 22 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap02-类的形态/02-2_operatorMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include 6 | #include "02-2_operator.h" 7 | 8 | int main() 9 | { 10 | Operator op; 11 | double r = 0; 12 | 13 | op.setOperator('/'); 14 | op.setParameter(9, 3); 15 | 16 | if( op.result(r) ) 17 | { 18 | printf("r = %lf\n", r); 19 | } 20 | else 21 | { 22 | printf("Calculate error!\n"); 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap02-类的形态/C++进阶(3) 类.md: -------------------------------------------------------------------------------- 1 | # C++进阶(3) 类 2 | 3 | ## 1 struct 与 class联系与区别 4 | 5 | 联系: 6 | 7 | - C++中,struct与class用法相同 8 | 9 | 区别:: 10 | 11 | - struct定义类时,所有成员的访问级别是public 12 | - class定义类时,所有成员的访问级别时private 13 | 14 | 15 | 16 | ## 2 类支持实现与声明的分离 17 | 18 | - 在头文件中声明类 19 | - 在源文件中实现类 -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/03-1_initialize.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | int i; 11 | int j; 12 | public: 13 | int getI() { return i; } 14 | int getJ() { return j; } 15 | void initialize() 16 | { 17 | i = 1; 18 | j = 2; 19 | } 20 | }; 21 | 22 | Test gt; 23 | 24 | int main() 25 | { 26 | gt.initialize(); 27 | 28 | printf("gt.i = %d\n", gt.getI()); 29 | printf("gt.j = %d\n", gt.getJ()); 30 | 31 | Test t1; 32 | 33 | //t1.initialize(); 34 | 35 | printf("t1.i = %d\n", t1.getI()); 36 | printf("t1.j = %d\n", t1.getJ()); 37 | 38 | t1.initialize(); 39 | 40 | Test* pt = new Test; 41 | 42 | pt->initialize(); 43 | 44 | printf("pt->i = %d\n", pt->getI()); 45 | printf("pt->j = %d\n", pt->getJ()); 46 | 47 | delete pt; 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/03-2_constructor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | int i; 11 | int j; 12 | public: 13 | int getI() { return i; } 14 | int getJ() { return j; } 15 | Test() 16 | { 17 | printf("Test() Begin\n"); 18 | 19 | i = 1; 20 | j = 2; 21 | 22 | printf("Test() End\n"); 23 | } 24 | }; 25 | 26 | 27 | Test gt; 28 | 29 | int main() 30 | { 31 | printf("gt.i = %d\n", gt.getI()); 32 | printf("gt.j = %d\n", gt.getJ()); 33 | 34 | Test t1; 35 | 36 | printf("t1.i = %d\n", t1.getI()); 37 | printf("t1.j = %d\n", t1.getJ()); 38 | 39 | Test* pt = new Test; 40 | 41 | printf("pt->i = %d\n", pt->getI()); 42 | printf("pt->j = %d\n", pt->getJ()); 43 | 44 | delete pt; 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/03-3_constructorWithPara.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | public: 10 | Test() 11 | { 12 | printf("Test()\n"); 13 | } 14 | Test(int v) 15 | { 16 | printf("Test(int v), v = %d\n", v); 17 | } 18 | }; 19 | 20 | int main() 21 | { 22 | Test t; // 调用 Test() 23 | Test t1(1); // 调用 Test(int v) 24 | Test t2 = 2; // 调用 Test(int v) 25 | 26 | int i(100); 27 | 28 | printf("i = %d\n", i); 29 | 30 | return 0; 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/03-4_intArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include "03-4_intArray.h" 6 | 7 | IntArray::IntArray(int len) 8 | { 9 | m_pointer = new int[len]; 10 | 11 | for(int i=0; i 7 | #include "03-4_intArray.h" 8 | 9 | int main() 10 | { 11 | IntArray a(5); 12 | 13 | for(int i=0; i 6 | 7 | class Test{ 8 | public: 9 | int getI(){ 10 | return i; 11 | } 12 | 13 | int getJ(){ 14 | return j; 15 | } 16 | 17 | Test(){ 18 | 19 | } 20 | 21 | // Test(const Test& t){ 22 | // i = t.i; 23 | // j = t.j; 24 | // } 25 | private: 26 | int i; 27 | int j; 28 | }; 29 | 30 | class EmptyClass{ 31 | // 至少有一个无参构造函数 32 | }; 33 | 34 | int main(){ 35 | Test t; 36 | Test tCopy = t; 37 | 38 | printf(" t.i = %d, t.j = %d\n", t.getI(), t.getJ()); 39 | printf(" tCopy.i = %d, tCopy.j = %d\n", tCopy.getI(), tCopy.getJ()); 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/03-6_deepCopyVSCopy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test{ 8 | public: 9 | int getI(){ 10 | return i; 11 | } 12 | 13 | int getJ(){ 14 | return j; 15 | } 16 | 17 | int* getP(){ 18 | return p; 19 | } 20 | 21 | Test(int v){ 22 | i = 1; 23 | j = 2; 24 | p = new int; 25 | *p = v; 26 | } 27 | 28 | Test(const Test& t){ 29 | i = t.i; 30 | j = t.j; 31 | p = new int; 32 | *p = *t.p; 33 | } 34 | ~Test(){ 35 | delete p; 36 | } 37 | private: 38 | int i; 39 | int j; 40 | int* p; 41 | }; 42 | 43 | class EmptyClass{ 44 | // 至少有一个无参构造函数 45 | }; 46 | 47 | int main(){ 48 | Test t(3); 49 | Test tCopy (t); 50 | 51 | printf(" t.i = %d, t.j = %d, t.p = %d\n", t.getI(), t.getJ(), t.getP()); 52 | printf(" tCopy.i = %d, tCopy.j = %d, tCopy.p = %d\n", tCopy.getI(), tCopy.getJ(), tCopy.getP()); 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/C++进阶(4) 构造函数.md: -------------------------------------------------------------------------------- 1 | # C++进阶(4) 构造函数 2 | 3 | ## 4.1 对象的成员初始化值 4 | 5 | 示例代码: 6 | 7 | ```C++ 8 | #include 9 | 10 | class Test 11 | { 12 | private: 13 | int i; 14 | int j; 15 | public: 16 | int getI() { return i; } 17 | int getJ() { return j; } 18 | }; 19 | 20 | Test gt; 21 | 22 | int main() 23 | { 24 | printf("gt.i = %d\n", gt.getI()); // i = 0 25 | printf("gt.j = %d\n", gt.getJ()); // j = 0 26 | 27 | Test t1; 28 | 29 | printf("t1.i = %d\n", t1.getI()); // i = 随机值 30 | printf("t1.j = %d\n", t1.getJ()); // j = 随机值 31 | 32 | Test* pt = new Test; 33 | 34 | printf("pt->i = %d\n", pt->getI()); 35 | printf("pt->j = %d\n", pt->getJ()); 36 | 37 | delete pt; 38 | 39 | return 0; 40 | } 41 | 42 | ``` 43 | 44 | 由实验结果,其中全局变量的 i j被初始化为0,而局部变量的i j为随机值,对象由动态内存分配的变量在堆空间中,变量值不定。因为 45 | 46 | - 局部变量在 **栈区**,初始值不定 47 | - 全局变量存储在**全局数据区**,初始值统一为0。 48 | - **堆** 空间中的变量,初始值不定 49 | 50 | ## 4.2 对象初始化 51 | 52 | 构造函数:与类名相同的函数名。 53 | 54 | - 构造函数没有任何返回类型的声明 55 | - 构造函数在定义时被自动调用 56 | 57 | 58 | 59 | ## 4.3 构造函数 60 | 61 | 带有参数的构造函数: 62 | 63 | - 类的构造函数可以重载 64 | 65 | > 对象定义与声明 66 | > 67 | > - 对象定义:申请对象占用的内存空间,调用构造函数初始化 68 | > - 对象声明: 告诉编译器存在这个对象,链接时会找 69 | > 70 | > ```C++ 71 | > Test t; 72 | > 73 | > int main(){ 74 | > extern Test t; // 链接时找的变量 75 | > 76 | > return 0; 77 | > } 78 | > ``` 79 | 80 | 81 | 82 | ### 4.3.1 赋值与初始化 83 | 84 | 在C++中,初始化会调用构造函数,赋值不会调用构造函数 。 85 | 86 | 87 | 88 | ### 4.3.2 构造函数的调用 89 | 90 | - 构造函数在对象定义时自动调用。 91 | - 手动调用构造函数 92 | 93 | ```C++ 94 | Test ta[3]; // 自动调用 95 | Test ta[3] = {Test(), Test(2), Test(2)}; // 手动调用 96 | ``` 97 | 98 | 调用构造函数的方式 99 | 100 | ```C++ 101 | Test ta = Test(1000); 102 | ``` 103 | 104 |
105 | 106 | ## 5 特殊构造函数 107 | 108 | ## 5.1 无参构造函数(默认构造函数) 109 | 110 | - 当类中没有定义构造函数时,编译器默认提供一个无参构造函数,其函数体为空 111 | 112 | 113 | 114 | - 拷贝构造函数也是构造函数, 定义拷贝构造函数后,编译器则不会提供任何的构造函数,包括默认构造函数。 115 | 116 | ## 5.2 拷贝构造函数 117 | 118 | 拷贝构造函数:参数为 `const class_name&` 的构造函数 119 | 120 | - 当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,**简单的进行成员变量的值复制** 。 121 | 122 | ### 5.2.1 拷贝构造函数的意义 123 | 124 | - 兼容C语言的初始化方式 125 | - 初始化行为符合预期的逻辑 126 | 127 | 浅拷贝:拷贝后对象的物理状态相同 128 | 129 | 深拷贝:拷贝后对象的逻辑状态相同 130 | 131 | - 编译器提供的拷贝构造函数是浅拷贝 132 | 133 |
134 | 135 | 浅拷贝 V.S. 深拷贝:如果成员变量有指针类型对象,如果通过默认拷贝构造函数进行浅拷贝,则其拷贝的为指针值,当释放对象时,会释放两次内存,造成内存泄露。 136 | 137 | image-20201003085352771 138 | 139 | 何时需要进行**深拷贝** ? 140 | 141 | - 对象的成员指代了系统资源 142 | - 动态内存空间 143 | - 打开外存的文件 144 | - 使用系统的网络端口 145 | 146 |
147 | 148 | > 自定义拷贝构造函数,必然需要进行深拷贝。 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap03-构造函数/images/image-20201003085352771.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap03-构造函数/images/image-20201003085352771.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap04-初始化列表/04-1_constMember.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test{ 8 | public: 9 | //Test(){} 10 | // Test(){ 11 | // ci = 10; 12 | // } 13 | Test(): ci(10){} 14 | int getI(){ 15 | return ci; 16 | } 17 | private: 18 | const int ci; 19 | }; 20 | 21 | 22 | int main(){ 23 | Test t; 24 | printf("t.ci = %d \n", t.getI()); 25 | return 0; 26 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap04-初始化列表/04-2_InitializeList.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Value 8 | { 9 | private: 10 | int mi; 11 | public: 12 | Value(int i) 13 | { 14 | printf("i = %d\n", i); 15 | mi = i; 16 | } 17 | int getI() 18 | { 19 | return mi; 20 | } 21 | }; 22 | 23 | class Test 24 | { 25 | private: 26 | Value m2; 27 | Value m3; 28 | Value m1; 29 | public: 30 | Test() : m1(1), m2(2), m3(3) 31 | { 32 | printf("Test::Test()\n"); 33 | } 34 | }; 35 | 36 | 37 | int main() 38 | { 39 | Test t; 40 | 41 | return 0; 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap04-初始化列表/04-3_constMemory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | #include 5 | 6 | class Value 7 | { 8 | private: 9 | int mi; 10 | public: 11 | Value(int i) 12 | { 13 | printf("i = %d\n", i); 14 | mi = i; 15 | } 16 | int getI() 17 | { 18 | return mi; 19 | } 20 | }; 21 | 22 | class Test 23 | { 24 | public: 25 | Test() : ci(10), m1(1), m2(2), m3(3) 26 | { 27 | printf("Test::Test()\n"); 28 | } 29 | 30 | int getCI(){ 31 | return ci; 32 | } 33 | 34 | int setCI(int v){ 35 | int* p = const_cast (&ci); 36 | *p = v; 37 | } 38 | 39 | private: 40 | const int ci; 41 | Value m2; 42 | Value m3; 43 | Value m1; 44 | }; 45 | 46 | int main(){ 47 | Test t; 48 | printf("t.ci = %d\n", t.getCI()); 49 | 50 | t.setCI(20); 51 | printf("t.ci = %d\n", t.getCI()); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap04-初始化列表/C++进阶(5) 初始化列表.md: -------------------------------------------------------------------------------- 1 | # C++进阶(5) 初始化列表 2 | 3 | 4 | 5 | 类的成员变量是否可以为const 类型? 6 | 7 | ```C++ 8 | class Test{ 9 | public: 10 | int getI(){ 11 | return ci; 12 | } 13 | private: 14 | const int ci; 15 | }; 16 | ``` 17 | 18 | - 类中可以定义const 成员变量,这个const 变量为只读变量,必须在调用构造函数之前进行初始化。 19 | 20 | 21 | 22 | ## 5.1 初始化列表 23 | 24 | C++中提供初始化列表对成员变量初始化 25 | 26 | ``` 27 | ClassName::ClassName(): 28 | m1(v1), m2(v1, v2), m3(v3); 29 | { 30 | // some other initialize operation 31 | } 32 | ``` 33 | 34 | > 初始化列表在调用 构造函数前,先对成员变量进行初始化。 35 | 36 |
37 | 38 | 39 | 40 | ## 5.2 初始化顺序 41 | 42 | - 成员的**初始化顺序**与成员**声明顺序**相同 43 | - 成员的初始化顺序**与初始化列表中的位置无关** 44 | - 初始化列表**先于构造函数体执行** 45 | 46 | ```C++ 47 | // 48 | // Created by Yang Shuangzhen on 2020/10/3. 49 | // 50 | 51 | #include 52 | 53 | class Value 54 | { 55 | private: 56 | int mi; 57 | public: 58 | Value(int i) 59 | { 60 | printf("i = %d\n", i); 61 | mi = i; 62 | } 63 | int getI() 64 | { 65 | return mi; 66 | } 67 | }; 68 | 69 | class Test 70 | { 71 | private: 72 | Value m2; 73 | Value m3; 74 | Value m1; 75 | public: 76 | Test() : m1(1), m2(2), m3(3) 77 | { 78 | printf("Test::Test()\n"); 79 | } 80 | }; 81 | 82 | 83 | int main() 84 | { 85 | Test t; 86 | 87 | return 0; 88 | } 89 | ``` 90 | 91 | 输出: 92 | 93 | ```C++ 94 | i = 2 95 | i = 3 96 | i = 1 97 | Test::Test() 98 | ``` 99 | 100 | ## 5.3 const 成员 101 | 102 | - 类中 const 成员会被分配空间 103 | - 类中const 成员的本质是只读变量 104 | - 类中的const成员只能在初始化列表中指定初始值 105 | 106 | ---> 编译器无法直接得到const 成员的初始值,因此无法进入符号表成为真正意义的常量。 107 | 108 | 109 | 110 | 初始化 V.S. 赋值 111 | 112 | 初始化:对正在创建的对象进行初值设置 113 | 114 | 赋值:对已经存在的对象进行值设置 -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-1_LocalVariable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | int mi; 11 | public: 12 | Test(int i) 13 | { 14 | mi = i; 15 | printf("Test(int i): %d\n", mi); 16 | } 17 | Test(const Test& obj) 18 | { 19 | mi = obj.mi; 20 | printf("Test(const Test& obj): %d\n", mi); 21 | } 22 | 23 | int getI(){ 24 | return mi; 25 | } 26 | }; 27 | 28 | int main() 29 | { 30 | int i = 0; 31 | Test a1 = i; 32 | 33 | while( i < 3 ) 34 | { 35 | Test a2 = ++i; 36 | } 37 | 38 | goto End; 39 | if( i < 4 ) 40 | { 41 | Test a = a1; 42 | } 43 | else 44 | { 45 | Test a(100); 46 | } 47 | End: 48 | //printf("a.i = %d\n", a.getI()); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-2_HeapVariable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | int mi; 11 | public: 12 | Test(int i) 13 | { 14 | mi = i; 15 | printf("Test(int i): %d\n", mi); 16 | } 17 | Test(const Test& obj) 18 | { 19 | mi = obj.mi; 20 | printf("Test(const Test& obj): %d\n", mi); 21 | } 22 | int getMi() 23 | { 24 | return mi; 25 | } 26 | }; 27 | 28 | int main() 29 | { 30 | int i = 0; 31 | Test* a1 = new Test(i); // Test(int i): 0 32 | 33 | while( ++i < 10 ) 34 | if( i % 2 ) 35 | new Test(i); // Test(int i): 1, 3, 5, 7, 9 36 | 37 | if( i < 4 ) 38 | new Test(*a1); 39 | else 40 | new Test(100); // Test(int i): 100 41 | 42 | return 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-3_GlobalVariable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include "05-3_test.h" 6 | 7 | Test t4("test4"); 8 | 9 | int main() 10 | { 11 | Test t5("test5"); 12 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-3_Global_1.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | #include "05-3_test.h" 5 | 6 | Test t1("test1"); 7 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-3_Global_2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include "05-3_test.h" 6 | 7 | Test t("test2"); -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-3_Global_3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include "05-3_test.h" 6 | 7 | Test t3("test3"); -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/05-3_test.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #ifndef CPP_EXERCEISE_05_3_TEST_H 6 | #define CPP_EXERCEISE_05_3_TEST_H 7 | 8 | #include 9 | 10 | class Test 11 | { 12 | public: 13 | Test(const char* s) 14 | { 15 | printf("%s\n", s); 16 | } 17 | }; 18 | 19 | 20 | #endif //CPP_EXERCEISE_05_3_TEST_H 21 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap05-对象构造顺序/C++进阶(6) 对象的构造顺序.md: -------------------------------------------------------------------------------- 1 | # C++进阶(6) 对象的构造顺序 2 | 3 | C++中类可以定义多个对象,对象的构造顺序是怎样的? 4 | 5 | ## 6.1 局部对象 6 | 7 | - 局部对象:程序执行到达对象定义语句时进行构造 8 | 9 | ```C++ 10 | int i = 0; 11 | Test a1 = i; // Test(int i): 0 12 | 13 | while( i < 3 ) 14 | { 15 | Test a2 = ++i; // Test(int i): 1 2 3 16 | } 17 | 18 | if( i < 4 ) 19 | { 20 | Test a = a1; // Test(const Test& t): 0 21 | } 22 | else 23 | { 24 | Test a(100); 25 | } 26 | ``` 27 | 28 | 输出 29 | 30 | ```C++ 31 | Test(int i): 0 32 | Test(int i): 1 33 | Test(int i): 2 34 | Test(int i): 3 35 | ``` 36 | 37 | 38 | 39 | ## 6.2 堆对象 40 | 41 | - 当程序执行流到达new 语句时创建对象 42 | - 使用new 创建对象将自动触发构造函数的调用 43 | 44 | ```C++ 45 | int i = 0; 46 | Test* a1 = new Test(i); 47 | while (++i < 10){ 48 | if (i % 2) 49 | new Test(i); 50 | } 51 | 52 | if (i < 4) 53 | new Test(*a1); 54 | else 55 | new Test(100); 56 | ``` 57 | 58 | 输出 59 | 60 | ```C++ 61 | Test(int i): 0 62 | Test(int i): 1 63 | Test(int i): 3 64 | Test(int i): 5 65 | Test(int i): 7 66 | Test(int i): 9 67 | Test(int i): 100 68 | ``` 69 | 70 |
71 | 72 | ## 6.3 全局变量 73 | 74 | - 对象的构造顺序是不确定的 75 | - 不同编译器使用不同的规则确定构造顺序 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap06-析构函数/06-1_intArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include "06-1_intArray.h" 6 | 7 | IntArray::IntArray(int len) 8 | { 9 | m_pointer = new int[len]; 10 | 11 | for(int i=0; i 7 | #include "06-1_intArray.h" 8 | 9 | int main() 10 | { 11 | IntArray a(5); 12 | 13 | for(int i=0; i 6 | 7 | class Test 8 | { 9 | int mi; 10 | public: 11 | Test(int i) 12 | { 13 | mi = i; 14 | printf("Test(): %d\n", mi); 15 | } 16 | ~Test() 17 | { 18 | printf("~Test(): %d\n", mi); 19 | } 20 | }; 21 | 22 | int main() 23 | { 24 | Test t(1); // 构造 Test(1) 25 | 26 | Test* pt = new Test(2); // 构造Test(2) 27 | 28 | delete pt; // 析构Test(2) 29 | // 析构Test(1) 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap06-析构函数/06-3_deconstructorOrder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/4. 3 | // 4 | 5 | #include 6 | 7 | class Member 8 | { 9 | const char* ms; 10 | public: 11 | Member(const char* s) 12 | { 13 | printf("Member(const char* s): %s\n", s); 14 | 15 | ms = s; 16 | } 17 | ~Member() 18 | { 19 | printf("~Member(): %s\n", ms); 20 | } 21 | }; 22 | 23 | class Test 24 | { 25 | Member mA; 26 | Member mB; 27 | public: 28 | Test() : mB("mB"), mA("mA") 29 | { 30 | printf("Test()\n"); 31 | } 32 | ~Test() 33 | { 34 | printf("~Test()\n"); 35 | } 36 | }; 37 | 38 | Member gA("gA"); 39 | 40 | int main() 41 | { 42 | Test t; 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap06-析构函数/C++进阶(7) 析构函数.md: -------------------------------------------------------------------------------- 1 | # C++进阶(7) 析构函数 2 | 3 | C++中如何清理对象?析构函数。 4 | 5 | - 对象销毁时自动进行清理的特殊函数 6 | - 对象释放系统资源的保障 7 | 8 | ## 7.1 析构函数 9 | 10 | 定义:~ClassName() 11 | 12 | - 析构函数没有参数和返回值 13 | - 析构函数在对象销毁时自动被调用 14 | 15 |
16 | 17 | 何时定义析构函数 18 | 19 | - 当类中定义构造函数,并且构造函数使用系统资源(内存申请、文件打开),则需定义析构函数。 20 | 21 | ## 7.2 析构函数的调用顺序 22 | 23 | 单个对象创建的构造函数的调用顺序 24 | 25 | 1. 调用父类的构造过程 26 | 2. 调用成员变量的构造函数(构造顺序与声明顺序相同) 27 | 3. 调用类自身的构造函数 28 | 29 | **析构函数与对应的构造函数的调用顺序相反** 。 30 | 31 |
32 | 33 | 多个对象析构时,析构顺序与构造顺序相反。 34 | 35 | > 实验 06-3 :构造函数与析构函数调用顺序 36 | 37 |
38 | 39 | - 栈对象和全局对象,与栈(FILO)相同,最先构造的对象,最后析构。 40 | - 堆对象的析构发生在delete的时候。 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap07-临时对象/07-1_tempVariable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | /* 7 | * Test() 构造函数中调用Test(0) ,仅仅创建了临时对象,并不是调用Test(int i) 8 | * 9 | */ 10 | class Test { 11 | int mi; 12 | public: 13 | Test(int i) { 14 | mi = i; 15 | } 16 | Test() { 17 | Test(0); 18 | } 19 | void print() { 20 | printf("mi = %d\n", mi); 21 | } 22 | }; 23 | 24 | 25 | int main() 26 | { 27 | Test t; 28 | 29 | t.print(); 30 | 31 | return 0; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap07-临时对象/07-2_initVariable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test { 8 | int mi; 9 | 10 | void init(int i) 11 | { 12 | mi = i; 13 | } 14 | public: 15 | Test(int i) { 16 | init(i); 17 | } 18 | Test() { 19 | init(0); 20 | } 21 | void print() { 22 | printf("mi = %d\n", mi); 23 | } 24 | }; 25 | 26 | 27 | int main() 28 | { 29 | Test t; 30 | 31 | t.print(); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap07-临时对象/07-3_tempVariableLiftTime.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/3. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | int mi; 10 | public: 11 | explicit Test(int i) 12 | { 13 | printf("Test(int i) : %d\n", i); 14 | mi = i; 15 | } 16 | Test(const Test& t) 17 | { 18 | printf("Test(const Test& t) : %d\n", t.mi); 19 | mi = t.mi; 20 | } 21 | Test() 22 | { 23 | printf("Test()\n"); 24 | mi = 0; 25 | } 26 | int print() 27 | { 28 | printf("mi = %d\n", mi); 29 | } 30 | ~Test() 31 | { 32 | printf("~Test()\n"); 33 | } 34 | }; 35 | 36 | // 临时对象作为返回值 37 | Test func() 38 | { 39 | return Test(20); 40 | } 41 | 42 | // 临时对象作为参数 43 | Test func1(Test a) 44 | { 45 | return Test(20); 46 | } 47 | 48 | // 对象作为返回值 49 | Test func2(Test a) 50 | { 51 | return a; 52 | } 53 | int main() 54 | { 55 | Test t = Test(10); // ==> Test t = 10; 56 | // Test tt = func(); // ==> Test tt = Test(20); ==> Test tt = 20; 57 | // Test tt = func1(t); 58 | Test tt = func2(t); 59 | 60 | t.print(); 61 | tt.print(); 62 | 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap07-临时对象/C++进阶(8) 临时对象.md: -------------------------------------------------------------------------------- 1 | # C++进阶(8) 临时对象 2 | 3 | 示例1:构造函数调用构造函数 4 | 5 | ```C++ 6 | class Test { 7 | int mi; 8 | public: 9 | Test(int i) { 10 | mi = i; 11 | } 12 | Test() { 13 | Test(0); 14 | } 15 | void print() { 16 | printf("mi = %d\n", mi); 17 | } 18 | }; 19 | 20 | 21 | int main() 22 | { 23 | Test t; 24 | 25 | t.print(); 26 | 27 | return 0; 28 | } 29 | ``` 30 | 31 | 输出: 32 | 33 | ```C++ 34 | mi = 376545317 // 随机值 35 | ``` 36 | 37 | 38 | 39 | 直接调用构造函数的行为是什么? 40 | 41 | 直接调用构造函数会产生一个临时对象,而临时对象的生命周期只有一条语句的时间,其作用域仅存在语句中。 42 | 43 |
44 | 45 | ## 8.2 编译器的行为 46 | 47 | > 现代C++编译器在不影响最终结果的前提下,会尽力减少临时对象的产生!!! 48 | 49 |
50 | 51 | 示例1: 临时对象赋值其他对象 52 | 53 | ```C++ 54 | Test t(10); 55 | Test t = Test(10); // 1. 生成临时对象 56 | // 2. 使用临时对象初始化 t (调用拷贝构造函数) 57 | 58 | 输出: 59 | Test(int i) : 10 60 | Test(int i) : 10 61 | 62 | 编译器避免使用临时对象,会进行优化:Test t = Test(10) ---> Test t = 10; 63 | ``` 64 | 65 | 示例2: 临时对象作为返回值 66 | 67 | ```C++ 68 | Test func(){ 69 | return Test(20); 70 | } 71 | 72 | int main(){ 73 | Test t = Test(10); 74 | Test tt = func(); 75 | 76 | return 0; 77 | } 78 | 79 | 输出: 80 | Test(int i) : 10 81 | Test(int i) : 20 82 | ~Test() // 析构 t 83 | ~Test() // 析构 tt 84 | 编译器优化:Test tt = Test(20) ---> Test tt = 20; 85 | ``` 86 | 87 | 示例3 : 临时对象作为参数 88 | 89 | ```C++ 90 | Test func1(Test a) 91 | { 92 | return Test(20); 93 | } 94 | 95 | int main() 96 | { 97 | Test t = Test(10); // ==> Test t = 10; 98 | Test tt = func1(t); // 参数拷贝构造,返回值被编译器优化直接初始化 99 | return 0; 100 | } 101 | 输出: 102 | Test(int i) : 10 103 | Test(const Test& t): 10 104 | Test(int i) : 20 105 | ~Test() // 析构参数a 106 | ~Test() // 析构t 107 | ~Test() // 析构tt 108 | 109 | ``` 110 | 111 | 示例4:对象作为返回值 112 | 113 | ```C++ 114 | // 对象作为返回值 115 | Test func2(Test a) 116 | { 117 | return a; 118 | } 119 | int main() 120 | { 121 | Test t = Test(10); 122 | Test tt = func2(t); 123 | return 0; 124 | } 125 | 126 | 输出: 127 | Test(int i) : 10 128 | Test(const Test& t) : 10 // 拷贝构造 a 129 | Test(const Test& t) : 10 // 拷贝构造tt 130 | ~Test() // 析构参数a 131 | ~Test() // 析构t 132 | ~Test() // 析构tt 133 | ``` 134 | 135 |
136 | 137 | ## 8.3 小结 138 | 139 | - 直接调用构造函数产生临时对象 140 | - 临时对象是性能的瓶颈, 也是bug来源之一 141 | - 现代C++编译器会尽力避开临时对象 142 | - 实际工程开发中需要认为的避开临时对象 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap08-静态成员变量/08-1_countObjectNumber.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | static int cCount; 11 | public: 12 | Test() 13 | { 14 | cCount++; 15 | } 16 | ~Test() 17 | { 18 | --cCount; 19 | } 20 | int getCount() 21 | { 22 | return cCount; 23 | } 24 | }; 25 | 26 | int Test::cCount = 0; 27 | 28 | Test gTest; 29 | 30 | int main() 31 | { 32 | Test t1; 33 | Test t2; 34 | 35 | printf("count = %d\n", gTest.getCount()); 36 | printf("count = %d\n", t1.getCount()); 37 | printf("count = %d\n", t2.getCount()); 38 | 39 | Test* pt = new Test(); 40 | 41 | printf("count = %d\n", pt->getCount()); 42 | 43 | delete pt; 44 | 45 | printf("count = %d\n", gTest.getCount()); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap08-静态成员变量/08-2_staticFunction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | 7 | class Demo 8 | { 9 | private: 10 | int i; 11 | public: 12 | int getI(); 13 | static void StaticFunc(const char* s); 14 | static void StaticSetI(Demo& d, int v); 15 | }; 16 | 17 | int Demo::getI() 18 | { 19 | return i; 20 | } 21 | 22 | void Demo::StaticFunc(const char* s) 23 | { 24 | printf("StaticFunc: %s\n", s); 25 | } 26 | 27 | void Demo::StaticSetI(Demo& d, int v) 28 | { 29 | d.i = v; 30 | } 31 | 32 | int main() 33 | { 34 | Demo::StaticFunc("main Begin..."); 35 | 36 | Demo d; 37 | 38 | Demo::StaticSetI(d, 10); 39 | 40 | printf("d.i = %d\n", d.getI()); 41 | 42 | Demo::StaticFunc("main End..."); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap08-静态成员变量/08-3_countObjectNumSafe.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | private: 10 | static int cCount; 11 | public: 12 | Test() 13 | { 14 | cCount++; 15 | } 16 | ~Test() 17 | { 18 | --cCount; 19 | } 20 | static int GetCount() 21 | { 22 | return cCount; 23 | } 24 | }; 25 | 26 | int Test::cCount = 0; 27 | 28 | int main() 29 | { 30 | printf("count = %d\n", Test::GetCount()); 31 | 32 | Test t1; 33 | Test t2; 34 | 35 | printf("count = %d\n", t1.GetCount()); 36 | printf("count = %d\n", t2.GetCount()); 37 | 38 | Test* pt = new Test(); 39 | 40 | printf("count = %d\n", pt->GetCount()); 41 | 42 | delete pt; 43 | 44 | printf("count = %d\n", Test::GetCount()); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap08-静态成员变量/C++进阶(8) 类的静态成员变量与静态成员函数.md: -------------------------------------------------------------------------------- 1 | # C++进阶(8) 类的静态成员变量与静态成员函数 2 | 3 | 统计程序运行期间某个类的对象数目。 4 | 5 | 类中静态成员变量是所有对象共享的,所以可以通过静态成员变量进行统计对象数目。 6 | 7 | ## 8.1 静态成员变量的特性 8 | 9 | - 静态成员变量属于整个类所有 10 | - 其生命周期不依赖于任何对象 11 | - 可以通过类名访问公有静态成员变量 12 | 13 | 所以 14 | 15 | - 所有对象共享类的静态成员变量 16 | - 可以通过对象名访问公有静态成员变量 17 | 18 | 19 | 20 | 语法: 21 | 22 | ```C++ 23 | Type ClassName::VarName = value ; 24 | ``` 25 | 26 | 静态成员变量在类外部单独分配空间,其存储在程序内部,位于全局数据区。 27 | 28 |
29 | 30 | ## 8.2 静态成员函数 31 | 32 | - 保证静态成员变量的安全性 33 | - 方便的获取静态成员变量 34 | 35 | 特点: 36 | 37 | - 静态成员属于整个类 38 | - 可以通过类名直接访问公有静态成员函数 39 | - 可以通过类对象直接访问静态成员函数 40 | 41 | 静态成员函数 V.S. 普通成员函数 42 | 43 | image-20201005100650197 44 | 45 | 46 | 47 | 统计对象个数: 48 | 49 | ```C++ 50 | #include 51 | 52 | class Test 53 | { 54 | private: 55 | static int cCount; 56 | public: 57 | Test() 58 | { 59 | cCount++; 60 | } 61 | ~Test() 62 | { 63 | --cCount; 64 | } 65 | static int GetCount() 66 | { 67 | return cCount; 68 | } 69 | }; 70 | 71 | int Test::cCount = 0; 72 | 73 | int main() 74 | { 75 | printf("count = %d\n", Test::GetCount()); 76 | 77 | Test t1; 78 | Test t2; 79 | 80 | printf("count = %d\n", t1.GetCount()); 81 | printf("count = %d\n", t2.GetCount()); 82 | 83 | Test* pt = new Test(); 84 | 85 | printf("count = %d\n", pt->GetCount()); 86 | 87 | delete pt; 88 | 89 | printf("count = %d\n", Test::GetCount()); 90 | 91 | return 0; 92 | } 93 | 94 | ``` 95 | 96 | ## 8.3 小结 97 | 98 | 静态成员变量和静态成员函数都是**属于类**,可以**通过类名直接访问**,所以在类中设置静态成员变量时,可以通过静态成员函数来进行管理。 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap08-静态成员变量/images/image-20201005100650197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap08-静态成员变量/images/image-20201005100650197.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/09-1_constructorReturn.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | 7 | class Test 8 | { 9 | int m_i; 10 | int m_j; 11 | bool m_Status; 12 | public: 13 | Test(int i, int j) : m_Status(false) 14 | { 15 | m_i = i; 16 | 17 | return; 18 | 19 | m_j = j; 20 | 21 | m_Status = true; 22 | } 23 | int getI() 24 | { 25 | return m_i; 26 | } 27 | int getJ() 28 | { 29 | return m_j; 30 | } 31 | int status() 32 | { 33 | return m_Status; 34 | } 35 | }; 36 | 37 | int main() 38 | { 39 | Test t1(1, 2); 40 | 41 | if( t1.status() ) 42 | { 43 | printf("t1.mi = %d\n", t1.getI()); 44 | printf("t1.mj = %d\n", t1.getJ()); 45 | 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/09-2_intArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include "09-2_intArray.h" 6 | 7 | IntArray::IntArray(int len) 8 | { 9 | m_length = len; 10 | } 11 | 12 | bool IntArray::constructor() { 13 | // 模拟内存失败 14 | m_pointer = new int[m_length]; 15 | if (m_pointer){ 16 | for(int i=0; iconstructor()) ) 34 | { 35 | delete ret; 36 | ret = nullptr; 37 | } 38 | 39 | return ret; 40 | } 41 | 42 | int IntArray::length() 43 | { 44 | return m_length; 45 | } 46 | 47 | bool IntArray::get(int index, int& value) 48 | { 49 | bool ret = (0 <= index) && (index < length()); 50 | 51 | if( ret ) 52 | { 53 | value = m_pointer[index]; 54 | } 55 | 56 | return ret; 57 | } 58 | 59 | bool IntArray::set(int index, int value) 60 | { 61 | bool ret = (0 <= index) && (index < length()); 62 | 63 | if( ret ) 64 | { 65 | m_pointer[index] = value; 66 | } 67 | 68 | return ret; 69 | } 70 | 71 | //void IntArray::free() 72 | //{ 73 | // delete[]m_pointer; 74 | //} 75 | 76 | IntArray::~IntArray() 77 | { 78 | delete[] m_pointer; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/09-2_intArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #ifndef CPP_EXERCEISE_09_2_INTARRAY_H 6 | #define CPP_EXERCEISE_09_2_INTARRAY_H 7 | 8 | class IntArray 9 | { 10 | private: 11 | int m_length; 12 | int* m_pointer; 13 | 14 | IntArray(int len); 15 | bool constructor(); 16 | public: 17 | static IntArray* NewInstance(int len); // 对象创建函数 18 | int length(); 19 | bool get(int index, int& value); 20 | bool set(int index ,int value); 21 | // void free(); 22 | ~IntArray(); 23 | }; 24 | 25 | 26 | #endif //CPP_EXERCEISE_09_2_INTARRAY_H 27 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/09-2_intArrayMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | 6 | #include 7 | #include "09-2_intArray.h" 8 | 9 | int main() 10 | { 11 | //IntArray a(5); 12 | 13 | IntArray* a = IntArray::NewInstance(5); 14 | 15 | printf("a.length = %d\n", a->length()); 16 | 17 | a->set(0, 1); 18 | 19 | for(int i=0; ilength(); i++) 20 | { 21 | int v = 0; 22 | 23 | a->get(i, v); 24 | 25 | printf("a[%d] = %d\n", i, v); 26 | } 27 | 28 | delete a; 29 | 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/09-3_TwoPhaseCons.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | #include 5 | 6 | class TwoPhaseCons 7 | { 8 | private: 9 | TwoPhaseCons() // 第一阶段构造函数 10 | { 11 | } 12 | bool construct() // 第二阶段构造函数 13 | { 14 | return true; 15 | } 16 | public: 17 | static TwoPhaseCons* NewInstance(); // 对象创建函数 18 | }; 19 | 20 | TwoPhaseCons* TwoPhaseCons::NewInstance() 21 | { 22 | TwoPhaseCons* ret = new TwoPhaseCons(); 23 | 24 | // 若第二阶段构造失败,返回 NULL 25 | if( !(ret && ret->construct()) ) 26 | { 27 | delete ret; 28 | ret = NULL; 29 | } 30 | 31 | return ret; 32 | } 33 | 34 | 35 | int main() 36 | { 37 | TwoPhaseCons* obj = TwoPhaseCons::NewInstance(); 38 | 39 | printf("obj = %p\n", obj); 40 | 41 | delete obj; 42 | 43 | return 0; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/C++进阶(9) 二阶构造模式.md: -------------------------------------------------------------------------------- 1 | # C++进阶(9) 二阶构造模式 2 | 3 | - 如何判断构造函数的返回结果 4 | - 构造函数执行 return 语句会发生什么 5 | - 构造函数执行结束是否意味着对象构造成功 6 | 7 | > 实验09-1 : 构造函数return 8 | 9 | 构造函数中如果含有return,会执行结束,所以构造函数执行结束,并不能说明对象构造成功。 10 | 11 | ## 9.1 半成品对象 12 | 13 | - 初始化操作不能按照预期完成得到的对象 14 | - 半成品对象时合法的C++对象,也是bug的来源 15 | 16 | > 实验09-2 : 半成品对象,即构造函数未按照预期完成 17 | 18 | 在内存分配失败时,程序会发生无法预测的段错误,此时bug无法定位。 19 | 20 | ## 9.2 二阶构造 21 | 22 | 构造过程可以分为: 23 | 24 | - 资源无关的初始化操作 25 | - 需要系统资源的操作(内存分配,文件管理) 26 | 27 | image-20201005104622013 28 | 29 | 二阶构造函数 30 | 31 | image-20201005104816838 32 | 33 | > 实验 09-3 :二阶构造类 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/images/image-20201005104622013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap09-二阶构造模式/images/image-20201005104622013.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap09-二阶构造模式/images/image-20201005104816838.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap09-二阶构造模式/images/image-20201005104816838.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap10-友元/10-1_friendFunction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | #include 5 | #include 6 | 7 | class Point 8 | { 9 | double x; 10 | double y; 11 | public: 12 | Point(double x, double y) 13 | { 14 | this->x = x; 15 | this->y = y; 16 | } 17 | 18 | double getX() 19 | { 20 | return x; 21 | } 22 | 23 | double getY() 24 | { 25 | return y; 26 | } 27 | 28 | friend double func(Point& p1, Point& p2); 29 | }; 30 | 31 | double func(Point& p1, Point& p2) 32 | { 33 | double ret = 0; 34 | 35 | ret = (p2.y - p1.y) * (p2.y - p1.y) + 36 | (p2.x - p1.x) * (p2.x - p1.x); 37 | 38 | ret = sqrt(ret); 39 | 40 | return ret; 41 | } 42 | 43 | int main() 44 | { 45 | Point p1(1, 2); 46 | Point p2(10, 20); 47 | 48 | printf("p1(%f, %f)\n", p1.getX(), p1.getY()); 49 | printf("p2(%f, %f)\n", p2.getX(), p2.getY()); 50 | printf("|(p1, p2)| = %f\n", func(p1, p2)); 51 | 52 | 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap10-友元/10-2_friendClass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | 7 | class ClassC 8 | { 9 | const char* n; 10 | public: 11 | ClassC(const char* n) 12 | { 13 | this->n = n; 14 | } 15 | 16 | friend class ClassB; 17 | }; 18 | 19 | class ClassB 20 | { 21 | const char* n; 22 | public: 23 | ClassB(const char* n) 24 | { 25 | this->n = n; 26 | } 27 | 28 | void getClassCName(ClassC& c) 29 | { 30 | printf("c.n = %s\n", c.n); 31 | } 32 | 33 | friend class ClassA; 34 | }; 35 | 36 | class ClassA 37 | { 38 | const char* n; 39 | public: 40 | ClassA(const char* n) 41 | { 42 | this->n = n; 43 | } 44 | 45 | void getClassBName(ClassB& b) 46 | { 47 | printf("b.n = %s\n", b.n); 48 | } 49 | /* 50 | void getClassCName(ClassC& c) 51 | { 52 | printf("c.n = %s\n", c.n); 53 | } 54 | */ 55 | }; 56 | 57 | int main() 58 | { 59 | ClassA A("A"); 60 | ClassB B("B"); 61 | ClassC C("C"); 62 | 63 | A.getClassBName(B); 64 | B.getClassCName(C); 65 | 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap10-友元/C++进阶(10) 友元.md: -------------------------------------------------------------------------------- 1 | # C++进阶(10) 友元 2 | 3 | ## 10.1 友元的概念 4 | 5 | - 友元是**函数与类之间** 或者 **类与类之间** 6 | 7 | - 友元关系是单项的 8 | 9 | 10 | 11 | image-20201005111132417 12 | 13 | 特点: 14 | 15 | - 类的友元可以是类或者函数 16 | - 友元不受访问界别的限制,可以直接访问具体类的所有成员 17 | 18 | > 实验10-1 :友元函数 19 | 20 |
21 | 22 | ## 10.2 友元的缺陷 23 | 24 | - 友元破坏了面相对象的封装性 25 | - 在实际产品中高效得不偿失,已被遗弃。 26 | 27 | 28 | 29 | 注意: 30 | 31 | - 友元不具备传递性 32 | - 友元可以是其他类的成员函数 33 | - 友元也可以是其他类 34 | 35 | > 实验10-2 :友元类 -------------------------------------------------------------------------------- /Cpp-Exerceise/chap10-友元/images/image-20201005111132417.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap10-友元/images/image-20201005111132417.png -------------------------------------------------------------------------------- /Cpp-Exerceise/chap11-函数重载/11-1_overLoading.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | #include 5 | 6 | class Test 7 | { 8 | int i; 9 | public: 10 | Test() 11 | { 12 | printf("Test::Test()\n"); 13 | this->i = 0; 14 | } 15 | 16 | Test(int i) 17 | { 18 | printf("Test::Test(int i)\n"); 19 | this->i = i; 20 | } 21 | 22 | Test(const Test& obj) 23 | { 24 | printf("Test(const Test& obj)\n"); 25 | this->i = obj.i; 26 | } 27 | 28 | static void func() 29 | { 30 | printf("void Test::func()\n"); 31 | } 32 | 33 | void func(int i) 34 | { 35 | printf("void Test::func(=int i), i %d\n", i); 36 | } 37 | 38 | int getI() 39 | { 40 | return i; 41 | } 42 | }; 43 | 44 | void func() 45 | { 46 | printf("void func()\n"); 47 | } 48 | 49 | void func(int i) 50 | { 51 | printf("void func(int i), i = %d\n", i); 52 | } 53 | 54 | int main() 55 | { 56 | // 全局函数 57 | func(); 58 | func(1); 59 | 60 | // 类的成员函数 61 | Test t; // Test::Test() 62 | Test t1(1); // Test::Test(int i) 63 | Test t2(t1); // Test(const Test& obj) 64 | 65 | // 静态成员函数和全局函数 66 | func(); // void func() 67 | Test::func(); // void Test::func() 68 | 69 | // 成员函数和全局函数 70 | func(2); // void func(int i), i = 2; 71 | t1.func(2); // void Test::func(int i), i = 2 72 | t1.func(); // void Test::func() 73 | 74 | return 0; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap11-函数重载/11-2_extendSystemFunction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/5. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | char* strcpy(char* buf, const char* str, unsigned int n) 9 | { 10 | return strncpy(buf, str, n); 11 | } 12 | 13 | int main() 14 | { 15 | const char* s = "D.T.Software"; 16 | char buf[8] = {0}; 17 | 18 | //strcpy(buf, s); 19 | strcpy(buf, s, sizeof(buf)-1); 20 | 21 | printf("%s\n", buf); 22 | 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap11-函数重载/C++进阶(11) 函数重载.md: -------------------------------------------------------------------------------- 1 | # C++进阶(11) 函数重载 2 | 3 | 类中成员函数的重载 4 | 5 | - 构造函数的重载 6 | - 普通成员函数的重载 7 | - 静态成员函数的重载 8 | 9 | > 实验11-1 函数重载 10 | 11 | 12 | 13 | ## 11.2 函数重载的意义 14 | 15 | - 通过函数名对函数功能进行提示 16 | - 参数列表对函数用法进行提示 17 | - 扩展系统中已存在的函数功能 18 | 19 | > 实验11-2 :扩展系统中已存在函数功能 20 | 21 | 重载函数必须在同一作用域中。 -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-1_ComplexAdd.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | #include 6 | 7 | class Complex 8 | { 9 | int a; 10 | int b; 11 | public: 12 | Complex(int a = 0, int b = 0) 13 | { 14 | this->a = a; 15 | this->b = b; 16 | } 17 | 18 | int getA() 19 | { 20 | return a; 21 | } 22 | 23 | int getB() 24 | { 25 | return b; 26 | } 27 | 28 | friend Complex Add(const Complex& p1, const Complex& p2); 29 | }; 30 | 31 | Complex Add(const Complex& p1, const Complex& p2) 32 | { 33 | Complex ret; 34 | 35 | ret.a = p1.a + p2.a; 36 | ret.b = p1.b + p2.b; 37 | 38 | return ret; 39 | } 40 | 41 | int main() 42 | { 43 | 44 | Complex c1(1, 2); 45 | Complex c2(3, 4); 46 | Complex c3 = Add(c1, c2); // c1 + c2 47 | 48 | printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB()); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-2_operator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | #include 6 | 7 | class Complex 8 | { 9 | int a; 10 | int b; 11 | public: 12 | Complex(int a = 0, int b = 0) 13 | { 14 | this->a = a; 15 | this->b = b; 16 | } 17 | 18 | int getA() 19 | { 20 | return a; 21 | } 22 | 23 | int getB() 24 | { 25 | return b; 26 | } 27 | 28 | friend Complex operator + (const Complex& p1, const Complex& p2); 29 | }; 30 | 31 | Complex operator + (const Complex& p1, const Complex& p2) 32 | { 33 | Complex ret; 34 | 35 | ret.a = p1.a + p2.a; 36 | ret.b = p1.b + p2.b; 37 | 38 | return ret; 39 | } 40 | 41 | int main() 42 | { 43 | 44 | Complex c1(1, 2); 45 | Complex c2(3, 4); 46 | Complex c3 = c1 + c2; // operator + (c1, c2) 47 | 48 | printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB()); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-3_ClassOperator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | #include 6 | 7 | class Complex 8 | { 9 | int a; 10 | int b; 11 | public: 12 | Complex(int a = 0, int b = 0) 13 | { 14 | this->a = a; 15 | this->b = b; 16 | } 17 | 18 | int getA() 19 | { 20 | return a; 21 | } 22 | 23 | int getB() 24 | { 25 | return b; 26 | } 27 | 28 | Complex operator + (const Complex& p) 29 | { 30 | Complex ret; 31 | printf("Complex operator + (const Complex& p)\n"); 32 | ret.a = this->a + p.a; 33 | ret.b = this->b + p.b; 34 | 35 | return ret; 36 | } 37 | 38 | friend Complex operator + (const Complex& p1, const Complex& p2); 39 | }; 40 | 41 | Complex operator + (const Complex& p1, const Complex& p2) 42 | { 43 | Complex ret; 44 | printf("Complex operator + (const Complex& p1, const Complex& p2)\n"); 45 | ret.a = p1.a + p2.a; 46 | ret.b = p1.b + p2.b; 47 | 48 | return ret; 49 | } 50 | 51 | int main() 52 | { 53 | 54 | Complex c1(1, 2); 55 | Complex c2(3, 4); 56 | Complex c3 = c1 + c2; // c1.operator + (c2) 57 | 58 | printf("c3.a = %d, c3.b = %d\n", c3.getA(), c3.getB()); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-4_Complex.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | #include "12-4_Complex.h" 6 | #include "math.h" 7 | 8 | Complex::Complex(double a, double b) 9 | { 10 | this->a = a; 11 | this->b = b; 12 | } 13 | 14 | double Complex::getA() 15 | { 16 | return a; 17 | } 18 | 19 | double Complex::getB() 20 | { 21 | return b; 22 | } 23 | 24 | double Complex::getModulus() 25 | { 26 | return sqrt(a * a + b * b); 27 | } 28 | 29 | Complex Complex::operator + (const Complex& c) 30 | { 31 | double na = a + c.a; 32 | double nb = b + c.b; 33 | Complex ret(na, nb); 34 | 35 | return ret; 36 | } 37 | 38 | Complex Complex::operator - (const Complex& c) 39 | { 40 | double na = a - c.a; 41 | double nb = b - c.b; 42 | Complex ret(na, nb); 43 | 44 | return ret; 45 | } 46 | 47 | Complex Complex::operator * (const Complex& c) 48 | { 49 | double na = a * c.a - b * c.b; 50 | double nb = a * c.b + b * c.a; 51 | Complex ret(na, nb); 52 | 53 | return ret; 54 | } 55 | 56 | Complex Complex::operator / (const Complex& c) 57 | { 58 | double cm = c.a * c.a + c.b * c.b; 59 | double na = (a * c.a + b * c.b) / cm; 60 | double nb = (b * c.a - a * c.b) / cm; 61 | Complex ret(na, nb); 62 | 63 | return ret; 64 | } 65 | 66 | bool Complex::operator == (const Complex& c) 67 | { 68 | return (a == c.a) && (b == c.b); 69 | } 70 | 71 | bool Complex::operator != (const Complex& c) 72 | { 73 | return !(*this == c); 74 | } 75 | 76 | Complex& Complex::operator = (const Complex& c) 77 | { 78 | if( this != &c ) 79 | { 80 | a = c.a; 81 | b = c.b; 82 | } 83 | 84 | return *this; 85 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-4_Complex.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | #ifndef CPP_EXERCEISE_12_4_COMPLEX_H 6 | #define CPP_EXERCEISE_12_4_COMPLEX_H 7 | 8 | #ifndef _COMPLEX_H_ 9 | #define _COMPLEX_H_ 10 | 11 | class Complex 12 | { 13 | double a; 14 | double b; 15 | public: 16 | Complex(double a = 0, double b = 0); 17 | double getA(); 18 | double getB(); 19 | double getModulus(); 20 | 21 | Complex operator + (const Complex& c); 22 | Complex operator - (const Complex& c); 23 | Complex operator * (const Complex& c); 24 | Complex operator / (const Complex& c); 25 | 26 | bool operator == (const Complex& c); 27 | bool operator != (const Complex& c); 28 | 29 | Complex& operator = (const Complex& c); 30 | }; 31 | 32 | #endif 33 | 34 | #endif //CPP_EXERCEISE_12_4_COMPLEX_H 35 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-4_ComplexMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/6. 3 | // 4 | 5 | 6 | #include 7 | #include "12-4_Complex.h" 8 | 9 | int main() 10 | { 11 | Complex c1(1, 2); 12 | Complex c2(3, 6); 13 | Complex c3 = c2 - c1; 14 | Complex c4 = c1 * c3; 15 | Complex c5 = c2 / c1; 16 | 17 | printf("c3.a = %f, c3.b = %f\n", c3.getA(), c3.getB()); 18 | printf("c4.a = %f, c4.b = %f\n", c4.getA(), c4.getB()); 19 | printf("c5.a = %f, c5.b = %f\n", c5.getA(), c5.getB()); 20 | 21 | Complex c6(2, 4); 22 | 23 | printf("c3 == c6 : %d\n", c3 == c6); 24 | printf("c3 != c4 : %d\n", c3 != c4); 25 | 26 | (c3 = c2) = c1; 27 | 28 | printf("c1.a = %f, c1.b = %f\n", c1.getA(), c1.getB()); 29 | printf("c2.a = %f, c2.b = %f\n", c2.getA(), c2.getB()); 30 | printf("c3.a = %f, c3.b = %f\n", c3.getA(), c3.getB()); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-5_intArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | #include "12-5_intArray.h" 6 | 7 | IntArray::IntArray(int len) 8 | { 9 | m_length = len; 10 | } 11 | 12 | IntArray::IntArray(const IntArray& obj) { 13 | m_length = obj.m_length; 14 | 15 | m_pointer = new int[m_length]; 16 | for (int i=0; iconstructor()) ) 42 | { 43 | delete ret; 44 | ret = nullptr; 45 | } 46 | 47 | return ret; 48 | } 49 | 50 | int IntArray::length() 51 | { 52 | return m_length; 53 | } 54 | 55 | bool IntArray::get(int index, int& value) 56 | { 57 | bool ret = (0 <= index) && (index < length()); 58 | 59 | if( ret ) 60 | { 61 | value = m_pointer[index]; 62 | } 63 | 64 | return ret; 65 | } 66 | 67 | bool IntArray::set(int index, int value) 68 | { 69 | bool ret = (0 <= index) && (index < length()); 70 | 71 | if( ret ) 72 | { 73 | m_pointer[index] = value; 74 | } 75 | 76 | return ret; 77 | } 78 | 79 | IntArray& IntArray::operator=(const IntArray &obj) { 80 | if (this != &obj){ 81 | int* pointer = new int[obj.m_length]; 82 | 83 | if (pointer){ 84 | for (int i=0; i < m_length; i++){ 85 | pointer[i] = obj.m_pointer[i]; 86 | } 87 | } 88 | m_length = obj.m_length; 89 | delete m_pointer; 90 | m_pointer = pointer; 91 | } 92 | 93 | return *this; 94 | } 95 | 96 | int& IntArray::operator[](int index) { 97 | return m_pointer[index]; 98 | } 99 | 100 | IntArray& IntArray::self() { 101 | return *this; 102 | } 103 | 104 | IntArray::~IntArray() 105 | { 106 | delete[] m_pointer; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-5_intArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/7. 3 | // 4 | 5 | #ifndef CPP_EXERCEISE_12_5_INTARRAY_H 6 | #define CPP_EXERCEISE_12_5_INTARRAY_H 7 | 8 | class IntArray 9 | { 10 | private: 11 | int m_length; 12 | int* m_pointer; 13 | 14 | IntArray(int len); 15 | IntArray(const IntArray& obj); 16 | bool constructor(); 17 | 18 | public: 19 | static IntArray* NewInstance(int len); // 对象创建函数 20 | int length(); 21 | bool get(int index, int& value); 22 | bool set(int index ,int value); 23 | 24 | IntArray& operator = (const IntArray& obj); 25 | int& operator [] (int index); 26 | IntArray& self(); 27 | ~IntArray(); 28 | }; 29 | 30 | #endif //CPP_EXERCEISE_12_5_INTARRAY_H 31 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/12-5_intArrayMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/9/27. 3 | // 4 | 5 | 6 | #include 7 | #include 8 | #include "12-5_intArray.h" 9 | 10 | using namespace std; 11 | 12 | void test_assignment(){ 13 | IntArray* a = IntArray::NewInstance(5); 14 | IntArray* b = IntArray::NewInstance(10); 15 | 16 | if( a && b ) 17 | { 18 | IntArray& array = a->self(); 19 | IntArray& brray = b->self(); 20 | 21 | cout << "array.length() = " << array.length() << endl; 22 | cout << "brray.length() = " << brray.length() << endl; 23 | 24 | array = brray; 25 | 26 | cout << "array.length() = " << array.length() << endl; 27 | cout << "brray.length() = " << brray.length() << endl; 28 | } 29 | 30 | delete a; 31 | delete b; 32 | 33 | } 34 | int main() 35 | { 36 | 37 | IntArray* a = IntArray::NewInstance(5); 38 | 39 | if (a != nullptr){ 40 | IntArray& array = a->self(); 41 | // printf("a.length = %d\n", a->length()); 42 | printf("a.length = %d\n", array.length()); 43 | 44 | // a->set(0, 1); 45 | array.set(0,1 ); 46 | 47 | for(int i=0; ilength(); i++) 48 | { 49 | // printf("a[%d] = %d\n", i, (*a)[i]); 50 | printf("a[%d] = %d\n", i, array[i]); 51 | } 52 | 53 | delete a; 54 | } 55 | 56 | test_assignment(); 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap12-操作符重载/C++进阶系列(12) 操作符重载.md: -------------------------------------------------------------------------------- 1 | # C++进阶系列(12) 操作符重载 2 | 3 | 复数加法: 4 | 5 | 解法1:利用友元函数 6 | 7 | > 实验12-1 利用友元函数对复数相加 8 | 9 | 10 | 11 | ## 12.1 操作符重载 12 | 13 | - 关键词 `operator` 14 | 15 | ```C++ 16 | Type operator Sign(const Type p1, const Type p2){ 17 | Type ret; 18 | 19 | return ret; 20 | } 21 | ``` 22 | 23 | 解法2:利用操作符重载 24 | 25 | - 操作符左右的两个参数 26 | - 将该函数声明为类的友元函数 27 | 28 | ```C++ 29 | Complex operator + (const Complex& p1, const Complex& p2) 30 | { 31 | Complex ret; 32 | 33 | ret.a = p1.a + p2.a; 34 | ret.b = p1.b + p2.b; 35 | 36 | return ret; 37 | } 38 | ``` 39 | 40 | > 实验12-2 类的友元运算符重载函数 41 | 42 |
43 | 44 | ## 12.2 类中操作符重载 45 | 46 | - 编译器优先在成员函数中寻找操作符重载函数 47 | 48 | ```C++ 49 | class Type{ 50 | public: 51 | Type operator Sign(const Type& p){ 52 | Type ret; 53 | 54 | return ret; 55 | } 56 | } 57 | ``` 58 | 59 | > 实验 12-3 类的运算符重载函数 60 | 61 | 62 | 63 | ## 12.3 数组操作符重载 64 | 65 | > 实验 12-5 : [] 操作符重载 66 | 67 | ## 12.4 赋值操作符重载 68 | 69 | > 实验 12-5 : = 操作符重载 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap13-智能指针/13-1_MemoryLeak.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/7. 3 | // 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Test{ 10 | public: 11 | Test(int val): i(val){} 12 | int value(){ 13 | return i; 14 | } 15 | ~Test(){} 16 | private: 17 | int i; 18 | }; 19 | 20 | int main(){ 21 | for (int i = 0; i < 5; i++){ 22 | Test* p = new Test(i); 23 | cout << p->value() << endl; // 使用完成,并未释放动态内存空间 24 | } 25 | 26 | return 0; 27 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap13-智能指针/13-2_autoPointer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/7. 3 | // 4 | #include 5 | 6 | using namespace std; 7 | 8 | class Test{ 9 | public: 10 | Test(int val): i(val){ 11 | cout << "Test(int val) " << endl; 12 | } 13 | int value(){ 14 | return i; 15 | } 16 | ~Test(){ 17 | cout << "~Test()" << endl; 18 | } 19 | private: 20 | int i; 21 | }; 22 | 23 | 24 | class Pointer{ 25 | public: 26 | Pointer(Test* p): m_p(nullptr) {} 27 | Pointer(const Pointer &obj){ 28 | delete m_p; 29 | m_p = obj.m_p; 30 | const_cast(obj).m_p = nullptr; 31 | } 32 | Pointer& operator = (const Pointer& obj){ 33 | if (this != &obj){ 34 | delete m_p; 35 | m_p = obj.m_p; 36 | const_cast(obj).m_p = nullptr; 37 | } 38 | 39 | return *this; 40 | } 41 | Test* operator -> (){ 42 | return m_p; 43 | } 44 | Test& operator * (){ 45 | return *m_p; 46 | } 47 | 48 | bool isNull(){ 49 | return m_p == nullptr; 50 | } 51 | ~Pointer(){ 52 | delete m_p; 53 | } 54 | 55 | private: 56 | Test* m_p; 57 | }; 58 | 59 | 60 | int main(){ 61 | Pointer p = new Test(0); 62 | cout << p->value() << endl; 63 | 64 | Pointer p2 = p; 65 | cout << p.isNull() << endl; 66 | cout << p2.isNull() << endl; 67 | 68 | return 0; 69 | } -------------------------------------------------------------------------------- /Cpp-Exerceise/chap13-智能指针/C++进阶(13) 智能指针.md: -------------------------------------------------------------------------------- 1 | # C++进阶(13) 智能指针 2 | 3 | C语言中经常会出现内存泄漏的bug,即 4 | 5 | - 动态申请的内存空间,在使用时候不释放该空间。 6 | - C++ 中没有垃圾回收机制 7 | - 指针无法控制所指堆空间的生命周期。 8 | 9 | ## 13.1 智能指针 10 | 11 | 在指针声明周期结束时自动释放堆空间,并且一片堆空间最多由一个指针标识,避免指针运算和指针比较。 12 | 13 | 解决方案: 14 | 15 | - 重载指针特征操作符(-> 和 *) 16 | - 只能定义一个重载函数 / 没有参数 17 | 18 | 19 | 20 | > 智能指针只能用来指向堆空间的对象或者变量。 21 | 22 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap14-操作符/14-1_logicalOperator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int func(int i) 11 | { 12 | cout << "int func(int i) : i = " << i << endl; 13 | 14 | return i; 15 | } 16 | 17 | int main() 18 | { 19 | if( func(0) && func(1) ) 20 | { 21 | cout << "Result is true!" << endl; 22 | } 23 | else 24 | { 25 | cout << "Result is false!" << endl; 26 | } 27 | 28 | cout << endl; 29 | 30 | if( func(0) || func(1) ) 31 | { 32 | cout << "Result is true!" << endl; 33 | } 34 | else 35 | { 36 | cout << "Result is false!" << endl; 37 | } 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap14-操作符/14-2_trackOfLogicalOperator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Test 11 | { 12 | int mValue; 13 | public: 14 | Test(int v) 15 | { 16 | mValue = v; 17 | } 18 | int value() const 19 | { 20 | return mValue; 21 | } 22 | }; 23 | 24 | bool operator && (const Test& l, const Test& r) 25 | { 26 | return l.value() && r.value(); 27 | } 28 | 29 | bool operator || (const Test& l, const Test& r) 30 | { 31 | return l.value() || r.value(); 32 | } 33 | 34 | Test func(Test i) 35 | { 36 | cout << "Test func(Test i) : i.value() = " << i.value() << endl; 37 | 38 | return i; 39 | } 40 | 41 | int main() 42 | { 43 | Test t0(0); 44 | Test t1(1); 45 | 46 | if( func(t0) && func(t1) ) 47 | { 48 | cout << "Result is true!" << endl; 49 | } 50 | else 51 | { 52 | cout << "Result is false!" << endl; 53 | } 54 | 55 | cout << endl; 56 | 57 | if( func(1) || func(0) ) 58 | { 59 | cout << "Result is true!" << endl; 60 | } 61 | else 62 | { 63 | cout << "Result is false!" << endl; 64 | } 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap14-操作符/14-3_commaOperator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void func(int i) 11 | { 12 | cout << "func() : i = " << i << endl; 13 | } 14 | 15 | int main() 16 | { 17 | int a[3][3] = { 18 | (0, 1, 2), // 因为有括号,所以为逗号表达式 19 | (3, 4, 5), // 逗号表达式值为最后一个数 20 | (6, 7, 8) // 修改为 {} 21 | }; 22 | 23 | int i = 0; 24 | int j = 0; 25 | 26 | while( i < 5 ) 27 | func(i), 28 | 29 | i++; 30 | 31 | for(i=0; i<3; i++) 32 | { 33 | for(j=0; j<3; j++) 34 | { 35 | cout << a[i][j] << endl; 36 | } 37 | } 38 | 39 | (i, j) = 6; 40 | 41 | cout << "i = " << i << endl; 42 | cout << "j = " << j << endl; 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap14-操作符/14-4_overloadCommaOperator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Test 11 | { 12 | int mValue; 13 | public: 14 | Test(int i) 15 | { 16 | mValue = i; 17 | } 18 | int value() 19 | { 20 | return mValue; 21 | } 22 | }; 23 | 24 | Test& operator , (const Test& a, const Test& b) 25 | { 26 | return const_cast(b); 27 | } 28 | 29 | Test func(Test& i) 30 | { 31 | cout << "func() : i = " << i.value() << endl; 32 | 33 | return i; 34 | } 35 | 36 | int main() 37 | { 38 | Test t0(0); 39 | Test t1(1); 40 | // Test tt = (func(t0), func(t1)); // Test tt = func(t1); 41 | Test tt = (operator ,(func(t0), func(t1))) ; // 重载逗号表达式函数:作为参数,从右向左计算 42 | cout << tt.value() << endl; // 1 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap14-操作符/C++进阶(14) 你忽视的操作符.md: -------------------------------------------------------------------------------- 1 | # C++进阶(14) 你忽视的操作符 2 | 3 | ## 14.1 逻辑操作符 4 | 5 | 逻辑操作符的原生语意: 6 | 7 | - 操作符只有bool值(true false) 8 | - 逻辑表达式不用完全计算能确定最终值 9 | 10 | > 实验14-1 逻辑操作符 11 | 12 | 13 | 14 | 陷阱:**重载逻辑操作符** 15 | 16 | > 实验14-2 重载逻辑操作符的陷阱 17 | 18 | 问题分析:重载逻辑操作符本质为函数,在编译器遇到被重载的操作符时,会转换为函数调用的形式,则逻辑操作符的左右两个数都换转换为函数参数,而函数参数的调用顺序不定。 19 | 20 | 违背了逻辑操作符的原生语意,所以在实际工程开发中避免重载逻辑操作符。如果一定要重载,则 21 | 22 | - 通过重载比较操作符代替 23 | - 通过使用成员函数代替 24 | - 使用全局函数对逻辑操作符进行重载 25 | 26 |
27 | 28 | ## 14.2 逗号操作符 29 | 30 | 逗号表达式: 31 | 32 | - 用于将多个子表达式连接为一个表达式 33 | - 表达式的值为最后一个子表达式的值 34 | - 前N-1 个子表达式可以没有返回值 35 | - 从左向右顺序计算子表达式的值 36 | 37 | > 实验 14-3:逗号操作符 38 | 39 | ### 14.2.1 重载逗号操作符 40 | 41 | - 使用全局函数对逗号操作符进行重载 42 | - 参数必须有一个是类类型 43 | - 返回值必须是引用 44 | 45 | ```C++ 46 | Class& operator , (const Class& a, const Class& b){ 47 | return const_cast(b); 48 | } 49 | ``` 50 | 51 | 与逻辑操作符相同,重载逗号操作符后,会从右向左计算,违背了逗号表达式从左向右计算的原生语义。 52 | 53 | 所以,工程中**不要重载逗号表达式** 。 54 | 55 |
56 | 57 | ## 14.3 前置操作符与后置操作符 58 | 59 | i++ , ++i 有什么区别?为什么? 60 | 61 | i++ // i 的值作为返回值,i自增1 62 | 63 | ++i // i自增1,将i的值作为返回值 64 | 65 | > 实验14-5 : 自增运算符 66 | 67 | 单独的自增运算符,由于编译器的优化,并无差别。 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/15-1_CTypeTrans.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/19. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() 11 | { 12 | short s = 'a'; 13 | unsigned int ui = 1000; 14 | int i = -2000; 15 | double d = i; 16 | 17 | cout << "d = " << d << endl; 18 | cout << "ui = " << ui << endl; 19 | cout << "ui + i = " << ui + i << endl; 20 | 21 | // i 转换为 unsign int 22 | if( (ui + i) > 0 ) 23 | { 24 | cout << "Positive" << endl; 25 | } 26 | else 27 | { 28 | cout << "Negative" << endl; 29 | } 30 | 31 | // 转换为 int 32 | cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; 33 | 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/15-2_CppClassTypeTrans.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/19. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Test 11 | { 12 | int mValue; 13 | public: 14 | Test() 15 | { 16 | mValue = 0; 17 | } 18 | 19 | explicit Test(int i) 20 | { 21 | mValue = i; 22 | } 23 | 24 | Test operator + (const Test& p) 25 | { 26 | Test ret(mValue + p.mValue); 27 | 28 | return ret; 29 | } 30 | 31 | int value() 32 | { 33 | return mValue; 34 | } 35 | }; 36 | 37 | int main() 38 | { 39 | Test t; 40 | 41 | t = static_cast(5); // t = Test(5); 42 | 43 | Test r; 44 | 45 | r = t + static_cast(10); // r = t + Test(10); 46 | 47 | cout << r.value() << endl; 48 | 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/15-3_ClassTypeToBuildType.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/19. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Test 11 | { 12 | int mValue; 13 | public: 14 | explicit Test(int i = 0) 15 | { 16 | mValue = i; 17 | } 18 | int value() 19 | { 20 | return mValue; 21 | } 22 | operator int () 23 | { 24 | return mValue; 25 | } 26 | }; 27 | 28 | int main() 29 | { 30 | Test t(100); 31 | // 隐式类型转换 32 | int i = t; // int i = t.operator int(); 33 | 34 | cout << "t.value() = " << t.value() << endl; 35 | cout << "i = " << i << endl; 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/15-4_TransConstrClassTypeToClassType.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/19. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Test; 10 | 11 | class Value 12 | { 13 | public: 14 | Value() 15 | { 16 | } 17 | explicit Value(Test& t) 18 | { 19 | } 20 | }; 21 | 22 | class Test 23 | { 24 | int mValue; 25 | public: 26 | Test(int i = 0) 27 | { 28 | mValue = i; 29 | } 30 | int value() 31 | { 32 | return mValue; 33 | } 34 | operator Value() 35 | { 36 | Value ret; 37 | cout << "operator Value()" << endl; 38 | return ret; 39 | } 40 | }; 41 | 42 | int main() 43 | { 44 | Test t(100); 45 | Value v = t; 46 | 47 | return 0; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/C++进阶(15) 类型转换.md: -------------------------------------------------------------------------------- 1 | # C++进阶(15) 类型转换 2 | 3 | C中的类型之间会进行隐式的类型转换,转换规则如下: 4 | 5 | image-20201019211319320 6 | 7 | 上述类型转换会将小类型转换为大类型。 8 | 9 | > 实验15-1 C 语言中的隐式类型转换 10 | 11 |
12 | 13 | ## 15.1 再谈构造函数 14 | 15 | 构造函数可以定义为不同类型的参数 16 | 17 | 转换构造函数的参数满足以下条件: 18 | 19 | - 有且只有一个参数 20 | - 参数是基本类型 21 | - 参数是其他类型 22 | 23 | 示例:对于以下语句: 24 | 25 | ````C++ 26 | Test t; 27 | t = 100; 28 | ```` 29 | 30 | 当类中有转换构造函数时,将以上代码默认转换为 31 | 32 | ```C++ 33 | Test t; 34 | t = Test(100); 35 | ``` 36 | 37 | 其实是将int类型强制转换为 Test 类型。 38 | 39 |
40 | 41 | 对于以上示例,编译器会将类型隐式转换,但工程中,这种隐式转换经常不是我们想要的,所以,为了避免上述情况的发生,通常使用 `explicit` 关键字杜绝编译器的转换尝试。转换方式如下: 42 | 43 | ```C++ 44 | static_cast (value); 45 | ClassName(value); 46 | (ClassName) value; (不推荐) 47 | ``` 48 | 49 | > 15-2 Cpp static_cast 强制类型转换与explicit 50 | 51 |
52 | 53 | ## 15.2 逆转换 / 类型转换函数 54 | 55 | 能否将类类型转换为 内置类型? 56 | 57 | C++类中可以定义类型转换函数,用于将类对象转换为其他类型,语法规则如下 58 | 59 | ```C++ 60 | Operator Type(){ 61 | Type ret; 62 | // ... 63 | return ret; 64 | } 65 | ``` 66 | 67 | > 实验5-3 : operator Type() 类型转换函数 68 | 69 |
70 | 71 | ## 15.3 类类型转换 72 | 73 | 能否将类类型转换为类类型? 74 | 75 | 转换构造函数可以将一个类类型转换为另一个类类型,如Test类转换为Value类,而类型转换函数也是将一个类类型转换为另一个类类型。所以两个函数是互逆的。如果同时定义,必须将 转换构造函数转换为 explicit 类型。 76 | 77 | > 工程中,一般不会使用类型转换函数,避免隐式转换。会使用 `Type toType()` 的共有成员函数代替类转换函数。 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Cpp-Exerceise/chap15-类型转换/images/image-20201019211319320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Cpp-Exerceise/chap15-类型转换/images/image-20201019211319320.png -------------------------------------------------------------------------------- /Git/[Git札记 1] GitHub 使用指南.md: -------------------------------------------------------------------------------- 1 | # How to properly use GitHub? 2 | 3 | [TOC] 4 | 5 | 6 | 7 | 8 | 9 | ## Terminal 10 | 11 | ### Prerequisites 12 | 13 | 1. 注册账号 14 | 2. 安装Git 15 | 16 | ### Step 1: Authenticate Yourself and Your Machine 17 | 18 | ​ 将电脑和Github账户通过`SSH` key 进行认证,在后面每次进行操纵自己仓库时,Github会自动进行认证,无需输入密码。下面创建 `SSH` key: 19 | 20 | 1. 打开 `terminal` 21 | 2. 输入邮箱地址以关联自己的Github账户 22 | 23 | ```bash 24 | ssh-keygen -t rsa -b 4096 -C "" 25 | ``` 26 | 27 | 3. 接下来会让你输入保存 `.ssh` 的目录,默认为 `home` 文件夹下,输入 `Enter` 选取默认路径,可在 `~/.ssh/id_rsa`中查看 28 | 4. 然后,系统提示选择密码,直接 `Enter` 默认为空。 29 | 30 | 下面查看一下 `ssh` key 是否创建成功: 31 | 32 | ```bash 33 | cd ~/.ssh 34 | ``` 35 | 36 | ``` 37 | ls 38 | ``` 39 | 40 | `.ssh` 文件夹下有`id_rsa` 和 `id_rsa.pub` 两个文件,其中,`id_rsa` 是私有密钥,`id_rsa.pub` 是公有密钥。 41 | 42 | 5. 将 `ssh` key 给 ssh-agent 帮助完成验证,下面创建一个ssh-agent 43 | 44 | ``` 45 | eval "$(ssh-agent -s)" 46 | ``` 47 | 48 | 查看`~/.ssh` 目录下是否生成 `config` 文件,若有,修改为以下内容,若文件夹中没有 `config` 文件,则自行创建并将以下内容保存至文件中。 49 | 50 | ``` 51 | Host * 52 | AddKeysToAgent yes 53 | UseKeychain yes 54 | IdentityFile ~/.ssh/id_rsa 55 | ``` 56 | 57 | 最后,将key添加至代理 58 | 59 | ``` 60 | ssh-add -K ~/.ssh/id_rsa 61 | ``` 62 | 63 | ### Step 2: Add the Key to Your Github 64 | 65 | 下一步将SSH key 添加至Github 账户。将公有密钥复制,在Terminal中输入: 66 | 67 | ``` 68 | pbcopy < ~/.ssh/id_rsa.pub 69 | ``` 70 | 71 | 在Github上添加SSH key: 72 | 73 | ![image-20190809125120287](./images/setting.png) 74 | 75 | 选择 `SSH and GPG keys` : 76 | 77 | ![image-20190809125430570](./images/sshandgpg.png) 78 | 79 | 新建 `New SSH key` 80 | 81 | ![image-20190809125613393](./images/new_ssh.png) 82 | 83 | 将复制的公用密钥粘贴至 `Key` 中,`Title` 中可写自己电脑的名称,用以区分不同电脑的 `ssh key` 。 84 | 85 | ![image-20190809125756374](./images/add_ssh.png) 86 | 87 | ### Step 3: Create a Github Repository 88 | 89 | 现在已经链接电脑与Github 账户, 可通过电脑管理仓库(Respository)。首先,新建一个仓库: 90 | 91 | ![image-20190809131135726](./images/create_repository.png) 92 | 93 | 点击 `New` , 会有新的仓库的描述 94 | 95 | ![image-20190809131546879](./images/description.png) 96 | 97 | 创建后,可看到下面的新仓库: 98 | 99 | ![image-20190809131815001](./images/create_comp.png) 100 | 101 | 102 | 103 | ### Step 4: Clone Your Repository 104 | 105 | 上一步在GitHub上创建了一个新仓库,下面创建一个本地版本的仓库,在 GitHub中称为 `clone` 。首先,点击 `clone and download` , 复制仓库地址: 106 | 107 | ![image-20190809132710111](./images/rep_url.png) 108 | 109 | 打开 `Terminal` , 选择或创建一个保存项目的路径: 110 | 111 | ```bash 112 | mkdir ~/Desktop/projects 113 | cd ~/Desktop/projects 114 | ``` 115 | 116 | 将远程项目 `clone` 至本地, `repository_URL` 是刚才复制的仓库地址: 117 | 118 | ``` 119 | git clone 120 | ``` 121 | 122 | 完成之后,会看到 `projects` 文件夹下已经下载好 `NewRepositoryDemo` 仓库。 123 | 124 | 125 | 126 | ### Step 5: Push Your First Commit 127 | 128 | 上面四步已经将远程仓库和本地电脑链接,可以通过本地对项目进行管理,完成修改后,提交至远程仓库,下面实践提交第一个Github文件。首先,在刚才保存的项目文件夹 `~/home/Desktop/projects/NewRepository` 中,新建一个 `Hello_GitHub.py` 文件,内容为: 129 | 130 | ```python 131 | print("Hello, GitHub!") 132 | ``` 133 | 134 | 打开 `Terminal` , 进入仓库目录下,查看仓库状态: 135 | 136 | ``` 137 | cd ~/home/projects/NewRepository/ 138 | git status 139 | ``` 140 | 141 | ![image-20190809135701041](./images/git_staus.png) 142 | 143 | 144 | 145 | > 本地仓库同步至远程仓库经过以下三个步骤: 146 | > 147 | > 1. 暂存更改(s tasing changes) 148 | > 2. 添加注释(Committing them) 149 | > 3. 推送至远程仓库 (Pushing them to the remote repository) 150 | 151 | 152 | 153 | 那么,第一步将暂存本地更改: 154 | 155 | ```bash 156 | git add Hello_GitHub.py 157 | ``` 158 | 159 | 查看仓库状态: 160 | 161 | ```bash 162 | git staus 163 | ``` 164 | 165 | ![image-20190809140827187](/Users/lyj/LearningNotes/TecNotes/images/git_add.png) 166 | 167 | 第二步, 为修改添加注释: 168 | 169 | ``` 170 | git commit -m "commit" 171 | ``` 172 | 173 | ![image-20190809140709096](./images/git_commit.png) 174 | 175 | `1 file changedj, 1 insertion(+)` ,用于描述修改,这里只添加了1个文件,文件增加了1行。如果修改了多个文件和多个修改,这里都会有修改描述。 176 | 177 | 第三步,推送至远程仓库。 178 | 179 | ```bash 180 | git push origin master 181 | or git push 182 | ``` 183 | 184 | 现在,查看Github 中的仓库,可以看到添加的文件和注释 185 | 186 | ![image-20190809141438552](./images/update_github.png) 187 | 188 | ### Step 6: Congratulations 189 | 190 | 成功上传第一个GitHub项目,你可以通过这个过程,不断为项目添加更多文件和更新。通过创建仓库,同步本地和远程仓库,可以更好理解GitHub的工作流程。 191 | 192 | 193 | 194 | ## GitHub Desktop 195 | 196 | ### Prerequisites 197 | 198 | 1. 注册账号 199 | 2. 下载GitHub Desktop 200 | 201 | 202 | 203 | ### Step 1: Create/Clone a GitHub Prository 204 | 205 | 打开 `GitHub Desktop` , 登陆GitHub账号,新建或者克隆一个仓库。 206 | 207 | ![image-20190809203340546](./images/new_clone.png?lastModify=1565355549) 208 | 209 | 选择 `Create a new repository` 或者 `clone repository` 210 | 211 | ![image-20190809203706834](./images/create.png?lastModify=1565355549) 212 | 213 | 可以看到仓库界面: 214 | 215 | ![image-20190809205140449](./images/upload.png?lastModify=1565355549) 216 | 217 | 218 | 219 | ### Step 2: Push Repository 220 | 221 | 在本地创建仓库后,我们需要把仓库推送至GitHub 222 | 223 | ![image-20190809205521684](./images/push.png?lastModify=1565355549) 224 | 225 | 推送之后,界面会变成下图, 226 | 227 | ![img](./images/desktop.png?lastModify=1565355549) 228 | 229 | ### Step 3: Create a New Branch 230 | 231 | GitHub 的版本控制通过 `branch` 进行管理,当我们需要保存当前的版本,并且在当前版本上进行修改时,可通过创建新的分支,把新的更新放在 `branch` 中, 如果需要恢复至更改之前的文件,则只需要修改至原来的 `branch`即可。 232 | 233 | ![image-20190809205830735](./images/branch.png?lastModify=1565355549) 234 | 235 | ### Step 4: Push Branch 236 | 237 | 与步骤2相同。 238 | 239 | 240 | 241 | ## Reference 242 | 243 | 1. [在Mac(OS X)中使用GitHub的超详细攻略(20170706)](https://blog.csdn.net/baimafujinji/article/details/74533992) 244 | 2. [How to Properly Setup Your Github Repository — Mac Version](https://medium.com/@aklson_DS/how-to-properly-setup-your-github-repository-mac-version-3a8047b899e5) 245 | 246 | -------------------------------------------------------------------------------- /Git/[Git札记 2] Github 常用操作及其命令.md: -------------------------------------------------------------------------------- 1 | # [Git札记 2] Github 常用操作及其命令 2 | 3 | Git系列笔记记录日常Git命令使用。 4 | 5 | [TOC] 6 | 7 | ## 开始管理仓库 8 | 9 | 1. 在 `GitHub` 上新建一个项目(详细参照上一篇 `GitHub使用指南` ) 10 | 2. 在本地创建文件夹以保存项目 11 | 12 | ```bash 13 | cd ~/Desktop 14 | mkdir Git_Projects 15 | ``` 16 | 17 | 3. 将远程项目同步至本地 18 | 19 | ```bash 20 | git clone https://github.com/cooldeepAI/Learning_Notes.git 21 | ``` 22 | 23 | 4. 查看 `~/Desktop/Git_Projects` 目录下有 `Learning_Notes` 工程,可在工程目录下做修改 24 | 5. 提交修改至本地仓库 25 | 26 | ```bash 27 | git status 28 | git add new_file 29 | git commit -m "add new_file" 30 | ``` 31 | 32 | 6. 提交修改至远程仓库 33 | 34 | ```bash 35 | git push 36 | or git push origin master 37 | ``` 38 | 39 | 40 | 41 | ## 常用操作 42 | 43 | ### 撤销 commit (NOT PUSH) 44 | 45 | ```bash 46 | git commit --amend 47 | ``` 48 | 49 | 50 | 51 | 52 | 53 | ### 更改目录/文件名 54 | 55 | ```bash 56 | git mv old_directory[old_file] new_directory[old_file] 57 | ``` 58 | 59 | 60 | 61 | ### 从远程仓库拉取更新本地仓库 62 | 63 | #### Fetch directly to local and merge remote 64 | 65 | 1. 在GitHub修改了文件,比如修改文件名,或者修改了文件 66 | 2. 将远程仓库拉取至本地仓库 67 | 68 | ```bash 69 | git remote -v # 查看远程仓库 70 | git fetch origin master# 拉取仓库至本地 71 | ``` 72 | 73 | 3. 比较本地仓库与远程仓库区别 74 | 75 | ```bash 76 | git log -p master.. origin/master 77 | ``` 78 | 79 | 4. 合并本地仓库 80 | 81 | ```bash 82 | git merge origin/master 83 | ``` 84 | 85 | #### Fetch indirectly to temp local and merge remote or delete temp 86 | 87 | 1. 查看远程仓库 88 | 89 | ```bash 90 | git remote -v 91 | ``` 92 | 93 | 2. 拉取仓库,暂存至本地暂存区 94 | 95 | ```bash 96 | git fetch origin master:temp 97 | ``` 98 | 99 | 3. 比较本地仓库和远程仓库 100 | 101 | ```bash 102 | git diff temp 103 | ``` 104 | 105 | 4. 合并/删除 `temp` 分支至 `master` 分支 106 | 107 | ```bash 108 | git merge temp # 合并 109 | git branch -D temp # 删除 110 | ``` 111 | 112 | 113 | 114 | ## 其他 115 | 116 | 1. 在 `Terminal` 查看使用Git 查看 `git status` ,中文使用八进制显示,如何解决? 117 | 118 | ```bash 119 | git config --global core.quotepath false 120 | ``` 121 | 122 | 2. Mac 修改文件后,`git status ` 无显示,如何设置全局忽略 `DS_Store`? 123 | 124 | - 添加编辑 `home` 目录下的 `.gitignore_global` 文件 125 | 126 | ```bash 127 | vi ~/.gitignore_global 128 | ``` 129 | 130 | - 添加下面两行 131 | 132 | ``` 133 | .DS_Store 134 | */.DS_Store 135 | ``` 136 | 137 | - 查看 `home` 目录 138 | 139 | ```bash 140 | pwd 141 | ``` 142 | 143 | - 修改 `home` 目录下 `gitconfig` 文件, 添加全局忽略规则 144 | 145 | ```bash 146 | vi ~/.gitconfig 147 | ``` 148 | 149 | ``` 150 | [core] 151 | excludesfile = /Users/zxxair/.gitignore_global 152 | ``` 153 | 154 | - 若修改中仍有 `.DS_Store` 文件,可能是已提交至Github,需要删除。 155 | 156 | ```bash 157 | git rm --cached .DS_Store 158 | find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch 159 | ``` 160 | 161 | 162 | 163 | ## Reference 164 | 165 | 1. [Git重命名文件和文件夹](https://blog.csdn.net/shenwanjiang111/article/details/78776191) 166 | 2. [Git修改上次提交的Commit](https://segmentfault.com/q/1010000000761908) 167 | 3. [更新远程仓库至本地](https://blog.csdn.net/u012150179/article/details/17172211) 168 | 4. [Mac git忽略.DS_Store](https://www.jianshu.com/p/e3d8eb2a4295) -------------------------------------------------------------------------------- /Git/[Git札记 3] Git基本概念及其配置.md: -------------------------------------------------------------------------------- 1 | # [Git 札记 3] Git基本概念及配置 2 | 3 | 很多时候使用 Git 时,仅仅使用常用的几条命令,比如:`git add .`, `git commmit -m 'commit'`, `git push origin master` ,但并没有真正的理解Git,若能理解Git的思想和基本工作原理,用起来会知其所以然,游刃有余。 4 | 5 | 6 | 7 | [TOC] 8 | 9 | ## Git 的基本概念 10 | 11 | ### Git 的四个特性 12 | 13 | 1. 直接记录快照,而非差异对比 14 | 15 | 其他版本控制系统: ![屏幕快照 2019-08-13 上午8.24.25](./images/tra_cvs.png) 16 | 17 | Git : 18 | 19 | ![屏幕快照 2019-08-13 上午8.31.42](./images/git.png) 20 | 21 | 相比其他版本控制系统进保存修改内容,Git 每次对全部文件制作快照并保存索引。 22 | 23 | 2. 几乎所有操作都是本地执行 24 | 25 | 3. Git 保证完整性 26 | 27 | 4. Git 一般只添加数据 28 | 29 | 30 | 31 | ### 三个状态 32 | 33 | 1. Committed (已提交) 34 | 2. Modified (已修改) 35 | 3. Staged (已暂存) 36 | 37 | 38 | 39 | ## Git 配置 40 | 41 | ### 配置文件位置 42 | 43 | 1. `/etc/gitconfig` :系统中每个用户和他们仓库的通用配置,`--system` 调用 44 | 2. `~/.gitconfig` 或 `~/.config/git/config` :当前用户的配置, `--global` 调用 45 | 3. 当前仓库的Git 目录中的 `config` 文件( `.git/config` ), 默认调用 46 | 47 | 48 | 49 | ### 如何配置 50 | 51 | 1. 配置用户信息 52 | 53 | ```bash 54 | git config --global user.name "Shuangzhen" 55 | git config --global user.email "dreamre21@gmail.com" 56 | ``` 57 | 58 | 2. 检查配置信息 59 | 60 | ```bash 61 | git config user.name 62 | git config user.email 63 | vi ~/.gitconfig 64 | ``` 65 | 66 | 3. 帮助信息 67 | 68 | ```bash 69 | git help 70 | git help 71 | man git- 72 | ``` 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Git/assets/image-20190819080159879.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/assets/image-20190819080159879.png -------------------------------------------------------------------------------- /Git/images/add_ssh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/add_ssh.png -------------------------------------------------------------------------------- /Git/images/apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/apply.png -------------------------------------------------------------------------------- /Git/images/branch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/branch.png -------------------------------------------------------------------------------- /Git/images/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/create.png -------------------------------------------------------------------------------- /Git/images/create_comp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/create_comp.png -------------------------------------------------------------------------------- /Git/images/create_repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/create_repository.png -------------------------------------------------------------------------------- /Git/images/description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/description.png -------------------------------------------------------------------------------- /Git/images/desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/desktop.png -------------------------------------------------------------------------------- /Git/images/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/git.png -------------------------------------------------------------------------------- /Git/images/git_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/git_add.png -------------------------------------------------------------------------------- /Git/images/git_commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/git_commit.png -------------------------------------------------------------------------------- /Git/images/git_life.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/git_life.png -------------------------------------------------------------------------------- /Git/images/git_staus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/git_staus.png -------------------------------------------------------------------------------- /Git/images/new_clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/new_clone.png -------------------------------------------------------------------------------- /Git/images/new_ssh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/new_ssh.png -------------------------------------------------------------------------------- /Git/images/push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/push.png -------------------------------------------------------------------------------- /Git/images/rep_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/rep_url.png -------------------------------------------------------------------------------- /Git/images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/setting.png -------------------------------------------------------------------------------- /Git/images/sshandgpg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/sshandgpg.png -------------------------------------------------------------------------------- /Git/images/tra_cvs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/tra_cvs.png -------------------------------------------------------------------------------- /Git/images/update_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/update_github.png -------------------------------------------------------------------------------- /Git/images/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/upload.png -------------------------------------------------------------------------------- /Git/images/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Git/images/wechat.png -------------------------------------------------------------------------------- /Linux/Linux 命令速查手册(一)帮助命令.md: -------------------------------------------------------------------------------- 1 | # Linux 命令速查手册(一)帮助命令 2 | 3 | [TOC] 4 | 5 | ## 1 帮助命令 6 | 7 | ### 1.1 whatis:简述命令的作用 8 | 9 | whatis: 简述命令的作用 10 | 11 | ```bash 12 | root@Eternal:~# whatis whatis 13 | whatis (1) - display one-line manual page descriptions 14 | ``` 15 | 16 | ### 1.2 info:查看命令详细的说明文档 17 | 18 | ```bash 19 | root@Eternal:~# info whatis 20 | WHATIS(1) Manual pager utils WHATIS(1) 21 | 22 | NAME 23 | whatis - display one-line manual page descriptions 24 | 25 | SYNOPSIS 26 | whatis [-dlv?V] [-r|-w] [-s list] [-m system[,...]] [-M path] [-L 27 | locale] [-C file] name ... 28 | 29 | DESCRIPTION 30 | Each manual page has a short description available within it. whatis 31 | searches the manual page names and displays the manual page descrip‐ 32 | tions of any name matched. 33 | 34 | name may contain wildcards (-w) or be a regular expression (-r). Using 35 | these options, it may be necessary to quote the name or escape (\) the 36 | special characters to stop the shell from interpreting them. 37 | ...... 38 | ``` 39 | 40 | ### 1.3 man:查看命令的说明文档 41 | 42 | ```bash 43 | root@Eternal:~# man locate 44 | locate(1) General Commands Manual locate(1) 45 | 46 | NAME 47 | locate - find files by name 48 | 49 | SYNOPSIS 50 | locate [OPTION]... PATTERN... 51 | 52 | DESCRIPTION 53 | locate reads one or more databases prepared by updatedb(8) and writes 54 | file names matching at least one of the PATTERNs to standard output, 55 | one per line. 56 | 57 | If --regex is not specified, PATTERNs can contain globbing characters. 58 | If any PATTERN contains no globbing characters, locate behaves as if 59 | the pattern were *PATTERN*. 60 | 61 | By default, locate does not check whether files found in database still 62 | exist (but it does require all parent directories to exist if the data‐ 63 | base was built with --require-visibility no). locate can never report 64 | files created after the most recent update of the relevant database. 65 | ...... 66 | ``` 67 | 68 | man分类标示: 69 | 70 | 1)用户可以操作的命令或者是可执行文件 71 | 72 | 2))系统核心可调用的函数与工具等 73 | 74 | 3))一些常用的函数与数据库 75 | 76 | 4)设备文件的说明 77 | 78 | 5)设置文件或者某些文件的格式 79 | 80 | 6)游戏 81 | 82 | 7)惯例与协议等。例如Linux标准文件系统、网络协议、ASCⅡ,码等说明内容 83 | 84 | 8)系统管理员可用的管理条令 85 | 86 | 9)与内核有关的文件 87 | 88 | 用法: 89 | 90 | ```bash 91 | root@Eternal:~# man 3 printf 92 | ``` 93 | 94 | 95 | 96 | ### 1.4 which:查看可执行文件的路径 97 | 98 | which:查看可执行文件的路径 99 | 100 | ```bash 101 | root@Eternal:~# which locate 102 | /usr/bin/locate 103 | ``` 104 | 105 | ### 1.5 whereis:查看程序的搜索路径 106 | 107 | whereis:查看程序的搜索路径 108 | 109 | ```bash 110 | root@Eternal:~# whereis locate 111 | locate: /usr/bin/locate /usr/share/man/man1/locate.1.gz 112 | ``` 113 | 114 | -------------------------------------------------------------------------------- /Linux/Linux 命令速查手册(三)文本处理.md: -------------------------------------------------------------------------------- 1 | # Linux 命令速查手册(三)文本处理 2 | 3 | [TOC] 4 | 5 | ## 3 文本处理 6 | 7 | ### 3.1 find:文件查找 8 | 9 | - find . -name "file_name" -maxdepth n:在当前目录下搜索n层,查找 `file_name` 文件 10 | 11 | ```bash 12 | root@Eternal:/home/sigai# find . -name "new*" 13 | ./new_dir 14 | ./new_dir/new_file 15 | root@Eternal:/home/sigai# find . -maxdepth 1 -name "new*" 16 | ./new_dir 17 | root@Eternal:/home/sigai# find . -maxdepth 1 -name "new*" -type f 18 | root@Eternal:/home/sigai# find . -maxdepth 2 -name "new*" -type f 19 | ./new_dir/new_file 20 | root@Eternal:/home/sigai# 21 | ``` 22 | 23 | - find [dir_name] -name [file_name] :在 `dir_name` 下查找 `file_name` 文件 24 | 25 | ```bash 26 | root@Eternal:~# find -name "*.txt" -o -name "*.pdf" 27 | ./Programfile/miniconda/share/doc/xz/faq.txt 28 | ./Programfile/miniconda/share/doc/xz/xz-file-format.txt 29 | ./Programfile/miniconda/share/doc/xz/history.txt 30 | ./Programfile/miniconda/share/doc/xz/examples/00_README.txt 31 | ./Programfile/miniconda/share/doc/xz/lzma-file-format.txt 32 | ... 33 | root@Eternal:~# find . \( -name "*.txt" -o -name "*.pdf" \) 34 | ./Programfile/miniconda/share/doc/xz/faq.txt 35 | ./Programfile/miniconda/share/doc/xz/xz-file-format.txt 36 | ./Programfile/miniconda/share/doc/xz/history.txt 37 | ./Programfile/miniconda/share/doc/xz/examples/00_README.txt 38 | ./Programfile/miniconda/share/doc/xz/lzma-file-format.txt 39 | ...... 40 | ``` 41 | 42 | - find [dir_name] -path [path_name]:在 `dir_name` 目录下,查找包含 `path_name` 的路径 43 | 44 | ```bash 45 | root@Eternal:~# find /home -path "*new_dir" 46 | /home/sigai/new_dir 47 | /home/new_dir 48 | root@Eternal:~# find /home -path "*new_dir*" 49 | /home/sigai/new_dir 50 | /home/sigai/new_dir/new_file 51 | /home/new_dir 52 | /home/new_dir/old_file 53 | root@Eternal:~# find / -path "*new_dir*" 54 | /home/sigai/new_dir 55 | /home/sigai/new_dir/new_file 56 | /home/new_dir 57 | /home/new_dir/old_file 58 | /new_dir 59 | /new_dir/new_file 60 | ``` 61 | 62 | 63 | 64 | ### 3.2 grep:文本搜索 65 | 66 | - grep match_pattern file:默认访问匹配 67 | - -o 只输出匹配的文本行 **VS** -v 只输出没有匹配的文本行 68 | - -c 统计文件中包含文本的次数 69 | 70 | - grep -c “text” filename 71 | - -n 打印匹配的行号 72 | - -i 搜索时忽略大小写 73 | - -l 只打印文件名 74 | 75 | - grep "content" . -R -n:在多级目录中对文本递归搜索 76 | 77 | ```bash 78 | 79 | root@Eternal:/home/sigai# grep "file" . -R -n 80 | ./.bashrc:2:# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) 81 | ./.bashrc:15:# append to the history file, don't overwrite it 82 | ./.bashrc:27:# match all files and zero or more directories and subdirectories. 83 | ./.bashrc:30:# make less more friendly for non-text input files, see lesspipe(1) 84 | ./.bashrc:100:# You may want to put all your additions into a separate file like 85 | ./.bashrc:109:# this, if it's already enabled in /etc/bash.bashrc and /etc/profile 86 | ./.bash_history:9:chmod new_dir/new_file 87 | ./.bash_history:10:chmod 777 new_dir/new_file 88 | ./.bash_history:14:ln new_dir/new_file soft_link_new 89 | ./.bash_history:16:chmod a+x new_dir/new_file 90 | ./.profile:1:# ~/.profile: executed by the command interpreter for login shells. 91 | ./.profile:2:# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login 92 | ./.profile:4:# see /usr/share/doc/bash/examples/startup-files for examples. 93 | ./.profile:5:# the files are located in the bash-doc package. 94 | ./.profile:7:# the default umask is set in /etc/profile; for setting the umask 95 | ./new_dir/new_file:1:This is a new file. 96 | root@Eternal:/home/sigai# grep -e "file" -e "old" new_dir/new_file 97 | This is a new file. 98 | ``` 99 | 100 | 101 | 102 | ### 3.3 xargs:命令行参数转换 103 | 104 | - cat file_name | xargs -n 3:单行输出转换为多行输出 105 | 106 | ```bash 107 | root@Eternal:/home/sigai# grep -e "file" -e "old" new_dir/new_file 108 | This is a new file. 109 | root@Eternal:/home/sigai# cat new_dir/new_file | xargs -n 3 110 | This is a 111 | new file. 112 | root@Eternal:/home/sigai# 113 | ``` 114 | 115 | 116 | 117 | ### 3.4 sort:排序 118 | 119 | 字段说明 120 | 121 | - -n 按数字进行排序 VS -d 按字典序进行排序 122 | - -r 逆序排序 123 | - -k N 指定按第N列排序 124 | 125 | ```bash 126 | root@Eternal:/home/sigai# sort -nrk 1 new_dir/new_file 127 | This is a new file. 128 | ``` 129 | 130 | 131 | 132 | ### 3.5 uniq:消除重复行 133 | 134 | - sort file_name | uniq 135 | - 消除重复行 136 | - -c 统计各行在文件中重复的次数 137 | - -d 找出重复行 138 | 139 | ```bash 140 | root@Eternal:/home/sigai# sort new_dir/new_file | uniq 141 | Add a new lines. 142 | The Third line. 143 | This is a new file. 144 | root@Eternal:/home/sigai# sort new_dir/new_file | uniq -c 145 | 1 Add a new lines. 146 | 2 The Third line. 147 | 1 This is a new file. 148 | root@Eternal:/home/sigai# sort new_dir/new_file | uniq -d 149 | The Third line. 150 | ``` 151 | 152 | 153 | 154 | ### 3.6 cut:按列切分字符 155 | 156 | - cut -f1,3 file_name:截取文件 `file_name` 的第2行和第4行 157 | - cut -f2 file_name:删除文件 `file_name` 的第2行 158 | - cut f2 -d ":" file_name:指定定界符 159 | 160 | 161 | 162 | ### 3.7 paste:按列拼接文本 163 | 164 | - paste -d ":" file_1 file_2 :将两个文件拼接,以":" 分割 165 | 166 | ```bash 167 | root@Eternal:/home/sigai/new_dir# paste -d ":" new_file table.txt > paste_file 168 | root@Eternal:/home/sigai/new_dir# cat paste_file 169 | This is a new file.:01 tom 69 91 170 | Add a new lines.:02 jack 71 87 171 | The Third line.:03 alex 68 98 172 | The Third line.: 173 | ``` 174 | 175 | 176 | 177 | ### 3.8 wc:统计行和字符数 178 | 179 | - wc 180 | - -l:统计行数 181 | - -w:统计单词数 182 | - -c:统计字符数 183 | 184 | ```bash 185 | root@Eternal:/home/sigai/new_dir# cat paste_file | wc -l 186 | 4 187 | root@Eternal:/home/sigai/new_dir# cat paste_file | wc -w 188 | 24 189 | root@Eternal:/home/sigai/new_dir# cat paste_file | wc -c 190 | 119 191 | ``` 192 | 193 | 194 | 195 | ### 3.9 sed:文本替换 196 | 197 | - sed 's/text/replace_txt/' file:将文件 `file` 中 `text` 替换为 `replace_txt` 198 | 199 | ```bash 200 | root@Eternal:/home/sigai/new_dir# cat new_file 201 | This is a new file. 202 | Add a new lines. 203 | The Third line. 204 | The Third line. 205 | root@Eternal:/home/sigai/new_dir# sed 's/lines/line/' new_file 206 | This is a new file. 207 | Add a new line. 208 | The Third line. 209 | The Third line. 210 | ``` 211 | 212 | 具体用法:https://man.linuxde.net/sed 213 | 214 | 215 | 216 | ### awk:数据流处理 217 | 218 | 用法:https://man.linuxde.net/awk 219 | 220 | -------------------------------------------------------------------------------- /Linux/Linux 命令速查手册(五)用户管理工具.md: -------------------------------------------------------------------------------- 1 | # Linux 命令速查手册(五)用户管理工具 2 | 3 | [TOC] 4 | 5 | ## 5 用户管理工具 6 | 7 | ### 5.1 useradd:添加用户 8 | 9 | - useradd -m username:创建 `username` 并在 `/home/` 目录下创建相应文件夹。 10 | 11 | ```bash 12 | root@Eternal:/home# useradd -m username 13 | root@Eternal:/home# ls 14 | baselines find_file_content list new_dir sigai soft_link_new username 15 | root@Eternal:/home# 16 | ``` 17 | 18 | ### 5.2 passwd:为用户设置密码 19 | 20 | - passwd username:为 `username` 设置密码 21 | 22 | ```bash 23 | root@Eternal:/home# passwd username 24 | Enter new UNIX password: 25 | Retype new UNIX password: 26 | passwd: password updated successfully 27 | ``` 28 | 29 | ### 5.3 userdel:删除用户 30 | 31 | - userdel -r username:删除用户及用户目录 32 | 33 | ```bash 34 | root@Eternal:/home# userdel -r username 35 | userdel: username mail spool (/var/mail/username) not found 36 | root@Eternal:/home# ls 37 | baselines find_file_content list new_dir sigai soft_link_new 38 | root@Eternal:/home# 39 | ``` 40 | 41 | ### 5.4 su:切换用户 42 | 43 | - su username:切换至 `username` 用户 44 | 45 | ```bash 46 | root@Eternal:/home# su sigai 47 | sigai@Eternal:/home$ su root 48 | Password: 49 | root@Eternal:/home# 50 | ``` 51 | 52 | ### 5.5 group:用户组 53 | 54 | - group:查看当前用户所在的用户组 55 | 56 | ```bash 57 | root@Eternal:/home# groups 58 | root 59 | root@Eternal:/home# 60 | ``` 61 | 62 | - usermod 63 | - -G root sigai:将用户 `sigai` 添加至 `root` 组 64 | - -g root sigai:将用户 `sigai` 添加至 `root` 组,并且从原来的组中删去 65 | 66 | ```bash 67 | root@Eternal:/home# usermod -G root sigai 68 | root@Eternal:/home# su sigai 69 | sigai@Eternal:/home$ groups 70 | sigai root 71 | root@Eternal:/home# usermod -g root sigai 72 | root@Eternal:/home# su sigai 73 | sigai@Eternal:/home$ groups 74 | root 75 | ``` 76 | 77 | - more 78 | - /etc/passwd:查看所有的用户及权限 79 | - /etc/groups:查看系统所有组 80 | 81 | ```bash 82 | root@Eternal:/home# more /etc/passwd 83 | root:x:0:0:root:/root:/bin/bash 84 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 85 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 86 | sys:x:3:3:sys:/dev:/usr/sbin/nologin 87 | sync:x:4:65534:sync:/bin:/bin/sync 88 | ... 89 | root@Eternal:/home# more /etc/group 90 | root:x:0:sigai 91 | daemon:x:1: 92 | bin:x:2: 93 | sys:x:3: 94 | adm:x:4:syslog 95 | tty:x:5: 96 | disk:x:6: 97 | lp:x:7: 98 | ... 99 | ``` 100 | 101 | ### 5.6 chmod:用户权限 102 | 103 | ```bash 104 | root@Eternal:/home# ls -l 105 | total 20 106 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 107 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 108 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 109 | drwxr-xr-x 2 root root 4096 Nov 2 05:11 new_dir 110 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 111 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 112 | root@Eternal:/home# 113 | ``` 114 | 115 |   文件属性字段总共有10个字母组成,第一个字母表示文件类型,如果这个字母是一个减号”-”,则说明该文件是一个普通文件。字母”d”表示该文件是一个目录,字母”d”,是dirtectory(目录)的缩写。 后面的9个字母为该文件的权限标识,3个为一组,分别表示文件所属用户、用户所在组、其它用户的读写和执行权限; 116 | 117 | 118 | 119 | - chmod usermark(+/-)PermissionMark 120 | - userMark取值: 121 | - u:用户 122 | - g:组 123 | - o:其它用户 124 | - a:所有用户 125 | - PermissionsMark取值: 126 | - r:读 127 | - w:写 128 | - x:执行 129 | 130 | ```bash 131 | root@Eternal:/home# chmod a+w new_dir/ 132 | root@Eternal:/home# ls -l 133 | total 20 134 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 135 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 136 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 137 | drwxrwxrwx 2 root root 4096 Nov 2 05:11 new_dir 138 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 139 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 140 | ``` 141 | 142 | - chmod 700 file:将文件权限设置为 `700` 143 | - 数字形式:使用三位八进制数字的形式来表示权限,第一位指定属主的权限,第二位指定组权限,第三位指定其他用户的权限,每位通过4(读)、2(写)、1(执行)三种数值的和来确定权限。如6(4+2)代表有读写权,7(4+2+1)有读、写和执行的权限。 144 | 145 | ```bash 146 | root@Eternal:/home# chmod 700 new_dir/ 147 | root@Eternal:/home# ls -l 148 | total 20 149 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 150 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 151 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 152 | drwx------ 2 root root 4096 Nov 2 05:11 new_dir 153 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 154 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 155 | ``` 156 | 157 | 158 | 159 | ### 5.8 chown:修改文件或目录持有者 160 | 161 | - chown username directory:将目录使用者权限更改为 `username` 162 | 163 | ```bash 164 | root@Eternal:/home# ls -l 165 | total 20 166 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 167 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 168 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 169 | drwx------ 2 root root 4096 Nov 2 05:11 new_dir 170 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 171 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 172 | root@Eternal:/home# chown sigai new_dir/ 173 | root@Eternal:/home# ls -l 174 | total 20 175 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 176 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 177 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 178 | drwx------ 2 sigai root 4096 Nov 2 05:11 new_dir 179 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 180 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 181 | root@Eternal:/home# cd new_dir/ 182 | root@Eternal:/home/new_dir# ls -l 183 | total 4 184 | -rw-r--r-- 1 root root 20 Nov 2 04:29 old_file 185 | ``` 186 | 187 | - chown -R username directory:将目录及目录下的文件使用者权限递归的更改为 `username` 188 | 189 | ```bash 190 | oot@Eternal:/home/new_dir# cd .. 191 | root@Eternal:/home# chown -R sigai new_dir/ 192 | root@Eternal:/home# ls -l 193 | total 20 194 | drwxr-xr-x 6 root root 4096 Mar 27 2019 baselines 195 | -rw-r--r-- 1 root root 20 Nov 2 04:39 find_file_content 196 | -rw-r--r-- 1 root root 27 Nov 2 05:25 list 197 | drwx------ 2 sigai root 4096 Nov 2 05:11 new_dir 198 | drwxr-xr-x 3 sigai root 4096 Nov 5 10:03 sigai 199 | lrwxrwxrwx 1 root root 16 Nov 2 05:11 soft_link_new -> new_dir/new_file 200 | root@Eternal:/home# cd new_dir/ 201 | root@Eternal:/home/new_dir# ls -l 202 | total 4 203 | -rw-r--r-- 1 sigai root 20 Nov 2 04:29 old_file 204 | ``` 205 | 206 | ### 5.9 bashrc / profile:环境变量 207 | 208 | #### bashrc / profile 209 | 210 | `bashrc` 与 `profile` 都用于保存用户的环境信息,`bashrc` 用于交互式 `non-loginshell` ,而 `profile` 用于交互式`login shell`。 211 | 212 | `/etc/profile` ,`/etc/bashrc` 是系统全局环境变量设定 213 | 214 | `~/.profile`,`~/.bashrc` 用户目录下的私有环境变量设定 215 | 216 | 217 | 218 | #### 当系统获得一个shell进程时,读取环境设置脚本分为三步: 219 | 220 | 1. 读入全局环境变量 `/etc/profile` ,根据内容读取 `/etc/profile.d` 和 `/etc/inputrc` 221 | 2. 读取当前登陆用户的 `HOME` 目录下的 `~/.bash_profile` ,然后是 `~/.bash_login` ,最后读取 `~/.profile` 222 | 3. 读取 `~/bashrc` 223 | 224 | 225 | 226 | #### ~/.bashrc v.s. ~/.profile 227 | 228 | 1. 两个文件都可以自定义设置 229 | 2. `~/.profile` 可以设置当前用户专有的路径,环境变量等。在登录时只执行一次。 230 | 3. `~/.bashrc` 也为当前用户专有的设定文档,可以设置路径,别名。每次登陆 `shell script` 时都会执行。 231 | 232 | -------------------------------------------------------------------------------- /Linux/Linux 命令速查手册(四)磁盘管理.md: -------------------------------------------------------------------------------- 1 | # Linux 命令速查手册(四)磁盘管理 2 | 3 | [TOC] 4 | 5 | ## 4 磁盘管理 6 | 7 | ### 4.1 df:查看磁盘大小 8 | 9 | - df -h:查看磁盘空间利用大小 10 | - df -sh:查看当前目录所占空间大小 11 | 12 | ```bash 13 | root@Eternal:~# df -h 14 | Filesystem Size Used Avail Use% Mounted on 15 | udev 225M 0 225M 0% /dev 16 | tmpfs 49M 8.1M 41M 17% /run 17 | /dev/vda1 9.6G 4.8G 4.4G 53% / 18 | tmpfs 245M 28K 245M 1% /dev/shm 19 | tmpfs 5.0M 0 5.0M 0% /run/lock 20 | tmpfs 245M 0 245M 0% /sys/fs/cgroup 21 | tmpfs 49M 0 49M 0% /run/user/0 22 | root@Eternal:~# du -sh 23 | 442M . 24 | root@Eternal:~# du -sh `ls` | sort 25 | 16K shadowsocksR.sh 26 | 345M Programfile 27 | 4.0K agentpolis-javadoc 28 | 4.0K jupyter_projects 29 | 4.0K repo 30 | 52K shadowsocksR.log 31 | 68M miniconda.sh 32 | 8.0K index.html 33 | ``` 34 | 35 | 36 | 37 | ### 4.2 tar:打包/压缩 38 | 39 | - tar -cvf file.tar /file:将 `file` 文件打包 40 | 41 | ```bash 42 | root@Eternal:/home/sigai# tar -cvf new_dir.tar /new_dir/ 43 | tar: Removing leading `/' from member names 44 | /new_dir/ 45 | /new_dir/new_file 46 | root@Eternal:/home/sigai# ls 47 | new_dir new_dir.tar 48 | root@Eternal:/home/sigai# 49 | ``` 50 | 51 | - gzip file.txt:压缩文件 52 | 53 | ```bash 54 | root@Eternal:/home/sigai/new_dir# gzip new_file table.txt paste_file 55 | root@Eternal:/home/sigai/new_dir# ls 56 | new_file.gz paste_file.gz table.txt.gz 57 | ``` 58 | 59 | 60 | 61 | ### 4.3 tar:解包/解压缩 62 | 63 | - tar -xvf file.tar:将 `file.tar` 解包 64 | 65 | ```bash 66 | root@Eternal:/home/sigai# tar -xvf new_dir.tar 67 | new_dir/ 68 | new_dir/new_file 69 | ``` 70 | 71 | - gunzip file.gz:将 `file.gz` 解压缩 72 | 73 | ```bash 74 | root@Eternal:/home/sigai/new_dir# gunzip table.txt.gz 75 | root@Eternal:/home/sigai/new_dir# ls 76 | new_file new_file.gz paste_file.gz table.txt 77 | ``` 78 | 79 | -------------------------------------------------------------------------------- /Others/Books/Pro_Git.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Others/Books/Pro_Git.pdf -------------------------------------------------------------------------------- /Others/LinuxProbe.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Others/LinuxProbe.pdf -------------------------------------------------------------------------------- /Others/Mac 新手上路.md: -------------------------------------------------------------------------------- 1 | # Mac 新手上路 2 | 3 | [TOC] 4 | 5 | ## 1.1 软件安装 6 | 7 | ### 1.1.1 所需软件 8 | 9 | 1. 通讯软件 10 | - QQ 11 | - Wechat 12 | 2. 开发软件 13 | - Pycharm 14 | - Anaconda 15 | - Typora 16 | - Github Desktop 17 | 3. 浏览器 18 | - Chrome 19 | 4. 播放器 20 | - IINA播放器 21 | 22 | 23 | 24 | ### 1.1.2 如何安装 25 | 26 | 1. 下载所需要的软件安装包(dmg文件) 27 | - 从App store下载 28 | - 从软件官网下载 29 | - 从网络下载 30 | 2. 安装,双击下载的安装包 31 | 3. 将App拖至Application中 32 | 33 | 34 | 35 | ## 1.2 快捷键 36 | 37 | ### 1.2.1 访达(Finder)操作 38 | 39 | 显示路径:`Option + Command + P ` 40 | 41 | 显示隐藏文件:`Command + shift+ . ` 42 | 43 | 前进:`Command + [` 44 | 45 | 后退:`Command + ]` 46 | 47 | home目录:`Command + shift + H` 48 | 49 | 新建文件夹:`Command + shift + N` 50 | 51 | 52 | 53 | ### 1.2.2 文件操作 54 | 55 | 移动文件:先复制(`Command + C`),再粘贴(`Option + Command + V`) 56 | 57 | 拷贝文件:先复制(`Command + C`),再粘贴(`Option + Command`) 58 | 59 | 复制文件:`Command + D` 60 | 61 | 文件重命名:点击选择文件,回车`Enter` 62 | 63 | 复制文件路径:点击选择文件,点击`Option` , 复制路径 64 | 65 | 显示隐藏文件:`Command + shift + .` 66 | 67 | 68 | 69 | ### 1.2.3 截图操作 70 | 71 | 截取全屏:`Command + shift + 3` 72 | 73 | 矩形截屏:`Command + shift + 4` 74 | 75 | 76 | 77 | ### 1.2.4 标签页切换 78 | 79 | 切换程序:`Command + tab` 80 | 81 | 标签页切换:`Control + tab` 82 | 83 | 84 | 85 | ## 1.2.5 其他 86 | 87 | 全局搜索:`Command + Space` 88 | 89 | home目录:打开访达, 快捷键`Command + shift + H` 90 | 91 | 92 | 93 | ## 1.3 手势操作 94 | 95 | ### 1.3.1 两指操作 96 | 97 | 同时上下:翻页 98 | 99 | 同时点击:左键 100 | 101 | ### 1.3.2 三指操作 102 | 103 | 同时点击:选择 104 | 105 | 同时滑动:移动窗口 106 | 107 | ### 1.3.3 四指操作 108 | 109 | 同时向上:后台应用 110 | 111 | 同时左右:切换桌面 112 | 113 | 114 | 115 | ## 1.3 gdb 调试 116 | 117 | [MacOS下gdb教程-血泪史](https://zhuanlan.zhihu.com/p/68398728) 118 | 119 | ## 1.3 其他 120 | 121 | Q1: 如何修改用户名,如何添加用户? 122 | 123 | **修改用户名**:`系统偏好设置` ---->`用户与群组`---->`解锁` ---->`右击用户`----> `高级选项` 124 | 125 | **添加用户**:`系统偏好设置` ---->`用户与群组`---->`解锁` ----> `➕` 126 | 127 | 128 | 129 | Q2: 如何打开`Ternimal`? 130 | 131 | 全局搜索(`Command + Space`), 输入`terminal`,`Enter` 132 | 133 | 134 | 135 | Q3: Chrome 在全屏之后显示单个网页,无地址栏? 136 | 137 | `显示` , 取消选择`在全屏模式下始终选择工具栏` 138 | 139 | 140 | 141 | Q4: Terminal 如何新建文件? 142 | 143 | 在terminal下, 输入`touch filename` 即可 144 | 145 | 146 | 147 | Q5: Mac 中的远程连接和 `ftp` 148 | 149 | 在 `terminal` , 输入 150 | 151 | ``` 152 | ssh [username]@[server ip] 153 | ``` 154 | 155 | 输入密码即可。 156 | 157 | 连接 `ftp` : 打开 `finder` ,快捷键:`Command + K` 158 | 159 | 160 | 161 | ## 参考 162 | 163 | 1. [Finder操作(详细)](https://www.jianshu.com/p/3666e6954e8a) 164 | 2. [[官方]Mac 键盘快捷键](https://support.apple.com/zh-cn/HT201236) 165 | 3. [[官方]Mac Terminal快捷键](https://support.apple.com/zh-cn/guide/terminal/trmlshtcts/mac) 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /Others/数据挖掘:概念与技术(第三版)中文版.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Others/数据挖掘:概念与技术(第三版)中文版.pdf -------------------------------------------------------------------------------- /Python/Numpy/Python核心编程-Numpy系列(一).md: -------------------------------------------------------------------------------- 1 | ### Python核心编程-Numpy篇-第1节课 2 | 3 | #### 本节课大纲 4 | 5 | - Numpy是什么? 6 | - 为什么要学Numpy? 7 | - Numpy为何如此快? 8 | - 除了快,还有呢? 9 | - 为什么需要听这门课? 10 | - 课程大纲 11 | - 课程学习方法 12 | 13 | #### Numpy是什么? 14 | 15 | ##### 看看维基百科 16 | 17 | > support for **large**, **multi-dimensional arrays** and **matrices**, along with a large collection of high-level **mathematical functions to operate on these arrays**. 18 | 19 | ##### 为什么不用List? 20 | 21 | - List本质上是一个链表,链表有链表的优势,但也有局限性 22 | - List在特定任务上的存储效率,操作效率,计算效率太低 23 | 24 | #### 为什么要学Numpy? 25 | 26 | - 运算快 27 | - 省内存 28 | - 函数库 29 | 30 | ##### 能有多快?直接学TensorFlow呗? 31 | 32 | 在一个线性回归任务中,有人做过测评,得到如下结果: 33 | 34 | | Implementation | Elapsed Time | 35 | | ------------------------------------ | ------------ | 36 | | Pure Python with list comprehensions | 18.65s | 37 | | Numpy | 0.32s | 38 | | TensorFlow on CPU | 1.20s | 39 | 40 | [Reference: Pure Python vs NumPy vs TensorFlow Performance Comparison](https://realpython.com/numpy-tensorflow-performance/) 41 | 42 | ##### Numpy与TensorFlow如何抉择? 43 | 44 | | | TensorFlow | Numpy | 45 | | :------: | :--------------: | :------------------: | 46 | | 框架目标 | Machine Learning | Scientific Computing | 47 | | 运行架构 | CPU,GPU,TPU | CPU | 48 | | 底层语言 | C++ | C、Fortran | 49 | | 分布式 | 支持 | 不支持 | 50 | | 自动微分 | 支持 | 不支持 | 51 | | 上手难度 | 较难 | 一般 | 52 | 53 | --- 54 | 55 | #### 为什么Numpy可以这么快? 56 | 57 | ##### 核心数据结构:ndarray 58 | 59 | - 内存使用效率高 60 | - 支持快速矢量化运算 61 | - 语言级别的性能优势 62 | 63 | ##### 关于内存使用效率,这里简单举个例子 64 | 65 | ``` py 66 | >>> import numpy as np 67 | >>> from sys import getsizeof 68 | >>> py_list = list(range(10000)) 69 | >>> np_arr = np.array(py_list) 70 | >>> getsizeof(py_list) 71 | 90112 72 | >>> np_arr.nbytes 73 | 80000 74 | >>> sum([getsizeof(x) for x in range(10000)]) 75 | 279996 76 | ``` 77 | 78 | 79 | 80 | #### 除了快,还有什么理由让你不得不学Numpy? 81 | 82 | ##### 生态 83 | 84 | - scipy 85 | - pandas 86 | - scikit-learn 87 | - matplotlib 88 | - TensorFlow 89 | - PyTorch 90 | 91 | #### 为什么需要听这门课? 92 | 93 | - 系统:能找到的为数不多的真正系统讲解Numpy的课程 94 | - 梯度:从入门到高手级别,都能找到值得学习的知识点 95 | - 深度:让你看清楚Numpy ndarray在内存上大概是什么样的 96 | - 广度:让你了解Numpy内置的满目琳琅的兵器库 97 | - 思想:从Python的面向对象编程到Numpy的矢量化编程 98 | 99 | --- 100 | 101 | #### 课程大纲 102 | 103 | | 课程名称 | 课程简介 | 104 | | :-----------------------: | :-------------------: | 105 | | 第二节课:Numpy快速入门 | 一节课,让你用上Numpy | 106 | | 第三节课:内存上的ndarray | 一节课,让你看透Numpy | 107 | | 第四节课:Numpy高阶编程 | 一节课,让你玩转Numpy | 108 | | 第五节课:Numpy的IO编程 | 一节课,让你打通Numpy | 109 | | 第六节课:Numpy的函数库 | 一节课,让你爱上Numpy | 110 | | 第七节课:Numpy编程思想 | 一节课,让你用好Numpy | 111 | 112 | --- 113 | 114 | #### 课程学习方法 115 | 116 | | 人群 | 目标 | 需要学习的课程 | 117 | | :---------: | :-----------------------: | :------------: | 118 | | Numpy零基础 | 能把Numpy顺利使用起来 | 第二节课 | 119 | | Numpy初学者 | 想了解Numpy都能干什么 | 第六节课 | 120 | | Numpy初学者 | 想学习Numpy的高级用法 | 第四节课 | 121 | | Numpy经常用 | 想了解Numpy的底层数据架构 | 第三节课 | 122 | | Numpy经常用 | 想用Numpy跟其他语言交互 | 第五节课 | 123 | | Numpy经常用 | 希望真正发挥Numpy的威力 | 第七节课 | 124 | 125 | --- 126 | 127 | #### 个人建议 128 | 129 | - 如果时间来得及,建议从头学到尾 130 | - 认真学完Python核心课的同学们已经反馈说,付出的时间和精力完全没有白费 131 | - 课程上线时间表:预计3月5日以前全部上线,每1-2天更新一集 -------------------------------------------------------------------------------- /Python/Numpy/Python核心编程-Numpy系列(七).md: -------------------------------------------------------------------------------- 1 | ### Python核心编程-Numpy篇-第7节课 2 | 3 | 4 | 5 | #### 本节课的OKR: 6 | 7 | ##### O: 8 | 9 | - 理解矢量化编程(Vectorization) 10 | 11 | 12 | 13 | ##### KR: 14 | 15 | - 写出真正的充分挥发Numpy性能的程序 16 | 17 | 18 | 19 | --- 20 | 21 | 22 | 23 | #### Code Vectorization 24 | 25 | ##### 如何识别哪些任务可以进行Code Vectorization: 26 | 27 | - 整个计算任务由多个相同性质的计算单元构成 28 | - 在每次计算中,所有计算单元上执行的计算具有相同的抽象计算逻辑 29 | 30 | 31 | 32 | ##### 代码层面的矢量化编程要点: 33 | 34 | - 计算单元 35 | - 计算逻辑 36 | - 空间条件 37 | - 时间条件 38 | 39 | 40 | 41 | ##### 先来感受一下 42 | 43 | ``` python 44 | >>> import numpy as np 45 | >>> from random import sample 46 | >>> from timeit import timeit 47 | >>> def add_python(L1, L2): 48 | ... return [x + y for (x, y) in zip(L1, L2)] 49 | ... 50 | >>> def add_numpy(L1, L2): 51 | ... return np.add(L1, L2) 52 | ... 53 | >>> a = sample(range(10000), 1000) 54 | >>> b = sample(range(10000), 1000) 55 | >>> type(a) 56 | 57 | >>> timeit("add_numpy(a, b)", globals=globals(), number=10000) 58 | 1.2160623630002192 59 | >>> timeit("add_python(a, b)", globals=globals(), number=10000) 60 | 0.5947407849998854 61 | ``` 62 | 63 | 64 | 65 | ##### 别慌 66 | 67 | ``` python 68 | >>> def make_ndarray(L1, L2): 69 | ... return np.array(L1), np.array(L2) 70 | ... 71 | >>> arr_a, arr_b = make_ndarray(a, b) 72 | >>> timeit("make_ndarray(a, b)", globals=globals(), number=10000) 73 | 1.1884412310000698 74 | >>> timeit("add_numpy(arr_a, arr_b)", globals=globals(), number=10000) 75 | 0.011329727999964234 76 | ``` 77 | 78 | 79 | 80 | --- 81 | 82 | 83 | 84 | ##### 用Numpy来实现一个简单的MaxPooling层 85 | 86 | 准备工作: 87 | 88 | ``` python 89 | import numpy as np 90 | from timeit import timeit 91 | 92 | def timeit_100(s): 93 | print(timeit(s, globals=globals(), number=100)) 94 | ``` 95 | 96 | 97 | 98 | 迭代处理: 99 | 100 | ``` python 101 | def maxpooling_iteration(x): 102 | y = np.empty((x.shape[-2] // 2, x.shape[-1] // 2), dtype=int) 103 | for i in range(x.shape[-2] // 2): 104 | for j in range(x.shape[-1] // 2): 105 | y[i, j] = np.max([x[2 * i, 2 * j], 106 | x[2 * i + 1, 2 * j], 107 | x[2 * i, 2 * j + 1], 108 | x[2 * i + 1, 2 * j + 1]]) 109 | return y 110 | ``` 111 | 112 | 113 | 114 | 矢量化处理: 115 | 116 | ``` python 117 | def maxpooling_vectorization(x): 118 | x = np.split(x, x.shape[-1] // 2, axis=-1) 119 | x = np.max(x, axis=-1) 120 | x = np.split(x, x.shape[-1] // 2, axis=-1) 121 | x = np.max(x, axis=-1) 122 | return x 123 | ``` 124 | 125 | 126 | 127 | 看一下结果: 128 | 129 | ``` python 130 | if __name__ == "__main__": 131 | x = np.arange(1000000).reshape((1000, 1000)) 132 | timeit_100('maxpooling_iteration(x)') 133 | timeit_100('maxpooling_vectorization(x)') 134 | ``` 135 | 136 | ``` python 137 | 176.918904601 138 | 1.1778114009999854 139 | ``` 140 | 141 | 142 | 143 | --- 144 | 145 | 146 | 147 | #### Problem Vectorization 148 | 149 | 问题:给定两个一维数组$X$、$Y$,对于其所有的索引$i、j$,求$\sum_{i,j} X[i] \times Y[j]$ 150 | 151 | 152 | 153 | ``` py 154 | def sum_xy_double_iteration(x, y): 155 | result = 0 156 | for i in x: 157 | for j in y: 158 | result += i * j 159 | return result 160 | ``` 161 | 162 | 163 | 164 | ``` python 165 | def sum_xy_broadcasting(x, y): 166 | return (x.reshape((1, x.size)) * y.reshape((y.size, 1))).sum() 167 | ``` 168 | 169 | 170 | 171 | ``` python 172 | def sum_xy_single_iteration_1(x, y): 173 | result = 0 174 | y_sum = 0 175 | for j in y: 176 | y_sum += j 177 | for i in x: 178 | result += y_sum * i 179 | return result 180 | ``` 181 | 182 | 183 | 184 | ``` python 185 | def sum_xy_single_iteration_2(x, y): 186 | x_sum = 0 187 | y_sum = 0 188 | for j in y: 189 | y_sum += j 190 | for i in x: 191 | x_sum += i 192 | return x_sum * y_sum 193 | ``` 194 | 195 | 196 | 197 | ``` python 198 | def sum_xy_vectorization(x, y): 199 | return x.sum() * y.sum() 200 | ``` 201 | 202 | 203 | 204 | ``` python 205 | if __name__ == "__main__": 206 | x = np.arange(1000) 207 | y = np.arange(1000, 2000) 208 | timeit_100('sum_xy_double_iteration(x, y)') 209 | timeit_100('sum_xy_broadcasting(x, y)') 210 | timeit_100('sum_xy_single_iteration_1(x, y)') 211 | timeit_100('sum_xy_single_iteration_2(x, y)') 212 | timeit_100('sum_xy_vectorization(x, y)') 213 | ``` 214 | 215 | ``` python 216 | 14.779160522 217 | 0.23248548099999944 218 | 0.02869011499999985 219 | 0.02303162900000011 220 | 0.000639435000000077 221 | ``` 222 | 223 | 224 | 225 | ##### Notes: 226 | 227 | - $$\sum_{i,j} (x_i \times y_j) = \sum_i (x_i \times (\sum_j y_j)) = (\sum_i x_i) \times (\sum_j y_j)$$ 228 | - Problem层面的Vectorization,本质上是基于工具底层的理解,对数学和算法的Vectorization 229 | 230 | 231 | 232 | --- 233 | 234 | 235 | 236 | #### Numpy Vectorization: 237 | 238 | - 先考虑Problem Vectorization,然后,充分Code Vectorization 239 | 240 | - 充分使用Numpy内置函数,能少用一个for算一个 241 | 242 | 243 | 244 | --- 245 | 246 | 247 | 248 | #### 课程结束语: 249 | 250 | - 编程的高手 = 对工具极深的理解 x 解决问题的能力 x 数学与算法的深厚功底 251 | - 高效率学习 = $$ \max \frac{精力}{\frac1{产能} + \frac1{产出}}$$ 252 | - 不要迷失在Numpy,别忘了,还有Pandas,Scipy,scikit-learn 253 | - TensorFlow 2.0 已发布,真正掌握Python与Numpy后,你会发现TensorFlow很简单 254 | 255 | -------------------------------------------------------------------------------- /Python/Numpy/Python核心编程-Numpy系列(三).md: -------------------------------------------------------------------------------- 1 | ### Python核心编程-Numpy篇-第3节课 2 | 3 | 4 | 5 | #### 本节课的目标人群及OKR 6 | 7 | ##### O: 8 | 9 | - 避免由于缺少对ndarray底层的认知而编写bug代码 10 | - 避免由于缺少对ndarray底层的认知而编写低效代码 11 | - 成为Numpy水平前1%的高手 12 | 13 | 14 | 15 | ##### KR: 16 | 17 | - 清楚ndarray是如何从内存上的一维变成程序里的多维的 18 | - 清楚ndarray对象的大致结构 19 | - 清楚ndarray的内存模型的几个重要细节问题 20 | - 深入理解View的本质 21 | 22 | 23 | 24 | --- 25 | 26 | 27 | 28 | #### 课程主要内容 29 | 30 | - 从逻辑层面认识ndarray 31 | - 从代码层面认识ndarray 32 | - 从内存层面认识ndarray 33 | - 重新理解ndarray的View与Copy 34 | - 深入理解Indexing Order 35 | 36 | 37 | 38 | --- 39 | 40 | 41 | 42 | #### ndarray的本质: 43 | 44 | - 内存上一维连续二进制流 45 | - 用于解读二进制流的模型 46 | 47 | 48 | 49 | ``` python 50 | >>> a = np.arange(10) 51 | >>> a.data 52 | 53 | ``` 54 | 55 | 56 | 57 | --- 58 | 59 | 60 | 61 | #### ndarray对象包含的信息: 62 | 63 | - 每个数据元素占用多少字节 64 | - 数据流在内存上的起始位置 65 | - 这个数组是几维的?每个维度的大小? 66 | - 两个元素之间的距离(不一定是元素大小的整数倍) 67 | - 每个数据元素是大端还是小端? 68 | - 引用的内存块是否是只读? 69 | - 每个数据元素如何解读?即数据类型 70 | - 数据是C-order还是Fortran-order 71 | 72 | 73 | 74 | ``` python 75 | >>> b = np.arange(24).reshape((2,3,4)) 76 | >>> b.itemsize 77 | 8 78 | >>> b.data 79 | 80 | >>> b.ndim 81 | 3 82 | >>> b.shape 83 | (2, 3, 4) 84 | >>> b.strides 85 | (96, 32, 8) 86 | >>> b.dtype.byteorder 87 | '=' 88 | >>> b.flags 89 | C_CONTIGUOUS : True 90 | F_CONTIGUOUS : False 91 | OWNDATA : False 92 | WRITEABLE : True 93 | ALIGNED : True 94 | WRITEBACKIFCOPY : False 95 | UPDATEIFCOPY : False 96 | 97 | >>> b.dtype 98 | dtype('int64') 99 | 100 | >>> np.arange(24).flags 101 | C_CONTIGUOUS : True 102 | F_CONTIGUOUS : True 103 | OWNDATA : True 104 | WRITEABLE : True 105 | ALIGNED : True 106 | WRITEBACKIFCOPY : False 107 | UPDATEIFCOPY : False 108 | 109 | >>> np.arange(24).reshape((2,3,4)).flags 110 | C_CONTIGUOUS : True 111 | F_CONTIGUOUS : False 112 | OWNDATA : False 113 | WRITEABLE : True 114 | ALIGNED : True 115 | WRITEBACKIFCOPY : False 116 | UPDATEIFCOPY : False 117 | 118 | >>> np.arange(24).reshape((2,3,4),order='F').flags 119 | C_CONTIGUOUS : False 120 | F_CONTIGUOUS : True 121 | OWNDATA : False 122 | WRITEABLE : True 123 | ALIGNED : True 124 | WRITEBACKIFCOPY : False 125 | UPDATEIFCOPY : False 126 | ``` 127 | 128 | 129 | 130 | 131 | 132 | --- 133 | 134 | 135 | 136 | #### ndarray对象的逻辑组成: 137 | 138 | - block of memory:raw data 139 | - Indexing schema:how to locate an element 140 | - Data Type Descriptor:how to interpret an element 141 | 142 | 143 | 144 | --- 145 | 146 | 147 | 148 | #### ndarray对象的代码组成: 149 | 150 | - dtype对象 151 | - ndim 152 | - shape 153 | - strides 154 | - data指针 155 | 156 | 157 | 158 | --- 159 | 160 | 161 | 162 | #### ndarray对象的内存组成: 163 | 164 | - metadata 165 | - raw data 166 | 167 | 168 | 169 | --- 170 | 171 | 172 | 173 | #### 如何根据ndarray对象解读内存上的二进制流 174 | 175 | 1. 根据data指针找到ndarray解读的二进制流在内存上的位置 176 | 2. 根据strides将二进制流切分成数据块 177 | 3. 根据dtype对象将数据块解读成数据元素(数据类型及大小端) 178 | 179 | 180 | 181 | --- 182 | 183 | 184 | 185 | #### ndarray设计哲学:让绝大多数的多维数组的操作仅需要改变其metadata部分即可 186 | 187 | 188 | 189 | --- 190 | 191 | 192 | 193 | #### 重新理解ndarray的View 194 | 195 | - 指向相同的内存(Buffer or Data) 196 | - 拥有不同的解读(metadata) 197 | 198 | > View算不算是新的ndarray对象? 199 | 200 | 201 | 202 | --- 203 | 204 | 205 | 206 | #### 工程常见问题:什么是大小端? 207 | 208 | ##### 从计算机数据类型与CPU寄存器的长度说起 209 | 210 | - 数据存储的最小单位是:字节(Byte) 211 | - 一个字节是8个二进制位:8bit 212 | - 常见数据类型一般是8bit-64bit不等,也就是1byte-8byte不等 213 | - 常见CPU的寄存器长度有16位,32位不等 214 | - 如果寄存器长度是32位,此时CPU去内存二进制流上框出一个int32数据 215 | - 那么,对于不同的处理器硬件,这32位对应的4个byte的顺序有两种 216 | - 从高到低,从低到高,也就是大小端的区别 217 | 218 | 219 | 220 | ``` python 221 | >>> a = np.arange(4).astype('>i4') 222 | >>> b = a.view('>i2') 223 | >>> c = a.view('>> a 225 | array([0, 1, 2, 3], dtype=int32) 226 | >>> b 227 | array([0, 0, 0, 1, 0, 2, 0, 3], dtype=int16) 228 | >>> c 229 | array([ 0, 0, 0, 256, 0, 512, 0, 768], dtype=int16) 230 | ``` 231 | 232 | 233 | 234 | ##### 弄明白大小端有什么用?凡涉及数据的IO,务必考虑一下大小端问题 235 | 236 | 237 | 238 | ##### ndarray的解决方案 239 | 240 | - 改变内存上的字节序:`array.byteswap()` 241 | - 改变解读内存字节序的方式:`array.newbyteorder()` 242 | 243 | > 思考:两种方式对程序的性能有何影响? 244 | 245 | 246 | 247 | ##### 常见的大小端状况 248 | 249 | - Intel 80x86系列:小端 250 | - ARM:默认小端,可切换到大端 251 | - C语言:默认小端(Keil 51C单片机C语言是大端) 252 | - Java:默认大端 253 | - 网络数据:普遍是大端 254 | 255 | 256 | 257 | --- 258 | 259 | 260 | 261 | #### 工程常见问题:Indexing Order 262 | 263 | ##### Convention by User:(m,n)or(x,y) 264 | 265 | - Matrix-Oriented(由高维到低维)(Numpy里基本遵循此习惯) 266 | - Image-Oriented(由x到y再到z的地理信息表示习惯) 267 | 268 | 269 | 270 | ``` python 271 | >>> np.arange(9).reshape((3,3)) 272 | array([[0, 1, 2], 273 | [3, 4, 5], 274 | [6, 7, 8]]) 275 | ``` 276 | 277 | 278 | 279 | ##### Convention by Language:随着内存上二进制流的移动,不同轴的变动速度是不同的 280 | 281 | - C 282 | - Fortran 283 | 284 | 285 | 286 | ``` python 287 | >>> a = np.arange(9).reshape((3,3),order='C') 288 | >>> b = np.arange(9).reshape((3,3),order='F') 289 | >>> a.ravel() 290 | array([0, 1, 2, 3, 4, 5, 6, 7, 8]) 291 | >>> b.ravel() 292 | array([0, 3, 6, 1, 4, 7, 2, 5, 8]) 293 | ``` 294 | 295 | 296 | 297 | --- 298 | 299 | 300 | 301 | #### 结束语: 302 | 303 | - 本节课需要消耗的认知负担较重,需要多看几遍,多做实验 304 | - 本节课的价值占整个系列课程中的一半以上,吃透本节课内容大有好处 305 | - 相信未来有一天,在面对Numpy的实际问题时,你会因本节课内容,会心一笑 -------------------------------------------------------------------------------- /Python/Python基本语法笔记/1. 预备知识.md: -------------------------------------------------------------------------------- 1 | # Python 学习笔记 ---- 预备知识 2 | 3 | [TOC] 4 | 5 | ## 10个问题 6 | 7 | 1. shell、bash、terminal、console区别 8 | 9 | ​ 简单来说,shell是一个应用程序,用于执行一些系统命令,与linux系统内核交互;bash是shell程序的一种;console是linux+ 外设;terminal = 网络 + shell = 虚拟的console,比如ssh连接。 10 | 11 | 2. 常用的linux命令 12 | 13 | - ls / ll -a 14 | - cd / 15 | - cd ~ 16 | - gedit 文件名 17 | - ./ 18 | 19 | 3. 账户读写权限 20 | 21 | ​ 文件类型 root权限 用户组权限 用户权限 22 | 23 | ​ 1 3 3 3 24 | 25 | 4. Python程序如何执行 26 | 27 | ​ 先编译后解释,跨平台性。 ./py ----> .pyc -------> 执行 -------------------------------------------------------------------------------- /Python/Python基本语法笔记/10. OOP in Python.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/10. OOP in Python.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/14. 迭代器协议.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/14. 迭代器协议.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/2. Python基础语法.md: -------------------------------------------------------------------------------- 1 | 第三节 Python基础语法 2 | 3 | 1. 谈谈变量与对象的关系,以及变量在内存中的情况。 4 | 5 |   Python中,定义变量必须由对象赋值,对象类型决定变量类型。从本质上来说,对象是存储数据的实体,而变量是指向对象的指针。举例来说,你的名字和本人就是变量与对象的关系,本人为实体,即对象,而名字只是指向你的一个指针,即变量。(挺别扭=_=) 6 | 7 |   变量无类型,对象有类型。变量类型由对象类型所决定。 8 | 9 | 2. Python基础的数据类型有哪些?基础的数据结构有哪些?谈谈你对5种基本的数据结构理解(性质,用途,用法)。 10 | 11 |   基础数据类型:整型,浮点型,布尔型,字符串,NULL 12 | 13 |   基础数据结构:list, tuple, dict, set, str 14 | 15 |   list: 16 | 17 |   (1)性质:可变有序集合 18 | 19 |   (2)用途:随机存取 20 | 21 |   (3)用法:切片,索引 22 | 23 |         append(), pop(), + , *, list[0], list[-1] 24 | 25 |   tuple: 26 | 27 |   (1)性质:不可修改的list 28 | 29 |   (2)用途:一般用于返回多个返回值 30 | 31 |   (3)用法:() 32 | 33 |   dict: 34 | 35 |   (1)性质:使用hash结构,查找速度快 36 | 37 |   (2)用途:键值对,快速存取 38 | 39 |   (3)用法: 40 | 41 |        增:d['*key_not_int_dict*'] = ** 42 | 43 |        删:d.pop('*key_in_dict*') 44 | 45 |        改:d['*key_in_dict*'] = ** 46 | 47 |        查:'any_key' in d 或者 d.get('key') 48 | 49 |   set: 50 | 51 |   (1)性质:无序,**不可变**,无重复(dict中的key) 52 | 53 |   (2)用途:用于无序数据 54 | 55 |   (3)用法:s.add() , s.remove() 56 | 57 | 58 | 59 | 3. 说下引用与拷贝的使用。 60 | 61 | 62 | 63 |   变量是对象的名称,引用则为对象的别名(小名),改变引用即改变对象。 64 | 65 |   以list为例: 66 | 67 | ```python 68 | >>> a = [1, 2, 3] 69 | >>> b = a 70 | >>> id(a) == id(b) 71 | True 72 | >>> b.append(9) 73 | >>> a 74 | [1, 2, 3, 9] 75 | ``` 76 | 77 | 78 | 79 | ```python 80 | >>> a = [1, 2, 3] 81 | >>> b = a[:] 82 | >>> id(a) == id(b) 83 | False 84 | >>> b.append(9) 85 | >>> a 86 | [1, 2, 3] 87 | ``` 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /Python/Python基本语法笔记/2. Python基础语法_question.md: -------------------------------------------------------------------------------- 1 | 第三节 Python基础语法 2 | 3 | 1. 谈谈变量与对象的关系,以及变量在内存中的情况。 4 | 5 | 2. Python基础的数据类型有哪些?基础的数据结构有哪些?谈谈你对5种基本的数据结构理解(性质,用途,用法)。 6 | 7 | 3. 说下引用与拷贝的使用。 8 | 9 | -------------------------------------------------------------------------------- /Python/Python基本语法笔记/3. Python快速面面观(上).xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/3. Python快速面面观(上).xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/4. Python快速面面观(下).xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/4. Python快速面面观(下).xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/5. 玩转Python中的List.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/5. 玩转Python中的List.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/6. Python 中的函数与函数式编程.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/6. Python 中的函数与函数式编程.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/8. 闭包.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/8. 闭包.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/9. 装饰器.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/9. 装饰器.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/函数库.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/Python/Python基本语法笔记/函数库.xmind -------------------------------------------------------------------------------- /Python/Python基本语法笔记/第三节 Python基础语法.md: -------------------------------------------------------------------------------- 1 | 第三节 Python基础语法 2 | 3 | 1. 谈谈变量与对象的关系,以及变量在内存中的情况。 4 | 5 |   Python中,定义变量必须由对象赋值,对象类型决定变量类型。从本质上来说,对象是存储数据的实体,而变量是指向对象的指针。举例来说,你的名字和本人就是变量与对象的关系,本人为实体,即对象,而名字只是指向你的一个指针,即变量。(挺别扭=_=) 6 | 7 |   变量无类型,对象有类型。变量类型由对象类型所决定。 8 | 9 | 2. Python基础的数据类型有哪些?基础的数据结构有哪些?谈谈你对5种基本的数据结构理解(性质,用途,用法)。 10 | 11 |   基础数据类型:整型,浮点型,布尔型,字符串,NULL 12 | 13 |   基础数据结构:list, tuple, dict, set, str 14 | 15 |   list: 16 | 17 |   (1)性质:可变有序集合 18 | 19 |   (2)用途:随机存取 20 | 21 |   (3)用法:切片,索引 22 | 23 |         append(), pop(), + , *, list[0], list[-1] 24 | 25 |   tuple: 26 | 27 |   (1)性质:不可修改的list 28 | 29 |   (2)用途:一般用于返回多个返回值 30 | 31 |   (3)用法:() 32 | 33 |   dict: 34 | 35 |   (1)性质:使用hash结构,查找速度快 36 | 37 |   (2)用途:键值对,快速存取 38 | 39 |   (3)用法: 40 | 41 |        增:d['*key_not_int_dict*'] = ** 42 | 43 |        删:d.pop('*key_in_dict*') 44 | 45 |        改:d['*key_in_dict*'] = ** 46 | 47 |        查:'any_key' in d 或者 d.get('key') 48 | 49 |   set: 50 | 51 |   (1)性质:无序,**不可变**,无重复(dict中的key) 52 | 53 |   (2)用途:用于无序数据 54 | 55 |   (3)用法:s.add() , s.remove() 56 | 57 | 58 | 59 | 3. 说下引用与拷贝的使用。 60 | 61 | 62 | 63 |   变量是对象的名称,引用则为对象的别名(小名),改变引用即改变对象。 64 | 65 |   以list为例: 66 | 67 | ```python 68 | >>> a = [1, 2, 3] 69 | >>> b = a 70 | >>> id(a) == id(b) 71 | True 72 | >>> b.append(9) 73 | >>> a 74 | [1, 2, 3, 9] 75 | ``` 76 | 77 | 78 | 79 | ```python 80 | >>> a = [1, 2, 3] 81 | >>> b = a[:] 82 | >>> id(a) == id(b) 83 | False 84 | >>> b.append(9) 85 | >>> a 86 | [1, 2, 3] 87 | ``` 88 | 89 | 90 | 91 | #### 小结 92 | 93 | ![小结](C:\Users\dream\Desktop\Python快速面面观.png) 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /images/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/images/wechat.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/SQL学习笔记1-SQL语句.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列1 SQL是如何执行的 2 | 3 | ## 1 SQL执行流程 4 | 5 | ### 1.1 Oracle 中 SQL执行过程 6 | 7 | image-20200915223249514 8 | 9 | 10 | 11 | ### 1.2 MySQL中的SQL执行过程 12 | 13 | image-20200915223618036 14 | 15 | MySQL是典型C/S 架构,服务端程序为mysqld。其中SQL层与数据库文件的存储方式无关,SQL层结构: 16 | 17 | image-20200915224105762 18 | 19 | SQL语句在MySQL执行流程:SQL语句 -> 缓存查询 -> 解析器 -> 优化器 -> 执行器 20 | 21 |
22 | 23 | img 24 | 25 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/SQL必知必会(13) 索引.md: -------------------------------------------------------------------------------- 1 | # SQL必知必会(13) 索引 2 | 3 | ## 13.1 索引的种类 4 | 5 | 从功能逻辑上分: 6 | 7 | - 普通索引:无约束,用于提高查询效率 8 | - 唯一索引:普通索引的基础上增加数据唯一性的约束,表中可以有多个唯一索引。 9 | - 主键索引:在唯一索引的基础上,增加不为空的约束,即NOT NULL+UNIQUE 10 | - 全文索引:MySQL自带的索引只支持英文 11 | 12 | 从物理实现方式分: 13 | 14 | - 聚集索引:按照主键对数据排序存储,索引指向的内容聚集在索引后面 15 | - 非聚集索引(二级索引 / 辅助索引):只为护索引,不为护索引指向的数据 16 | 17 | 区别: 18 | 19 | 1. 聚集索引叶子结点存储数据记录,非聚集索引叶子结点存储数据位置。非聚集索引不会影响数据表的物理存储顺序。 20 | 2. 一个表只有一个聚集索引,可以有多个非聚集索引,多个索引目录提供数据检索 21 | 3. 聚集索引数据查询效率高,但对数据插入,删除,更新操作,效率比非聚集索引低。 22 | 23 | 小结 24 | 25 | image-20201013214901671 26 | 27 |
28 | 29 | ## 13.2 B+树索引 30 | 31 | ### 13.2.1 B树 32 | 33 | 二叉树的搜索效率为O(logn), 但在某些情况,二叉树会退化为链表。所以提出平衡二叉搜索树,即树中节点的左右子树的高度相差要小于等于1。但对于数据量巨大情况,二叉树的深度logn也会很大,也就是会有logn次的磁盘I/O操作,这种时间消耗是巨大的。 34 | 35 | 所以,使用二叉树作为索引结构使得树变得很高,增加了硬盘I/O次数,影响查询时间。B树可以有效解决这个问题,B树又叫平衡的多路搜索树,它的高度远小于平衡二叉树的高度。在文件系统和数据库系统中的索引结构常用B树实现。 36 | 37 | 38 | 39 | 40 | 41 | ## 13.3 Hash 索引 42 | 43 | ### 13.3.1 Hash检索效率 44 | 45 | Hash本身是一个散列函数,可以大幅提升检索效率。算法复杂度为O(1) 46 | 47 | ### 13.3.2 Hash索引的优点和不足 48 | 49 | 优点:使用Hash检索效率非常高,通常一次检索即可找到数据,而B+树则需要自顶向下查找,多次访问节点才能找到数据,需要进行多次I/O操作,效率上来说,Hash比B+树更快。 50 | 51 | 不足:Hash冲突。如果桶的空间小于输入的空间,不同的输入可能会映射到同一个桶中,这时会产生Hash冲突,如果Hash冲突量很大,则会影响读取的性能。 52 | 53 | ### 13.3.3 Hash索引和B+树索引区别及使用场景 54 | 55 | 1. Hash索引不能进行范围查询,而B+树可以。 56 | 57 | 2. Hash索引不支持联合索引的最左侧原则,即联合索引的部分索引无法使用,而B+树可以。 58 | 3. Hash索引不支持ORDER BY排序,Hash索引指向的数据是无序的,因此无法排序优化,而B+树索引数据是有序的。 59 | 60 | 等值查询,Hash索引效率更高,不过对于索引列重复值过多,效率会降低。 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200915223249514.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200915223249514.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200915223618036.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200915223618036.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200915224105762.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200915224105762.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200915225428293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200915225428293.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200924143802668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200924143802668.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200924144457031.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200924144457031.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20200927150049618.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20200927150049618.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20201005162519814.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20201005162519814.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/images/image-20201013214901671.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据库/SQL必知必会/images/image-20201013214901671.png -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(1)SQL语句.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(2)SQL语句 2 | 3 | ## 1 数据库定义 4 | 5 | ```sql 6 | CREATE DATABASE nba; 7 | DROP DATABASE nba; 8 | ``` 9 | 10 | ## 2 数据表定义 11 | 12 | ### 2.1 创建表 13 | 14 | ```sql 15 | CREATE TABLE [table_name] (字段名 数据类型, ...) 16 | ``` 17 | 18 | 示例 19 | 20 | - 创建语句建表 21 | 22 | ```sql 23 | CREATE TABLE player ( 24 | player_id int(11) NOT NULL AUTO_INCREMENT, 25 | player_name varchar(255) NOT NULL 26 | ) 27 | ``` 28 | 29 | - 使用 `navicat` 软件进行建表,并导出建表语句 30 | 31 | image-20200915225428293 32 | 33 | ```sql 34 | DROP TABLE IF EXISTS `player`; 35 | CREATE TABLE `player` ( 36 | `player_id` int(11) NOT NULL AUTO_INCREMENT, 37 | `team_id` int(11) NOT NULL, 38 | `player_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 39 | `height` float(3, 2) NULL DEFAULT 0.00, 40 | PRIMARY KEY (`player_id`) USING BTREE, 41 | UNIQUE INDEX `player_name`(`player_name`) USING BTREE 42 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 43 | ``` 44 | 45 | 其中,`utf8-general_ci` 表示排序规则为大小写不敏感 46 | 47 | ### 2.2 修改表结构 48 | 49 | 1. 添加字段 50 | 51 | ```sql 52 | ALTER TABLE player ADD(age int(11)); 53 | ``` 54 | 55 | 2. 修改字段名 56 | 57 | ```sql 58 | ALTER TABLE player RENAME COLUMN age to player_age; 59 | ``` 60 | 61 | 3. 修改字段类型 62 | 63 | ```sql 64 | ALTER TABLE player MODIFY (player_age float(3, 1)); 65 | ``` 66 | 67 | 4. 删除字段 68 | 69 | ```sql 70 | ALTER TABLE player DROP COLUMN player_age; 71 | ``` 72 | 73 | ### 2.3 常见约束 74 | 75 | 1. 主键约束 76 | 1. UNIQUE + NOT NULL 77 | 2. 可以是一个字段,也可是多个字段复合 78 | 2. 外键约束 79 | 1. 可以重复,可以为空 80 | 2. 外键确保表与表之间的完整性 81 | 3. 唯一性约束 82 | 1. 表明任何两个数据不能相同 83 | 4. NOT NULL 84 | 1. 字段不应为空,必须有取值 85 | 5. DEFAULT 86 | 1. 字段默认值 87 | 6. CHECK 88 | 1. 字段取值范围的有效性 89 | 90 | ### 2.3 设计表的原则 91 | 92 | 1. 数据表个数越少越好:实体与联系越简洁 93 | 2. 数据表中字段越少越好:字段相互独立 94 | 3. 数据表中联合主键字段越少越好:减少索引空间 95 | 4. 使用主键和外键越多越好:冗余度低,利用度高 96 | 97 | 98 | 99 | img 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(10) 游标.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(10) 游标 2 | 3 | ## 10.1 什么是游标 4 | 5 | 游标提供一种灵活的操作方式,使得SQL有面向过程开发的能力。其相当于C语言中的指针,可以指向存储在数据库表中的数据行指针。 6 | 7 | ## 10.2 如何使用游标 8 | 9 | 1. 定义游标 10 | 11 | ```sql 12 | DECLARE cursor_name CURSOR FOR select_statement; 13 | ``` 14 | 15 | 2. 打开游标 16 | 17 | ```sql 18 | OPEN cursor_name; 19 | ``` 20 | 21 | 3. 从游标中获取数据 22 | 23 | ```sql 24 | FETCH cursor_name INTO var_name ...; 25 | ``` 26 | 27 | 4. 关闭游标 28 | 29 | ```sql 30 | CLOSE cursor_name; 31 | ``` 32 | 33 | 5. 释放游标 34 | 35 | ```sql 36 | DEALLOCATE cursor_namec; 37 | ``` 38 | 39 | 40 | 41 | ## 10.3 小结 42 | 43 | img 44 | 45 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(11) 当我们在谈论数据库调优时,我们在谈论什么?.md: -------------------------------------------------------------------------------- 1 | ## 搞定SQL系列(11) 当我们在谈论数据库调优时,我们在谈论什么? 2 | 3 | ## 11. 1 调优的目标 4 | 5 | 数据库调优的目标是让数据能更好更快的查询,使得其响应时间更快,吞吐量更大。不过随着用户数量的增加,并发数量提高,或者在不同时间段,数据库的访问急剧增加,如双十一或者节假日活动期间。所以,首先需要更好的定位问题,确定目标,才能更好的调优。 6 | 7 | 可以通过以下几个方面进行确定: 8 | 9 | 1. 用户反馈 10 | 2. 日志分析 11 | 3. 服务器资源使用监控,如服务器CPU、内存、I/O等使用情况,实时了解服务器性能 12 | 4. 服务器内部状况监控,数据库监控的活动会话监控是一个重要指标。 13 | 14 | 通过以上分析,确定问题所在,针对该问题进行优化。 15 | 16 | ## 11.2 从哪些方面着手 17 | 18 | 略 19 | 20 | ## 11.3 如何思考和分析数据调优 21 | 22 | 略 23 | 24 | ## 小结 25 | 26 | img 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(12) 数据表的范式,你知道么.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(12) 数据表的范式,你知道么 2 | 3 | ## 12.1 数据库的设计范式 4 | 5 | 范式:在设计数据库模型的时候,对关系内部各个属性之间的联系的合理化程度进行定义,使得其有不同等级的规范要求,称为范式。 6 | 7 | 关系型数据库有6种范式:1NF、2NF、3NF、BCNF(巴斯-科德范式)、4NF和5NF(完美范式)。数据库范式越高,其冗余度越低。 8 | 9 |
10 | 11 | ## 12.2 数据表的键 12 | 13 | 为更清晰的表达下列各键的含义,示例:NBA球员表和球队表。球员包含球员编号、姓名、身份证号、年龄和球队编号。球队包含球队编号、主教练和球队所在地。 14 | 15 | - 超键:唯一标识元祖的属性集 16 | - (球员编号, 姓名) 17 | - (身份证号,姓名) 18 | - 候选键:不包含多余属性的超键,即唯一标识元组的属性 19 | - (球员编号) 20 | - (身份证号) 21 | - 主键:用户可以从候选键中选取一个作为主键 22 | - (球员编号) 23 | - (身份证号) 24 | - 外键:其他数据表中的主键 25 | - (球队编号) 26 | - 主属性:包含任一候选键中的属性 27 | - (球员编号) 28 | - (身份证号) 29 | - 非主属性:不包含任一候选键中的属性 30 | - (姓名) 31 | - (年龄) 32 | 33 |
34 | 35 | ## 12.3 1NF、2NF、3NF 36 | 37 | 1NF:指数据库表中的任何属性都是原子的,不可再分。即对于字段X,不可分为X-1和字段X-2. 38 | 39 | 2NF:指数据表中的非主属性都和所有候选键有**完全依赖**关系,即在1NF基础上,消除对非主属性对键的部分依赖。 40 | 41 | 示例 - 不满足2NF:player_game表中有球员编号、姓名、年龄、比赛编号、比赛时间和比赛场地。可以通过候选键决定如下关系: 42 | 43 | (球员编号, 比赛编号) ---> (姓名,年龄,比赛时间,比赛场地,得分) 44 | 45 | 因为对于非主属性,还满足(部分依赖): 46 | 47 | (球员编号) ---> (姓名,年龄) 48 | 49 | (比赛编号) ---> (比赛时间,比赛场地) 50 | 51 | 将该表分为三张表:player(球员编号,姓名,年龄),game( 比赛编号,比赛时间,比赛场地),player_game(球员编号,比赛编号,得分) 52 | 53 | 3NF:在满足2NF同时,对任何非主属性都**不传递依赖**于候选键,即在2NF基础上,消除非主属性对键的传递依赖。即不能存在非主属性A依赖于非主属性B,非主属性B依赖于候选键。 54 | 55 | img 56 | 57 | 示例- 满足3NF:球员表属性包括球员编号、姓名和球队名称;球队表属性包括球队名称、球队主教练。 58 | 59 | ## 小结 60 | 61 | ![img](https://static001.geekbang.org/resource/image/e7/11/e775113e733020a7810196afd4f58711.jpg) -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(2)检索数据.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(2) 检索数据 2 | 3 | ## 2.1 SELECT查询的基本语法 4 | 5 | SQL文件:[Github地址](https://github.com/cystanford/sql_heros_data) 6 | 7 | 1. 查询列 8 | 9 | 1. 单个列 10 | 11 | ```sql 12 | SELECT name FROM heros; 13 | ``` 14 | 15 | ​ b. 多个列 16 | 17 | ```sql 18 | SELECT name, hp_max, attack_max, defense_max FROM heros; 19 | ``` 20 | 21 | ​ c. 所有列 22 | 23 | ```sql 24 | SELECT * FROM heros; 25 | ``` 26 | 27 | > 生产环境中避免使用 `SELECT *` 28 | 29 | 2. 起别名(多表查询,简化名称) 30 | 31 | ```sql 32 | SELECT name AS n, hp_max AS hm, mp_max AS mm, attack_max AS am, defense_max AS dm FROM heros; 33 | ``` 34 | 35 | 3. 查询常数:在查询时增加常数列 36 | 37 | ```sql 38 | SELECT '王者荣耀' as platform, name FROM heros; 39 | ``` 40 | 41 | - 如果是字符串,必须使用 单引号 42 | 43 | 4. 去除重复行 44 | 45 | ```sql 46 | SELECT DISTINCT attack_range FROM heros; 47 | SELECT DISTINCT attack_range , name FROM heros; 48 | ``` 49 | 50 | - DISTINCT 放在所有列名之前 51 | - DISTINCT对后面的列名组合去重,所以第二条sql会列出所有的数据,因为英雄名称不同。 52 | 53 |
54 | 55 | ## 2.2 排序检索 56 | 57 | ORDER BY 子句: 58 | 59 | - 排序列名:如果ORDER BY 后有一个或多个列名,会先按照第一个进行排序,再依次对后面的列排序 60 | - 排序顺序 61 | - ASC:递增排序(默认) 62 | - DESC:递减排序 63 | - 非选择列排序:可以使用非选择列进行排序 64 | - ORDER BY位置:通常在SELECT语句的最后一条子句 65 | 66 | 示例1:显示英雄名称和最大生命值,按照最大生命值从高到低排序 67 | 68 | ```sql 69 | SELECT name, hp_max FROM heros ORDER BY hp_max DESC; 70 | ``` 71 | 72 | 示例2: 显示英雄名称及最大生命值,按照第一排序最大法力从低到高,当最大法力相等时按照第二排序进行,即最大生命值从高到低 73 | 74 | ```sql 75 | SELECT name, max_hp FROM hero ORDER BY mp_max, hp_max DESC 76 | ``` 77 | 78 | 约束返回结果的数量:LIMIT 79 | 80 | 示例1: 返回英雄名称及最大生命值,按照最大生命值从高到低排序,返回5条记录 81 | 82 | ```sql 83 | SELECT name, hp_max FROM heros ORDER BY hp_max DESC LIMIT 5; 84 | ``` 85 | 86 | #### SELECT 执行顺序 87 | 88 | 1. 关键字顺序 89 | 90 | ```sql 91 | SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY... 92 | ``` 93 | 94 | 2. SELECT语句执行顺序 95 | 96 | ```sql 97 | FROM > WHERE > GROUP BY > HAVING > SELECT字段 > DISTINCT > ORDER BY > LIMIT 98 | ``` 99 | 100 | 示例1 : 101 | 102 | ```sql 103 | SELECT DISTINCT player_id, player_name, count(*) as num #顺序5 104 | FROM player JOIN team ON player.team_id = team.team_id #顺序1 105 | WHERE height > 1.80 #顺序2 106 | GROUP BY player.team_id #顺序3 107 | HAVING num > 2 #顺序4 108 | ORDER BY num DESC #顺序6 109 | LIMIT 2 #顺序7 110 | ``` 111 | 112 | - 步骤1:通过CROSS JOIN 求笛卡尔积,得到虚拟表vt 1-1 113 | - 步骤2: 通过ON 筛选,在vt1-1 基础上筛选得到 vt1-2 114 | - 步骤3: 添加外部行,如果使用左连接/右连接/全连接,增加外部行,得到vt 1-3 115 | - 步骤4: WHERE,筛选v1 得到v2 116 | - 步骤5: GROUP 和 HAVING 得到 vt3 和 vt4 117 | - 步骤6: SELECT 和 DISTINCT得到 vt5-1 和vt5-2 118 | - 步骤7: ORDER BY得到vt 6 119 | - 步骤8: LIMIT 得到 vt7 120 | 121 |
122 | 123 | ## 2.3 何时使用`SELECT*` ,如何提升 SELECT 查询效率 124 | 125 | 指定列名,减少数据表查询的网络传输量。提高效率 126 | 127 | 1. 避免使用 SELECT * 128 | 2. 约束返回结果的数量 129 | 130 |
131 | 132 | 小结: 133 | 134 | img 135 | 136 | 提高查询效率的方式 137 | 138 | - 约束返回结果的数量 139 | - 指定筛选条件,进行过滤。 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(3) 数据过滤.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(3) 数据过滤 2 | 3 |    4 | 5 | ## 3.1 比较运算符 6 | 7 | 表3-1 比较运算符及其含义 8 | 9 | image-20200924143802668 10 | 11 | Where 子句的基本格式 12 | 13 | ```sql 14 | SELECT ...(列名) FROM ...(表名) WHERE ...(子句条件) 15 | ``` 16 | 17 | 示例1:查询所有最大生命值大于6000的英雄 18 | 19 | ```sql 20 | SELECT name, hp_max FROM heros where max_hp > 6000; 21 | ``` 22 | 23 | 示例2:查询所有最大生命值在5399到6811之间的英雄 24 | 25 | ```sql 26 | SELECT name, hp_max FROM heros WHERE hp_max BETWEEN 5399 AND 6811; 27 | ``` 28 | 29 | 示例3:对heros表中的hp_max 字段进行空值查询 30 | 31 | ```sql 32 | SELECT name, hp_max FROM heros WHERE hp_max IS NULL; 33 | ``` 34 | 35 |
36 | 37 | ## 3.2 逻辑运算符 38 | 39 | 表3-2 逻辑运算符及其含义 40 | 41 | image-20200924144457031 42 | 43 | 示例1:筛选最大生命值大于6000,最大法力大于1700,按照最大生命值和最大法力值之和从高到低进行排序。 44 | 45 | ```sql 46 | SELECT name, hp_max, mp_max FROM heros WHERE hp_max > 6000 AND mp_max > 1700 ORDER BY (hp_max+mp_max) DESC; 47 | ``` 48 | 49 | 示例2:查询最大生命值加最大法力值大于8000的英雄,或者最大生命值大于6000并且最大法力值大于1700的英雄。 50 | 51 | ```sql 52 | SELECT name, hp_max, mp_max FROM heros 53 | WHERE (hp_max+mp_max)>8000 OR hp_max>6000 AND mp_max > 1700 ORDER BY (hp_max+mp_max) DESC; 54 | ``` 55 | 56 | **AND 优先级比 OR优先级更高** ,所以SQL会优先处理AND运算符,再处理OR运算符。 57 | 58 | 示例3:查询主要定位和次要定位是法师或射手的英雄,上线时间不在2016-01-01和2017-01-01之间。 59 | 60 | ```sql 61 | SELECT name, role_main, role_assist, hp_max, mp_max, birthdate 62 | FROM heros 63 | WHERE (role_main IN ('法师', '射手') OR role_assist IN ('法师', '射手') AND DATE(birthday) NOT BETWEEN '2016-01-01' AND '2017-01-01') 64 | ORDER BY (hp_max + mp_max) DESC 65 | ``` 66 | 67 |
68 | 69 | ## 3.3 通配符 70 | 71 | 通配符用于匹配值的一部分的特殊字符,使用`LIKE` 操作符。 72 | 73 | - 匹配任意字符出现的任意次数,使用 `%` 通配符。 74 | - ` - ` :代表一个字符 75 | 76 | 示例1:查询英雄名中包含“太”字的英雄 77 | 78 | ```sql 79 | SELECT name FROM heros WHERE name LIKE'%太%'; 80 | ``` 81 | 82 | 示例2:查询英雄名除了第一个字以外,包含‘太’字的英雄 83 | 84 | ```sql 85 | SELECT name FROM heros WHERE name LIKE '_%太%'; 86 | ``` 87 | 88 |
89 | 90 | ## 小结 91 | 92 | SQL语句保持高效率,要避免全局扫描,考虑在ORDER BY 和 WHERE 涉及的列上增加索引。 93 | 94 | img 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(4) 聚集函数.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(4) 聚集函数 2 | 3 | ## 4.1 聚集函数 4 | 5 | SQL中聚集函数由5个: 6 | 7 | image-20200927150049618 8 | 9 |
10 | 11 | 示例1 - COUNT() :查询最大生命值大于6000的英雄数量 12 | 13 | ```sql 14 | SELECT COUNT(*) FROM heros WHERE hp_max > 6000; 15 | ``` 16 | 17 | 示例2 - MAX():查询射手(主要定位或者次要定位是射手)的最大生命值的最大值是多少? 18 | 19 | ```sql 20 | SELECT MAX(hp_max) FROM heros WHERE role_main = '射手' OR role_assist = '射手'; 21 | ``` 22 | 23 | 示例3 - 聚集函数:查询射手(主要定位或者次要定位是射手)的英雄数、平均最大生命值、法力最大值的最大值、攻击最大值的最小值、以及这些英雄总的防御最大值等的汇总数据 24 | 25 | ```sql 26 | SELECT COUNT(*), AVG(hp_max), MAX(mp_max), MIN(attack_max), SUM(defense_max) FROM heros WHERE role_main = '射手' OR role_assist = '射手'; 27 | ``` 28 | 29 | 注:AVG、MAX、MIN等聚集函数会自动忽略值为NULL的数据行。 30 | 31 | 32 | 33 | 示例4 - 汉字排序:汉子按照全拼拼音进行排列 34 | 35 | ```sql 36 | SELECT MIN(CONVERT(name USING gbk)), MAX(CONVERT(name USING gbk)) FROM heros; 37 | ``` 38 | 39 |
40 | 41 | 示例5 - 分组聚集统计:统计不同生命最大值英雄的平均生命最大值,保留小数点后两位。 42 | 43 | ```sql 44 | SELECT ROUND((AVG(DISTINCT hp_max), 2) FROM heros; 45 | ``` 46 | 47 |
48 | 49 | ## 4.2 数据分组,聚集统计 50 | 51 | 对数据分组,使用 group by 子句。 52 | 53 | 示例6 - GROUP BY分组:按英雄的主要定位分组,统计每组的英雄数量。 54 | 55 | ```sql 56 | SELECT COUNT(*), role_main FROM heros GROUP BY role_main; 57 | ``` 58 | 59 | 示例7 - 多个字段分组:按照英雄的主要定位、次要定位分组,查看英雄的数量,按照从高到低进行排序 60 | 61 | ```sql 62 | SELECT COUNT(*) AS num, role_main, role_assist FROM heros GROUP BY role_main, role_assist ORDER BY num DESC; 63 | ``` 64 | 65 |
66 | 67 | ## 4.3 Having与Where 68 | 69 | Having 与 Where 都用于过滤数据,但WHERE 用于数据行,HAVING用于分组。 70 | 71 | 示例8 - HAVING :按照英雄的主要定位、次要定位分组,筛选英雄的数量大于5的组,按照从高到低进行排序 72 | 73 | ```sql 74 | SELECT COUNT(*) AS num, role_main, role_assist FROM heros GROUP BY role_main, role_assist HAVING num > 5 ORDER BY num DESC; 75 | ``` 76 | 77 | 示例9 - HAVING 与 WHERE 区别:筛选最大生命值大于6000的英雄,按照主要定位、次要定位进行分组,显示分组中英雄数量大于5的分组,数量从高到低进行排序。 78 | 79 | ```sql 80 | SELECT COUNT(*) as num, role_main, role_assist FROM heros WHERE hp_max > 6000 GROUP BY role_main, role_assist HAVING num > 5 ORDER BY num DESC; 81 | ``` 82 | 83 |
84 | 85 | ## 小结 86 | 87 | 1. SQL 语句 88 | 89 | WHERE - 数据行过滤 90 | 91 | GROUP BY - 数据分组 92 | 93 | HAVING - 分组过滤 94 | 95 | ORDER BY - 按照字段排序输出 96 | 97 | ```sql 98 | SELECT ... FROM .. WHERE... GROUP BY ... HAVING ... ORDER BY... 99 | ``` 100 | 101 | 2. 聚集函数及分组 102 | 103 | img 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(5) 子查询.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(5) 子查询 2 | 3 | ## 5.1 子查询分类 4 | 5 | 子查询是一种嵌套的查询方式,可以根据子查询是否执行多次,分为关联子查询和非关联子查询。 6 | 7 | - 关联子查询:子查询从数据表中查询了数据结果,数据结果仅执行一次,作为主查询条件进行执行 8 | - 非关联子查询:子查询需要执行多次,即循环的方式,从外部查询开始,每次传入子查询进行查询,再将结果反馈至外部。 9 | 10 | 示例1 - 非关联子查询:查询最高的球员身高为多少 11 | 12 | ```sql 13 | SELECT player_name, height FROM player WHERE height = (SELECT MAX(height) FROM player); 14 | ``` 15 | 16 | 示例2 - 关联子查询:查询每个球队中大于平均身高的球员,显示球员姓名、身高、以及所在球队ID 17 | 18 | ```sql 19 | SELECT player_name, height, team_id FROM player AS a WHERE height > (SELECT AVG(height) FROM player AS b WHERE a.team_id = b.team_id); 20 | ``` 21 | 22 |
23 | 24 | ## 5.2 子查询关键字 25 | 26 | EXITS 子查询用于判断条件是否满足。 27 | 28 | 示例3 - EXIT子查询:查询出过场的球员,并且显示他们的姓名,球员ID和球队ID 29 | 30 | ```sql 31 | SELECT player_id, team_id, name FROM player WHERE EXITS (SECLECT player_id FROM play_score WHERE player.player_id = player_score.player_id); 32 | ``` 33 | 34 |
35 | 36 | IN、ANY、ALL、SOME 集合比较子查询 37 | 38 | image-20200927165028536 39 | 40 | 示例4 - IN子查询:查询出过场的球员有哪些 41 | 42 | ```sql 43 | SELECT player_id, team_id, player_name 44 | FROM player 45 | WHERE player_id IN ( 46 | SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id); 47 | ``` 48 | 49 |
50 | 51 | IN 与EXISTS 模式 52 | 53 | IN 使用 表B 的索引 54 | 55 | ```sql 56 | SELECT * FROM A WHERE cc IN (SELECT CC FROM B); 57 | ``` 58 | 59 | EXISTS使用 表A的索引 60 | 61 | ```sql 62 | SELECT * FRMO A WHERE EXIST (SELECT CC FROM B WHERE B.cc = A.CC) 63 | ``` 64 | 65 | 效率比较:在cc列建立索引情况下,需要比较表A和表B的大小。 66 | 67 | - 如果表A比表B大,那么IN子查询效率比EXIST子查询效率高,因为表B如果对cc列进行了索引,所以IN子查询的效率高。 68 | - 如果表A比表B小,使用EXIST子查询效率更高,因为可以使用到A表中对cc列的索引,而不用从B中进行cc列的查询 69 | 70 | > 索引是个前提,其实和选择与否 还是要看表的大小。选择的标准,你可以理解为: 小表驱动大表。这种方式下效率是最高的。比如 71 | > SELECT * FROM A WHERE cc IN (SELECT cc FROM B) 72 | > SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc) 73 | > 当A小于B时,用EXIST。因为EXIST的实现,相当于外表循环,实现的逻辑类似于: 74 | > for i in A 75 | > for j in B 76 | > if j.cc == i.cc then ... 77 | > 78 | > 当B小于A时,用IN,因为实现的逻辑类似于: 79 | > for i in B 80 | > for j in A 81 | > if j.cc == i.cc then ... 82 | > 所以哪个表小就用哪个表来驱动,A表小 就用EXIST,B表小 就用IN 83 | 84 | 示例5 - ANY 子查询:查询球员表中,比印第安步行者(team_id = 1002) 中任意一个球员的身高高的球员信息,输出球员ID、姓名和身高。 85 | 86 | ```sql 87 | SELECT player_id, player_name, height FROM player WHERE height > ANY(SELECT height FROM player WHERE team_id = 1002); 88 | ``` 89 | 90 | 示例6 - ALL子查询 91 | 92 | 查询球员表中,比印第安步行者(team_id = 1002) 中所有球员的身高高的球员信息,输出球员ID、姓名和身高。 93 | 94 | ```sql 95 | SELECT player_id, player_name, height FROM player WHERE height > ALL(SELECT height FROM player WHERE team_id = 1002); 96 | ``` 97 | 98 |
99 | 100 | ## 5.3 使用子查询作为计算字段 101 | 102 | 示例7 - 子查询作为计算字段:查询每个球队的队员数 103 | 104 | ```sql 105 | SELECT team_name, (SELECT COUNT(*) FROM player WHERE player.team_id = team.team_id) AS player_num FROM team; 106 | ``` 107 | 108 | 109 | 110 | ## 5.4 小结 111 | 112 | img 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(6) 连接表.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(6) 连接表 2 | 3 | ## 6.1 连接表的种类 4 | 5 | ### 6.1.1 笛卡尔积 6 | 7 | 笛卡尔积是一个数学运算。假设集合X和Y,其笛卡尔积是X与Y的所有组合。 8 | 9 | 示例1 - 表的笛卡尔积:两种表的笛卡尔积 10 | 11 | ```sql 12 | SELECT * FROM player, team; 13 | ``` 14 | 15 |
16 | 17 | ### 6.1.2 等值连接 18 | 19 | 等值连接是将两张表中都存在的列进行连接。 20 | 21 | 示例2 - 等值连接 :将palyer 和team 表中的team_id 用等值连接进行查询 22 | 23 | ```sql 24 | SELECT player_id, player.team_id, player_name, height, team_name FROM player, team WHERE palyer.team_id = team.team_id; 25 | ``` 26 | 27 | 示例3 - 别名使用 :与示例2相同 28 | 29 | ```sql 30 | SELECT player_id, a.team_id, player_name, height, team_name FROM player AS a, team AS b WHERE a.team_id = b.team_id; 31 | ``` 32 | 33 |
34 | 35 | ### 6.1.3 非等值连接 36 | 37 | 与等值连接相反,使用其他运算符连接的就是非等值连接。 38 | 39 | 示例4 - 非等值连接:查询每个球员的身高的级别 40 | 41 | ```sql 42 | SELECT p.player_name, p.height, h.height_level 43 | FROM player AS p, height_grades AS h 44 | WHERE p.height BETWEEN h.height_lowest AND h.height_highest; 45 | ``` 46 | 47 |
48 | 49 | ### 6.1.4 外连接 50 | 51 | - 左外连接:左边为主表,显示左表中所有行 52 | 53 | 示例5 - 左外连接: 54 | 55 | ```sql 56 | SELECT * FROM player LEFT JOIN team ON player.team_id = team.team_id; 57 | ``` 58 | 59 | - 右外连接:右边为主表,显示右表的所有行 60 | 61 | 示例6 - 右外连接 62 | 63 | ```sql 64 | SELECT * FROM player RIGHT JOIN team ON player.team_id = team.team_id; 65 | ``` 66 | 67 |
68 | 69 | ### 6.1.5 自连接 70 | 71 | 自连接可以对多个表进行操作,也可以对同一个表进行操作。 72 | 73 | 示例7 - 自连接:查看比布雷尔 格里芬高队员,以及他们对影身高 74 | 75 | ```sql 76 | SELECT b.player_name, b.height FROM player as a, player as b WHERE a. player_name = '布雷克-格里芬' and a.height < b.height; 77 | ``` 78 | 79 |
80 | 81 | ## 6.2 SQL 99 标准 82 | 83 | ### 6.2.1 交叉连接 84 | 85 | 示例1 - 交叉连接:player 与 team的笛卡尔积结果 86 | 87 | ```sql 88 | SELECT * FROM player CROSS JOIN team; 89 | ``` 90 | 91 | 示例2 - 多张表的交叉连接: 92 | 93 | ```sql 94 | SELECT * FROM t1 CROSS JOIN t2 CROSS JOIN t3; 95 | ``` 96 | 97 |
98 | 99 | ### 6.2.2 自然连接 / 等值连接 100 | 101 | 示例3 - 等值连接:player 与team的等值连接 102 | 103 | ```sql 104 | SELECT player_id, team_id, player_name, height, team_name FROM player NATURAL JOIN team; 105 | ``` 106 | 107 | 在SQL99中使用 `NATURAL JOIN` 代替了 `WHERE player.team_id = team.team_id` 。 108 | 109 |
110 | 111 | ### 6.3.3 ON 指定连接条件 112 | 113 | 示例4 - 等值连接/ 自然连接的条件指定: 114 | 115 | ```sql 116 | SELECT player_id, team_id, player_name, height, team_name FROM player NATURAL JOIN team WHERE player.team_id = team.team_id; 117 | ``` 118 | 119 | 示例5 - 非等值连接的条件指定:查询球员的身高等级,是哟哦那个palyer和height_grades两张表 120 | 121 | ```sql 122 | SQL99: 123 | SELECT p.player_name, p.height, h.height_level 124 | FROM player as p JOIN height_grades as h 125 | ON height BETWEEN h.height_lowest AND h.height_highest; 126 | ``` 127 | 128 |
129 | 130 | ### 6.3.4 USING 连接 131 | 132 | USING指定数据表中的同名字段进行等值连接 133 | 134 | 示例6 - USING 连接:与示例4等价。 135 | 136 | ```sql 137 | SELECT player_id, team_id, player_name, height, team_name FROM player JOIN team USING(team_id) 138 | ``` 139 | 140 |
141 | 142 | ### 6.3.5 外连接 143 | 144 | 示例7 - 左外连接: 145 | 146 | ```sql 147 | SELECT * FROM player LEFT JOIN team ON player.team_id = team.team_id; 148 | ``` 149 | 150 | 示例8 - 右外连接: 151 | 152 | ```sql 153 | SELECT * FROM player RIGHT JOIN team ON player.team_id = team.team_id 154 | ``` 155 | 156 | 示例9 - 全外连接 = 左右表匹配的数据 + 左表没有匹配的数据 + 右表没有匹配的数据 157 | 158 | ```sql 159 | SELECT * FROM player FULL JOIN team ON player.team_id = team.team_id 160 | ``` 161 | 162 |
163 | 164 | ### 6.3.6 自连接 165 | 166 | 示例10 - 自连接 167 | 168 | ```sql 169 | SELECT b.player_name, b.height 170 | FROM player as a JOIN player as b 171 | ON a.player_name = '布雷克-格里芬' and a.height < b.height; 172 | ``` 173 | 174 | ## 小结 175 | 176 | 1. 内连接:将多个表中满足连接条件的数据查询出来,包括等值连接、非等值连接和自连接。 177 | 2. 外连接:返回一个表中所有记录,以及另一个表中所有匹配的行,包括左外连接和右外连接和全连接 178 | 3. 交叉连接:即笛卡尔积。返回左表中的每一行与右表中每个行的组合。 179 | 180 | 181 | 182 | img 183 | 184 | img 185 | 186 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(7) 视图.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(7) 视图 2 | 3 | ## 7.1 视图及SQL操作 4 | 5 | 视图本质为虚拟表,本身是没有数据的,其可以看作是 6 | 7 | - 一张表或多张表的数据结果集 8 | - SELECT 语句的封装 9 | 10 | 在大型项目中,视图可以提升效率。 11 | 12 | ### 7.1.1 创建视图 13 | 14 | 创建视图语法: 15 | 16 | ```sql 17 | CREATE VIEW view_name AS // 视图名 18 | SELECT column1, column2 // 列名 19 | FROM table 20 | WHERE condition; // 过滤条件 21 | ``` 22 | 23 | 示例1 - 创建视图:查询比NBA球员的平均身高 高的球员,显示球员ID和身高。 24 | 25 | ```sql 26 | CREATE VIEW player_above_avg_height AS 27 | SELECT player_id, height 28 | FROM player 29 | WHERE height > (SELECT AVG(height) from player); 30 | ``` 31 | 32 | 示例2 - 使用视图: 33 | 34 | ```sql 35 | SELECT * FROM player_above_avg_hegiht; 36 | ``` 37 | 38 | ### 7.1.2 嵌套视图 39 | 40 | 示例3 - 嵌套视图:找到比上个表的球员平均身高 高的球员作为新的视图 41 | 42 | ```sql 43 | CREATE VIEW player_above_above_avg_height AS 44 | SELECT player_id, height 45 | FROM player_above_avg_height 46 | WHERE height > (SELECT AVG(height) FROM player_above_avg_height); 47 | ``` 48 | 49 |
50 | 51 | ### 7.1.3 修改视图 52 | 53 | 修改视图语法:更新原有视图 54 | 55 | ```sql 56 | ALERT VIEW view_name AS 57 | SELECT column1, column2 58 | FROM table 59 | WHERE condition; 60 | ``` 61 | 62 | 示例4 - 修改视图:增加字段 player_name 63 | 64 | ```sql 65 | ALERT VIEW player_above_avg_height AS 66 | SELECT player_id, player_name, height 67 | FROM player 68 | WHERE height > (SELECT AVG(height) FROM player); 69 | ``` 70 | 71 |
72 | 73 | ### 7.1.3 删除视图 74 | 75 | 删除视图语法: 76 | 77 | ```sql 78 | DROP VIEW view_name; 79 | ``` 80 | 81 | 示例5 - 删除视图:删除创建的视图 82 | 83 | ```sql 84 | DROP VIEW player_above_avg_height; 85 | ``` 86 | 87 |
88 | 89 | ## 7.2 使用视图简化SQL操作 90 | 91 | ### 7.2.1 利用视图完成复杂的连接 92 | 93 | 示例6 - 利用视图完成复杂的连接:对player和height_grades表进行连接 94 | 95 | ```sql 96 | CREATE VIEW player_height_grades AS 97 | SELECT p.player_name, p.height, h.height_level 98 | FROM player as p JOIN height_grades as h 99 | ON height BETWEEN h.height_lowest AND h.height_highest; 100 | ``` 101 | 102 | ```sql 103 | SELECT * FROM player_height_grades WHERE height >= 1.90 AND height <= 2.08; 104 | ``` 105 | 106 |
107 | 108 | ### 7.2.2 利用视图对数据进行格式化 109 | 110 | 示例7 - 利用视图对数据进行格式化 :输出球员姓名和对应球队,对应格式为player_name(team_name) 111 | 112 | ```sql 113 | CREATE VIEW player_team AS 114 | SELECT CONCAT(player_name, '()', team.team_name, ')') AS player_name FROM player JOIN team WHERE player.team_id = team.team_id; 115 | ``` 116 | 117 | ```sql 118 | SELECT * FROM player_team; 119 | ``` 120 | 121 |
122 | 123 | ### 7.2.3 使用视图与计算字段 124 | 125 | 示例8 - 计算字段:统计每位球员在煤厂比赛中的二分球、三分球和发球的得分,通过创建视图完成 126 | 127 | ```sql 128 | CREATE VIEW game_player_score AS 129 | SELECT 130 | game_id, player_id, 131 | (shoot_hits-shoot_3_hits)*2 AS shoot_2_points, 132 | shoot_3_hits*3 AS shoot_3_points, 133 | shoot_p_hits AS shoot_p_points, score 134 | FROM player_score 135 | ``` 136 | 137 | ```sql 138 | SELECT * FROM game_player_score; 139 | ``` 140 | 141 |
142 | 143 | ## 7.3 视图 V.S. 临时表 144 | 145 | 临时表是真实存在的数据表,不用于长期存放数据,只为当前连接存在,关闭连接后会自动释放。 146 | 147 | 视图本身是不存储数据,通常视图仅仅用于查询。 148 | 149 | 150 | 151 | ## 7.4 小结 152 | 153 | img 154 | 155 | > 视图的本质: 156 | > 157 | > 一个视图其实是SELECT语句的集合,执行时会提前编译好,可以反复使用。在底层执行顺序的时候和SELECT语句是一样: 158 | > 1、FROM子句组装数据 159 | > 2、WHERE子句进行条件筛选 160 | > 3、GROUP BY分组 161 | > 4、使用聚集函数进行计算; 162 | > 5、HAVING筛选分组; 163 | > 6、计算所有的表达式; 164 | > 7、SELECT 的字段; 165 | > 8、ORDER BY排序 166 | > 9、LIMIT筛选 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(8) 存储过程.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(8) 存储过程 2 | 3 | ## 8.1 存储过程 4 | 5 | ### 8.1.1 定义、删除、更新 6 | 7 | 存储过程是SQL语句的封装,创建存储过程后,可以像使用函数一样调用存储过程。 8 | 9 | 存储过程定义: 10 | 11 | ```sql 12 | CREATE PROCEDURE 存储过程名称([参数列表]) 13 | BEGIN 14 | 执行语句 15 | END 16 | ``` 17 | 18 | 删除存储过程 19 | 20 | ```sql 21 | DROP PROCEDURE [存储过程名称] 22 | ``` 23 | 24 | 更新存储过程 25 | 26 | ```sql 27 | ALTER PROCEDURE 28 | ``` 29 | 30 | 示例1 - 存储过程:累加计算,计算 1+2+...+n 31 | 32 | ```sql 33 | DELIMITER // 34 | CREATE PROCEDURE `add_num` (IN n INT) 35 | BEGIN 36 | DECLARE i INT; 37 | DECLARE sum INT; 38 | 39 | SET i = 1; 40 | SET sum = 0; 41 | WHILE i <= n DO 42 | SET sum = sum + i; 43 | SET i = i + 1; 44 | END WHILE 45 | SELECT sum; 46 | END // 47 | DELIMITER ; 48 | ``` 49 | 50 |
51 | 52 | ### 8.1.2 参数列表 53 | 54 | image-20201005162519814 55 | 56 | 示例2 - 参数:输出某一类型英雄的最大的最大生命值,最小的最大魔法值,以及平均最大攻击值。 57 | 58 | ```sql 59 | CREATE PROCEDURE `get_hero_scores` ( 60 | OUT max_max_hp FLOAT; 61 | OUT min_max_mp FLOAT; 62 | OUT avg_max_attack FLOAT; 63 | s VARCHAR(255) 64 | ) 65 | BEGIN 66 | SELECT MAX(hp_max), MIN(mp_max), AVG(attack_max) FROM heros WHERE role_main=s INTO max_max_hp, min_max_mp, ag_max_attack; 67 | END 68 | ``` 69 | 70 | 示例3 - 调用存储过程 71 | 72 | ```sql 73 | CALL get_hero_scores(@max_max_hp, @min_max_mp, @avg_max_attack, '战士'); 74 | SELECT @max_max_hp, @min_max_mp, @avg_max_attack; 75 | ``` 76 | 77 |
78 | 79 | ## 8.2 流程控制语句 80 | 81 | - `BEGIN...END` :包含多个语句,每个语句以 `;` 结束 82 | - `DECLARE` :声明变量 83 | - `SET` :赋值语句 84 | - `SELECT...INTO` :变量赋值 85 | - `IF...THEN...ENDIF` :条件判断 86 | - `CASE` :多条件分支判断 87 | - `LOOP` 、`LEAVE` 、`ITERATE` :循环、跳出循环、进入下一次循环 88 | - `REPEAT ... UNTIL... END REPEAT` :循环语句 89 | - `WHILE...DO... END WHILE` :循环语句 90 | 91 |
92 | 93 | ## 8.3 小结 94 | 95 | img 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /数据库/SQL必知必会/搞定SQL系列(9) 事务.md: -------------------------------------------------------------------------------- 1 | # 搞定SQL系列(9) 事务 2 | 3 | ## 9.1 事务特性:ACID 4 | 5 | 事务的特性:要么完全执行,要么不执行。 6 | 7 | 1. 原子性(Atomicity, A):数据处理操作的基本单位 8 | 2. 一致性(Consistency,c):数据库进行事务操作后,由一种一致状态变成另一种一致状态。 9 | 3. 隔离性(Isolation,I):每个事务彼此独立 10 | 4. 持久性(Durability,D):事务提交后对事务的修改是持久性的。 11 | 12 | 一致性:由具体的业务定义,任何写入数据库的数据都需要满足事先定义的约束规则。 13 | 14 | 持久性:通过事务日志保证,包括回滚日志和重做日志。 15 | 16 | ## 9.2 事务控制指令 17 | 18 | - `START TRANSACTION` / `BEGIN` :显式开启一个事务 19 | - `COMMIT` :提交事务,一旦提交,对数据库的修改是永久性的 20 | - `ROLLBACK` / `ROLLBACK TO [SAVEPOINT]` :回滚事务。撤销正在进行的所有没有提交的修改,或者将事务回滚到某个保存点 21 | - `SAVEPOINT` :在事务中创建保存点,方便后续针对保存点进行回滚。 22 | - `RELEASE SAVEPOINT` :删除某个保存点 23 | - `SET TRANSACTION` :设置事务的隔离级别 24 | 25 |
26 | 27 | ## 9.3 事务隔离 28 | 29 | 事务隔离是事务的基本特性之一,防止数据库在并发处理时出现数据不一致的情况。 30 | 31 | 示例1 - 查看事务隔离级别 32 | 33 | ```sql 34 | SHOW VARIABLES LIKE 'transaction_isolation'; 35 | ``` 36 | 37 |
38 | 39 | ### 9.3.1 事务并发处理的异常 40 | 41 | 事务并发处理时会发生以下异常:脏读、不可重复读、幻读。 42 | 43 | #### 脏读 44 | 45 | 脏读(Dirty Read):在并发访问数据库时,当一方对数据修改后,但未commit,而有另一方对数据库进行读取,会读取脏数据,称为脏读。 46 | 47 | 示例2 - 设置事务隔离级别为`读未提交` 48 | 49 | ```sql 50 | SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 51 | ``` 52 | 53 | 示例3 - 设置取消自动commit 54 | 55 | ```sql 56 | SET autocommit = 0; 57 | ``` 58 | 59 | 示例4 - 模拟脏读:客户端1 60 | 61 | ```sql 62 | -- ---------------------------- 63 | -- Table structure for heros_temp 64 | -- ---------------------------- 65 | DROP TABLE IF EXISTS `heros_temp`; 66 | CREATE TABLE `heros_temp` ( 67 | `id` int(11) NOT NULL, 68 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 69 | PRIMARY KEY (`id`) USING BTREE 70 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 71 | 72 | -- ---------------------------- 73 | -- Records of heros_temp 74 | -- ---------------------------- 75 | INSERT INTO `heros_temp` VALUES (1, '张飞'); 76 | INSERT INTO `heros_temp` VALUES (2, '关羽'); 77 | INSERT INTO `heros_temp` VALUES (3, '刘备'); 78 | ``` 79 | 80 | 示例4 - 客户端2 81 | 82 | ```sql 83 | INSERT INTO heros_temp values(4, '吕布'); 84 | ``` 85 | 86 | 示例4 - 客户端1 87 | 88 | ```sql 89 | SELECT * FROM heros_temp; 90 | ``` 91 | 92 | 93 | 94 | #### 不可重复读 95 | 96 | 不可重复读(Norepeatable Read):同一条记录,两次读取结果不一样。 97 | 98 | ![img](https://static001.geekbang.org/resource/image/c3/b8/c3361eaa98016638fc47af65ce12edb8.png) 99 | 100 | 示例5 - 模拟不可重复读:客户端1 101 | 102 | ```sql 103 | SELECT name FROM heros_temp WHERE id = 1; 104 | ``` 105 | 106 | 客户端2 107 | 108 | ```sql 109 | BEGIN; 110 | UPDATE heros_temp SET name = '张翼德' where id = 1; 111 | ``` 112 | 113 | 客户端1 114 | 115 | ```sql 116 | SELECT name FROM heros_temp WHERE id = 1; 117 | ``` 118 | 119 | #### 幻读 120 | 121 | 幻读(Phantom Read):事务A根据条件查询得到N条数据,事务B此时又更改或者增加了M条符合事务A查询的数据,当A再次查询时,会发现有N+M条数据,产生幻读。 122 | 123 | 示例6 - 幻读:客户端1 124 | 125 | ```sql 126 | SELECT * FROM heros_temp; 127 | ``` 128 | 129 | 客户端2 130 | 131 | ```sql 132 | BEGIN; 133 | INSERT INTO heros_temp values(4, '吕布'); 134 | ``` 135 | 136 | 客户端1 137 | 138 | ```sql 139 | SELECT * FROM heros_temp; 140 | ``` 141 | 142 | 143 | 144 |
145 | 146 | ### 9.3.2 事务隔离级别 147 | 148 | 解决异常数量从少到多的顺序决定隔离级别,隔离级别从高低到高分别是 149 | 150 | - 读未提交(READ UNCOMMITTED) 151 | - 读已提交 (READ COMMITTED) 152 | - 可重复读 (REPEATABLE READ) 153 | - 可串行化 (SERIALIZABLE) 154 | 155 | ![img](https://static001.geekbang.org/resource/image/b0/95/b07103c5f5486aec5e2daf1dacfd6f95.png) 156 | 157 | #### 读未提交 158 | 159 | 读未提交是指允许读到未提交的数据,这种查询不使用锁,可能会产生脏读、不可重复读、幻读等情况。 160 | 161 | #### 读已提交 162 | 163 | 读已提交是指只能读取已经commit 的数据,所以可以避免读取脏数据。如果要避免不可重复读或者幻读,需要编写带加锁的SQL语句。 164 | 165 | #### 可重复读 166 | 167 | 可重复读保证一个事务在相同查询条件下两次查询条件得到的数据结果是一致的。可以避免不可重复读和脏读,但无法避免幻读。 168 | 169 | #### 可串行化 170 | 171 | 可串行化指将事务进行串行化,即在一个队列中按照顺序执行,是最高的隔离等级。可以解决所有可能出现的异常情况,但牺牲了系统的并发性。 172 | 173 | 174 | 175 | ### 9.3.3 小结 176 | 177 | img 178 | 179 | 180 | 181 | > 不可重复读 VS 幻读的区别: 182 | > 不可重复读是同一条记录的内容被修改了,重点在于UPDATE或DELETE 183 | > 幻读是查询某一个范围的数据行变多了或者少了,重点在于INSERT 184 | 185 | > 脏读:一个事务读取了另一个事务改写但还未提交的数据。 186 | > 幻读:一个事务读取了另一个事务插入的新纪录。 187 | > 不可重复读:在同一个事务中,多次读取同一数据返回的结果有所不同。 188 | 189 | > 读未提交:在这个隔离级别下,事务A会读到事务B未提交的数据,在事务B回滚后,事务A读到的数据无意义,是脏数据,称为 脏读 190 | > 读已提交:在这个隔离级别下,只有在事务B已提交时,事务A才能读到,如果事务A先查询id为1的记录,之后事务B修改这条记录并提交,事务A再读取,两次结果会不一致,所以不可重复读。 191 | > 可重复读:在这个隔离级别下,就算事务B的修改已经提交,事务A读到的数据依旧是一致的。当事务B插入一条新数据并提交之后,事务A查询不到当前数据,查询不到就以为不存在,但是事务A却可以更新这条数据成功,并且更新后再次查询,数据出现了。一开始查询不到,但能修改,再次查询又出现了,跟幻觉一样,所以称为 幻读。 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /数据结构与算法/images/image-20201002101803574.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据结构与算法/images/image-20201002101803574.png -------------------------------------------------------------------------------- /数据结构与算法/images/image-20201005154025200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/数据结构与算法/images/image-20201005154025200.png -------------------------------------------------------------------------------- /数据结构与算法/搞定动态规划系列(1) 贪心算法.md: -------------------------------------------------------------------------------- 1 | # 搞定动态规划系列(1) 贪心算法 2 | 3 | 4 | 5 | - 重叠子问题:在计算过程中,会被重复计算的问题。 6 | 7 |
8 | 9 | ## 贪心算法 10 | 11 | - 对于某个问题进行建模后,在每一步计算时,都会选择当前的最好的选择(局部最优解),而非从整体最优考虑(全局最优解)。在所有子问题解决完成后,将局部最优解合并,得到基于局部最优解的一个解,即原问题的答案。 12 | 13 |
14 | 15 | ## 局限性 16 | 17 | - 不能保证求得的最后解是最优解 18 | - 不能用来求最大/最小解的问题 19 | - 只能求满足某些约束条件的可行解的范围 20 | 21 |
22 | 23 | ## 改进 24 | 25 | - 由于贪心算法仅考虑局部最优 26 | - 一般使用 **回溯法** 来进行优化 27 | 28 | 29 | 30 | Leetcode-322-零钱兑换:[贪心+回溯题解](https://leetcode-cn.com/problems/coin-change/solution/322-by-ikaruga/) 31 | 32 | ```C++ 33 | int coinChange(std::vector& coins, int amount) { 34 | if (amount == 0) return 0; 35 | std::sort(coins.rbegin(), coins.rend()); 36 | int ans = INT_MAX; 37 | dfsHelper(coins, amount, 0, 0, ans); 38 | return ans == INT_MAX ? -1 : ans; 39 | } 40 | 41 | void dfsHelper(std::vector& coins, int amount, int c_index, int count, int& ans){ 42 | if (amount == 0){ 43 | ans = std::min(count, ans); 44 | return ; 45 | } 46 | if (c_index == coins.size()){ 47 | return ; 48 | } 49 | 50 | for (int k = amount / coins[c_index]; k >= 0 && k + count < ans; k--){ 51 | dfsHlper(coins, amount-coins[c_index] * k, c_index+1, count+k, ans ); 52 | } 53 | } 54 | ``` 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /数据结构与算法/搞定动态规划系列(2) 暴力递归.md: -------------------------------------------------------------------------------- 1 | # 搞定动态规划系列(2) 暴力递归 2 | 3 | ## 2.1 递归实现三要素 4 | 5 | 1. 确定递归参数和返回值 6 | 2. 确定终止条件 7 | 3. 确定单层递归的逻辑 8 | 9 |
10 | 11 | ## 2.2 斐波那契数列 12 | 13 | 斐波那契数列如下所示: 14 | 15 | image-20201002101803574 16 | 17 | 求F(N) 。 18 | 19 | 迭代版本 20 | 21 | ```C++ 22 | int Fibonacci(int n){ 23 | if (n == 0 || n == 1) return n; 24 | 25 | int i = 1; 26 | int fib1 = 0, fib2 = 1, fib = 0; 27 | while (i < n){ 28 | fib = fib1 + fib2; 29 | fib1 = fib2; 30 | fib2 = fib; 31 | ++i; 32 | } 33 | return fib; 34 | } 35 | ``` 36 | 37 | 递归版本: 38 | 39 | 1. 确定参数和返回值 40 | 41 | ```C++ 42 | int fibonacci(int n); 43 | ``` 44 | 45 | 2. 确定终止条件 46 | 47 | ```C++ 48 | if (n == 0) return 0; 49 | if (n == 1) return 1; 50 | ``` 51 | 52 | 3. 确定单层递归逻辑 53 | 54 | ```C++ 55 | return fibonacci(n-1) + fibonacci(n-2); 56 | ``` 57 | 58 | ```C++ 59 | int Fibonacci(int n){ 60 | if (n == 0 || n == 1) 61 | return n; 62 | if (n > 1){ 63 | return Fibonacci(n-1) + Fibonacci(n-2); 64 | } 65 | 66 | return -1; // 输入有误,返回-1 67 | } 68 | ``` 69 | 70 |
71 | 72 | ## 2.3 优化暴力递归:剪枝与优化 73 | 74 | 1. 使用贪心,从面值最大的硬币的最大情况 75 | 2. 对于递归树中,一些重叠子问题进行剪枝。 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /数据结构与算法/搞定动态规划系列(3) 备忘录.md: -------------------------------------------------------------------------------- 1 | # 搞定动态规划系列(3) 备忘录 2 | 3 | ## 5.1 重叠子问题 4 | 5 | 重叠子问题是在计算过程中,需要重复计算的问题。在斐波那契数列中,如使用递归进行计算,每次都需要从 n到1计算,计算重复。而这种时间复杂度是十分巨大的,如O(2^n). 6 | 7 | img 8 | 9 |
10 | 11 | ## 5.2 递归中的备忘录 12 | 13 | 将解决的问题记录下来,当遇到子问题时,先从备忘录中查询是否解决过该子问题,如果之前计算过,则直接将答案取出来复用,若没有使用,则进行计算。备忘录的两种方式: 14 | 15 | 1. 数组 16 | 2. 哈希表 17 | 18 | 斐波那契数列的备忘录解法: 19 | 20 | ```C++ 21 | int FabonacciHelper(int n, std::vector& memo){ 22 | if (n == 0 || n == 1) return n; 23 | if (memo[n] != 0) return memo[n]; 24 | 25 | if (n > 1){ 26 | memo[n] = FabonacciHelper(n-1, std::vector& memo) + FabonacciHelper(n-2, std::vector& memo); 27 | return memo[n]; 28 | } 29 | 30 | return -1; 31 | } 32 | 33 | int Fiboonacci(int n){ 34 | std::vector memo(n+1, 0); 35 | return FabonacciHelper(n, memo); 36 | } 37 | ``` 38 | 39 | 硬币找零的备忘录解法: 40 | 41 | ```C++ 42 | int GetMinCountHelper(int total, std::vector& values, std::vector& memo){ 43 | if (memo[total] != -2) return memo[total]; 44 | 45 | int minCount = INT_MAX; 46 | for (int i=0; i total) continue; 49 | 50 | // 使用当前硬币 51 | int rest = total - values[i]; 52 | int restCount = GetMinCountHelper(rest, values, memo); 53 | 54 | // 无可用组合 55 | if (restCount == -1) continue; 56 | 57 | minCount = 1 + restCount; 58 | } 59 | 60 | // 硬币都无法满足要求 61 | if (minCount == INT_MAX){ 62 | memo[total] = -1; 63 | return -1; 64 | } 65 | 66 | // 保存至备忘录 67 | memo[total] = minCount; 68 | return minCount; 69 | } 70 | 71 | int GetMinCount(){ 72 | std::vector values{3, 5}; 73 | int total = 11; 74 | 75 | std::vector memo(total+1, -2); 76 | memo[0] = 0; 77 | return GetMinCountHelper(total, values, memo); 78 | } 79 | ``` 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /数据结构与算法/搞定动态规划系列(4) 动态规划.md: -------------------------------------------------------------------------------- 1 | # 搞定动态规划系列(4) 动态规划 2 | 3 | ## 4.1 动态规划的问题描述 4 | 5 | 动态规划问题的三个特征: 6 | 7 | 1. 重叠子问题:在穷举过程中(如递归),存在重复计算的现象 8 | 2. 无后效性:子问题之间的依赖是单向的,状态一旦确定,不受后续决策影响 9 | 3. 最优子结构:子问题之间相互独立,或者后续计算可以通过哦前面状态推导 10 | 11 |
12 | 13 | ## 4.2 动态规划求解 14 | 15 | 动态规划核心是写出正确的状态转移方程,确定以下几点: 16 | 17 | 1. 初始化状态:从最基本的子问题开始。 18 | 2. 状态(核心):找出子问题与原问题之间发生变化的变量,该变量是状态转移方程的参数 19 | 3. 决策:改变状态,使得状态不断逼近初始化状态。 20 | 21 | 硬币找零的动态规划解 22 | 23 | image-20201005154025200 24 | 25 | ```C++ 26 | int coinChange(std::vector& coins, int amount){ 27 | // 初值设为amount+1,dp[i] 最多需要i个,i dp(amount+1, amount+1); 30 | dp[0] = 0; 31 | 32 | // 依次求得amount的最小硬币数,即 dp[i] 33 | for (int i=0; i 49 | 50 | ## 4.3 从贪心到动态规划 51 | 52 | 贪心算法:根据当前阶段得到局部最优解 53 | 54 | 递归:自顶向下求的满足条件的所有组合,暴力计算的结果必定是整体最优解 55 | 56 | 剪枝优化:对于重叠子问题进行优化,利用备忘录记录子问题的结果。 57 | 58 | 动态规划:自底向上的计算方式,用迭代代替递归,得到全局最优解。 -------------------------------------------------------------------------------- /数据结构与算法/搞定动态规划系列(5) 经典问题.md: -------------------------------------------------------------------------------- 1 | ## 搞定动态规划系列(5) 经典问题 2 | 3 | ## 5.1 最值问题 4 | 5 | 1. 乘积最大子数组 6 | 2. 最长回文字符串 7 | 3. 最长上升子序列 8 | 9 |
10 | 11 | ## 5.2 可行性问题 12 | 13 | 1. 零钱兑换问题 14 | 2. 字符串交错组成问题 15 | 16 |
17 | 18 | ## 5.3 方案总数 19 | 20 | 1. 硬币组合问题 21 | 2. 路径规划问题 22 | 23 |
24 | 25 | ## 5.4 非动态规划问题 26 | 27 | 数据不可排序 28 | 29 | - 最小的K个数 30 | 31 | 数据不可交换 32 | 33 | - 全排列 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /笔试面试系列/images/image-20201007111610236.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/笔试面试系列/images/image-20201007111610236.png -------------------------------------------------------------------------------- /笔试面试系列/images/image-20201007112831433.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/笔试面试系列/images/image-20201007112831433.png -------------------------------------------------------------------------------- /笔试面试系列/images/image-20201012221352261.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/笔试面试系列/images/image-20201012221352261.png -------------------------------------------------------------------------------- /笔试面试系列/如果我是面试官系列(1) C++篇.md: -------------------------------------------------------------------------------- 1 | # 如果我是面试官系列(1) C++篇 2 | 3 | 1. 对于给定的一个空类,该类是否真正是空的,如果不是,会提供哪些函数?(C++进阶00-3 实验12-5) 4 | 5 | 该类不会是空的,编译器会提供构造函数、拷贝构造函数、赋值操作符重载函数和析构函数。对于拷贝构造函数和赋值操作符重载函数,如果类中含有动态内存对象时,必须自定义,否则可能会出现内存泄漏的情况。 6 | 7 | 2. 说下拷贝构造函数与赋值操作符重载函数有何作用?何时使用?(C++进阶00-3 实验00-3) 8 | 9 | 拷贝构造函数:ClassName(const ClassName& obj); 10 | 11 | 赋值操作运算符重载: 12 | 13 | ```C++ 14 | ClassName& operator = (const ClassName& obj){ 15 | if (this != &obj){ 16 | // 拷贝对象 17 | ... 18 | // 拷贝完成释放原有对象 19 | } 20 | 21 | return *this; 22 | } 23 | ``` 24 | 25 | 两者都是将一个对象拷贝至另一个对象。对于拷贝构造函数,在对象初始化时如果使用另一个对象对其进行初始化,则调用拷贝构造函数进行构造。而对象创建后,重新对对象赋值时,调用赋值操作符重载函数。 26 | 27 | 深拷贝时,必须重新定义拷贝拷贝构造函数和重载赋值操作符。 28 | 29 | 3. 阅读下列代码,说出其输出结果 30 | 31 | 问题1 32 | 33 | ```C++ 34 | const char* p = "12345"; 35 | string s = ""; 36 | 37 | s.reverse(10); 38 | for (int i=0; i<5; i++){ 39 | s[i] = p[i]; // s = "12345" 40 | } 41 | 42 | if (!s.empty()){ 43 | cout << s << endl; 44 | } 45 | ``` 46 | 47 | 输出结果为空。在进行for循环赋值时,只是将 `string` 对象的内容改变,并未改变其属性 `length` ,所以不会有输出。图示问题分析如下: 48 | 49 | image-20201007111610236 50 | 51 | 解决方案:尽量避免使用C语言中的const char* ,使用C++中的string进行操作。 52 | 53 | 问题2 54 | 55 | ```C++ 56 | string s = "12345"; 57 | const char* p = s.c_str(); 58 | 59 | cout << p << endl; // 12345 60 | s.append("abcde"); // 内存被释放,p成为野指针 61 | 62 | cout << p << endl; // 12345 63 | ``` 64 | 65 | 输出结果都为 12345。当字符串插入新的字符时,会重新分配空间,并且释放掉原有空间,所以指针会变为野指针。问题分析如图所示 66 | 67 | image-20201007112831433 68 | 69 | 解决方案:避免使用C++ 与 C混合编程的方式。 70 | 71 |
72 | 73 | 4. 内存泄漏是什么?写一个内存泄漏的例子。 74 | 75 | 内存泄漏是指在动态申请(malloc / new)内存空间后,使用完该空间,但并未释放,会造成内存泄漏。 76 | 77 | ```C++ 78 | class Test{ 79 | public: 80 | Test(int val): i(val){} 81 | int value(){ 82 | return i; 83 | } 84 | ~Test(){} 85 | private: 86 | int i; 87 | } 88 | 89 | int main(){ 90 | for (int i = 0; i < 5; i++){ 91 | Test* p = new Test(i); 92 | cout << p->value() << endl; // 使用完成,并未释放动态内存空间 93 | } 94 | 95 | return 0; 96 | } 97 | ``` 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /笔试面试系列/如果我是面试官系列(2) 网络篇.md: -------------------------------------------------------------------------------- 1 | # 如果我是面试官系列(2) 网络篇 2 | 3 | 1. 客户端挂了以后,服务器怎么办,tcp连接会不会断开(问吐了) 4 | 5 | 网络编程入门(2) 远方的你还在嘛? 6 | 7 |
8 | 9 | 2. Socket 最多能打开多少个?socket 端口范围是多少? 10 | 11 | socket 本质也是文件,所以可以通过查看系统的文件最大打开个数,一般为1024个。 12 | 13 | 1023以下端口为系统端口 14 | 15 |
16 | 17 | 3. 网络字节序和本地字节序说一下。 18 | 19 | 大端序:高位字节存放在低位地址,低位字节存放在低位地址。 20 | 21 | 小端序:高位字节存放在高位地址,低位字节存放在低位地址。 22 | 23 | 网络字节序一般为大端序,即高位字节在低位地址。网络字节序与主机字节序相互转换的四个函数: 24 | 25 | ```C++ 26 | htons(); ntohs(); htonl(); ntohl(); 27 | ``` 28 | 29 |
30 | 31 | 4. socket编程中的listen() accept() connect() 的作用? 32 | 33 | Listen() 接受客户端的连接请求,成功返回0,失败返回-1。accept() 是从已经准备好的连接队列中获取一个请求,如果队列为空,accept将阻塞等待,成功返回值为分配给客户端的socket,失败返回-1设置errno。 34 | 35 | ​ 1) 服务端调用 listen() 之前,客户端不能向服务端发起连接请求 36 | 37 | ​ 2) 服务端调用 listen() 后,服务端的socket 开始监听客户端的连接 38 | 39 | ​ 3) 客户端调用 connect() 函数向服务端发起请求连接 40 | 41 | ​ 4) TCP底层客户端与服务端三次握手建立通信通道,如果有多个客户端请求,则服务端会形成一个已准 备好的连接队列 42 | 43 | ​ 5) 服务端调用 accept() 函数从队列中获取一个已准备好的连接,函数返回一个socket ,新的socket 用于 与客户端通信,listen 的socket 只负责监听客户端的连接请求。 44 | 45 |
46 | 47 | 5. TCP 三次握手说一下 48 | 49 | image-20201012221352261 50 | 51 | 52 | 53 |
54 | 55 | 6. listen 的soocket 队列? 56 | 57 | 内核会为listen 状态的socket维护两个队列:不完全请求队列(SYN_RECV状态)和等待accept建立socket 的队列(ESTABLISHED状态)。 58 | 59 | blacklog参数指等待accept 的完全建立socket的队列长度,而不是不完全连接请求数量。 不完全连接请求数量可以在 `/proc/sys/net/ipv4/tcp_max_syn_blacklog` 设置(默认为128)。 60 | 61 | 7. TCP分包与粘包? 62 | 63 | 分包:指发送方发送字符串"hello world" ,接受方会接受到 "hello" 和 "world" 64 | 65 | 粘包:指发送方发送字符串 "hello" 和 "world" , 接收方会接受到 "hello world"。 66 | 67 | 解决方案:因为TCP传输保证两点,第一顺序不变,比如发送方发送hello,接收方一定按照顺序接受到hello。 68 | 69 | 第二分割包中间不会插入其他数据。所以在实际开发中,为解决分包和粘包的问题,需要自定义一份协议,常见的是报文长度+报文内容 0010+helloworld 70 | 71 | -------------------------------------------------------------------------------- /笔试面试系列/如果我是面试官系列(3) 排序算法.md: -------------------------------------------------------------------------------- 1 | # 如果我是面试官系列(3) 排序算法 2 | 3 | ## 3.1 冒泡排序 4 | 5 | 1. 实现一下冒泡排序算法?如何判断数组是否有序?复杂度分析? 6 | 7 | 冒泡排序是最基本的排序算法,通过两层for循环遍历数组,判断相邻两个元素是否有序来对元素进行交换。 8 | 9 | 有两种优化方式,一种是增加一个sorted 标志,当遍历一次后,没有进行交换操作,置sorted=true,则表明数组有序。 10 | 11 | 第二种优化方式为增加两个标志,一个为sorted标志,判断数组是否有序,另一个为 lastSwappedIndex ,来记录最后一次交换的位置,即有序与无序的边界sortBoard。 12 | 13 | 冒泡排序最坏时间复杂度为O(n^2),最好情况是有序数组,仅需要遍历一次即可,时间复杂度为O(n). 14 | 15 | 2. 使用冒泡排序对单链表进行排序 16 | 17 | ````C++ 18 | Node* LinkedListBubbleSort(Node* head){ 19 | if (head == nullptr) return nullptr; 20 | 21 | bool sorted = false; 22 | Node* cur = head; 23 | while (!sorted && cur->next != nullptr){ 24 | sorted = true; 25 | Node* nCur = cur->next; 26 | while (cur->next != nullptr){ 27 | if (cur->val > cur->next->val){ 28 | std::swap(cur->val, cur->next->val); 29 | sorted = false; 30 | } 31 | cur = cur->next; 32 | } 33 | cur = nCur; 34 | } 35 | 36 | return head; 37 | } 38 | ```` 39 | 40 | 41 | 42 | 3. 使用冒泡排序对字符串进行排序 -------------------------------------------------------------------------------- /笔试面试系列/如果我是面试官系列(4) SQL篇.md: -------------------------------------------------------------------------------- 1 | # 如果我是面试官系列(4) SQL篇 2 | 3 | 1. 数据库范式知道么?说一下三种范式。 (SQL-SQL必知必会-搞定SQL系列(12) 数据表的范式,你知道么) 4 | 5 | 6 | 7 | 2. 说一下 -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/01-美团/01-01_satisfyCookie.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/12. 3 | // 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main(){ 9 | int n, m, a, b; 10 | cin >> n >> m >> a >> b; 11 | 12 | int rest_1, rest_2; 13 | cin >> rest_1 >> rest_2; 14 | 15 | int min_cookie = a < b ? a : b; 16 | int max_cookie = a > b ? a : b; 17 | 18 | if (rest_1 > max_cookie || rest_2 > max_cookie){ 19 | cout << "NO" << endl; 20 | return 0; 21 | } 22 | 23 | if (rest_1 < min_cookie || rest_2 < min_cookie){ 24 | cout << "NO" << endl; 25 | return 0; 26 | } 27 | 28 | cout << "YES" << endl; 29 | return 0; 30 | } -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/01-美团/01-02_numOfPromotion.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/12. 3 | // 4 | 5 | #include 6 | using namespace std; 7 | 8 | int partition(int A[], int low, int high){ 9 | int pivot = A[high]; 10 | int i = low-1; 11 | int j = low; 12 | 13 | while (j pivot){ 15 | int tmp = A[++i]; 16 | A[i] = A[j]; 17 | A[j] = tmp; 18 | } 19 | j++; 20 | } 21 | 22 | int tmp = A[i+1]; 23 | A[i+1] = A[high]; 24 | A[high] = tmp; 25 | 26 | return i+1; 27 | } 28 | 29 | void quickSort(int A[], int low, int high){ 30 | if (low < high){ 31 | int pi = partition(A, low, high); 32 | 33 | quickSort(A, low, pi-1); 34 | quickSort(A, pi+1, high); 35 | } 36 | } 37 | 38 | 39 | int main(){ 40 | int n, x; 41 | cin >> n >> x; 42 | 43 | int score[n]; 44 | for (int i=0; i> score[i]; 46 | } 47 | 48 | quickSort(score, 0, n-1); 49 | 50 | int min_score = score[x]; 51 | int num_success = 0; 52 | for (int i=x; i >= 0; i--){ 53 | if (score[i] > min_score && score[i] > 0){ 54 | num_success++; 55 | } 56 | } 57 | cout << num_success << endl; 58 | return 0; 59 | } -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/01-美团/01-03_rotarySushi.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/12. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | int maxSubarraySumCircular(vector& A) { 11 | int sizz=A.size(); 12 | if(sizz==0){ 13 | return 0; 14 | } 15 | int sum=A[0]; 16 | int summ=A[0]; 17 | int maxx=A[0]; 18 | int minn=0; 19 | int all=A[0]; 20 | for(int i=1;i> n_grp >> n; 36 | while (n_grp--){ 37 | vector A(n, 0); 38 | int res = 0; 39 | for (int i=0; i> A[i]; 41 | } 42 | res = maxSubarraySumCircular(A); 43 | cout << res << endl; 44 | } 45 | return 0; 46 | } -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/02-01_ClockinScenicSpots.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/13. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | /* 10 | * 给定几个城市,每个城市有多个旅游景点,在朋友圈打卡:要求每个城市的景点必须在一起。至少需要发几个朋友圈 11 | * 12 | * 输入示例:[1, 2, 1, 3, 4, 6, 5, 9] 13 | * 1 1 2 3 3 4 6 8 8 9 9 14 | * 输出示例:4 15 | * 16 | * 基本思路:贪心算法。 17 | */ 18 | 19 | int numClock(vector& city){ 20 | sort(city.rbegin(), city.rend()); 21 | if (city.size() == 0) return 0; 22 | 23 | for (auto c : city) 24 | cout << c << " "; 25 | cout << endl; 26 | vector visited(city.size(), false); 27 | int res = 0; 28 | int total = 0; 29 | 30 | int i = 0; 31 | while (i < city.size()){ 32 | total = city[i]; 33 | if (visited[i]){ 34 | i++; 35 | continue; 36 | } 37 | visited[i] = true; 38 | for (int j=city.size()-1; j >= 0 && !visited[j]; j--){ 39 | if (total+city[j] <= 9){ 40 | total += city[j]; 41 | visited[j] = true; 42 | } 43 | } 44 | i++; 45 | res += 1; 46 | } 47 | 48 | return res; 49 | } 50 | 51 | int main(){ 52 | vector city; 53 | int nSpots; 54 | while (true){ 55 | cin >> nSpots; 56 | city.push_back(nSpots); 57 | if (getchar() == '\n') //检测如果是空格,退出循环; 58 | break; 59 | } 60 | 61 | for (auto c : city) 62 | cout << c << " "; 63 | cout << endl; 64 | int res = numClock(city); 65 | cout << res << endl; 66 | return 0; 67 | } -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/03-01_MathPro.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Yang Shuangzhen on 2020/10/18. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | long factorial(long number) 13 | { 14 | if(number <= 1) 15 | return 1; 16 | else 17 | return number * factorial(number-1); 18 | } 19 | 20 | int combinator(int n, int m) { 21 | int temp; 22 | if (n < m) { 23 | temp = n; 24 | n = m; 25 | m = temp; 26 | } 27 | return factorial(n) / (factorial(m) * factorial(n - m)); 28 | } 29 | 30 | int main(){ 31 | int nGrp; 32 | int ni, ki; 33 | double xi; 34 | std::vector n, k; 35 | std::vector x; 36 | 37 | cin >> nGrp; 38 | for (int i=nGrp; i>0; i--){ 39 | cin >> ni >> ki >> xi; 40 | n.push_back(ni); 41 | k.push_back(ki); 42 | x.push_back(xi); 43 | } 44 | cout< 6 | #include 7 | using namespace std; 8 | 9 | int coun = 0; 10 | 11 | /* 12 | * tn: traversed n,即已经遍历过的物品; 13 | * rw: reserved w,即背包还能容量的重量。 14 | */ 15 | 16 | int DP(const std::vector& w, const std::vector& v, int N, int W) { 17 | int dp[N+1][W+1]; memset(dp, 0, sizeof(dp)); // 创建备忘录 18 | 19 | // 初始化状态 20 | for (int i = 0; i < N + 1; i++) { dp[i][0] = 0; } 21 | for (int j = 0; j < W + 1; j++) { dp[0][j] = 0; } 22 | 23 | for (int tn = 1; tn < N + 1; tn++) { // 遍历每一件物品 24 | for (int rw = 1; rw < W + 1; rw++) { // 背包容量有多大就还要计算多少次 25 | if (rw < w[tn]) { 26 | // 当背包容量小于第tn件物品重量时,只能放入前tn-1件 27 | dp[tn][rw] = dp[tn-1][rw]; 28 | } else { 29 | // 当背包容量还大于第tn件物品重量时,进一步作出决策 30 | dp[tn][rw] = max(dp[tn-1][rw], dp[tn-1][rw-w[tn]] + v[tn]); 31 | } 32 | } 33 | } 34 | 35 | return dp[N][W]; 36 | } 37 | 38 | int DPSol() { 39 | int N = 3, W = 5; // 物品的总数,背包能容纳的总重量 40 | std::vector w = {0, 3, 2, 1}; // 物品的重量 41 | std::vector v = {0, 5, 2, 3}; // 物品的价值 42 | 43 | return DP(w, v, N, W); // 输出答案 44 | } 45 | 46 | 47 | 48 | int main(){ 49 | cout << 5 /3 << endl; 50 | traversal() 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /笔试面试系列/校招笔试/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(Interview) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_executable(01-01_satisfyCookie 01-美团/01-01_satisfyCookie.cpp) 7 | add_executable(01-02_numOfPromotion 01-美团/01-02_numOfPromotion.cpp) 8 | add_executable(01-03_rotarySushi 01-美团/01-03_rotarySushi.cpp) 9 | 10 | add_executable(02-01_ClockinScenicSpots 02-01_ClockinScenicSpots.cpp ) 11 | 12 | add_executable(03-01_MathPro 03-01_MathPro.cpp) 13 | add_executable(03-2_01bag 03-2_01bag.cpp) -------------------------------------------------------------------------------- /网络编程/images/image-20201007152244901.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/网络编程/images/image-20201007152244901.png -------------------------------------------------------------------------------- /网络编程/images/image-20201007164022801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/网络编程/images/image-20201007164022801.png -------------------------------------------------------------------------------- /网络编程/images/image-20201007203614107.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/网络编程/images/image-20201007203614107.png -------------------------------------------------------------------------------- /网络编程/images/四次挥手.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanekicn/Linux-Cpp-Development-Advanced-Learning/9ca47d6b1bb4719b919cae1f9d0e74a0f70e88f2/网络编程/images/四次挥手.pptx -------------------------------------------------------------------------------- /网络编程/网络编程入门(1) TIME_WAIT.md: -------------------------------------------------------------------------------- 1 | # 网络编程入门(1) TIME_WAIT 2 | 3 | ## 1.1 TIME_WAIT 的产生 4 | 5 | 应用服务需要通过发起TCP连接对外提供服务,每个连接会占用一个端口,当在高并发的情况下,TIME_WAIT 状态连接过多,导致本机的可用端口耗尽,应用服务则不能正常工作。 6 | 7 | image-20201007152244901 8 | 9 | 一段时间后,处于TIME_WAIT 状态的连接被系统回收,释放出本地端口,应用服务可正常工作。所以会出现应用服务时而正常,时而中断服务的状况。 10 | 11 |
12 | 13 | ## 1.2 TIME_WAIT产生的原因 14 | 15 | ### 四次挥手 16 | 17 | image-20201007203614107 18 | 19 | image-20201007164022801 20 | 21 | FIN_WAIT_1:主机1 (服务端 客户端都可发起)设置SYN、ACK,向主机发送一个FIN报文段,该阶段主机1没有数据要发送至主机2 22 | 23 | FIN_WAIT_2:主机2 收到主机1的FIN报文,发送ACK确认,表示同意主机1关闭连接,主机2进入CLOSE_WAIT状态 24 | 25 | TIME_WAIT:主机2 向主机1 发送 FIN报文,请求关闭连接,进入LAST_ACK状态 26 | 27 | CLOSED:主机1 收到FIN报文,进入TIME_WAIT状态,主机2 收到主机1 的ACK报文就进入CLOSED状态。主机1则等待2MSL没有回复后,说明对端正常关闭,主机1页关闭连接,进入CLOSED状态。 28 | 29 | ## 1.3 TIME_WAIT 的作用 30 | 31 | 1. 确保最后的ACK 能让被动关闭方接受,从而使其正常关闭。 32 | 33 | TCP是全双工, 必须可靠的终止连接的两个方向。假设最后的ACK丢失,被动方会重新发送FIN 包,主动方需要维持TIME_WAIT 状态来重发最终的ACK,否则会发送RST,导致被动方关闭出现错误。 34 | 35 | 2. 经过2MSL,足以使得两个方向上的分组都被丢弃,是的原来连接的分组在网络都自然消失,再出现分组一定是新化身所产生的。 36 | 37 | > 2MSL 是从主机1节收到FIN后 发送ACK开始计时。 38 | 39 |
40 | 41 | ## 1.4 TIME_WAIT 的危害 42 | 43 | 1. 内存资源占用 44 | 2. 端口资源占用,一般可以开启的端口(32768 ~ 61000),可以通过`net.ipv4.ip_local_port_range` 指定。 45 | 46 | 47 | 48 | ## 扩展阅读 49 | 50 | 1. [面试官,不要再问我三次握手四次挥手](https://yuanrengu.com/2020/77eef79f.html) 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /网络编程/网络编程入门(2) 远方的你还在嘛?.md: -------------------------------------------------------------------------------- 1 | # 网络编程入门(2) 远方的你还在嘛? 2 | 3 | 问题:服务器由于一些原因崩溃,向客户端发送的FIN包由于异常情况,没有正常到达,导致客户端维持该连接(不会收到服务端的消息)。 4 | 5 | 客户端崩溃,服务器端在几天内都维护着一个无用的TCP连接。 6 | 7 | 原因:客户端没有及时对连接有效性进行检测。 8 | 9 | 解决方案:保证连接的有效性检测。 10 | 11 |
12 | 13 | ## 2.1 Keep-Alive 机制 14 | 15 | 为了避免上述问题的发生,TCP有一个保持活跃的机制:Keep-Alive。 16 | 17 | Keep-Alive机制:定义一个时间段,如果在时间段内,没有任何连接相关的活动,TCP保活机制发挥作用,每隔一个时间间隔发送一个探测报文,如果连续几个探测报文没有得到相应,则认为TCP连接已经死亡,系统内核将错误信息通知给上层的应用程序。 18 | 19 | 在Linux系统中,上述时间段,时间间隔和探测次数分别为7200s,75s和9次。 20 | 21 | 开启TCP保活的三种探测情况: 22 | 23 | 1. 发送探测报文,对端正常响应。表明对端正常工作,重置TCP保活时间 24 | 2. 发送探测报文,对端响应RST报文。表明该连接不存在,但与对端有其他连接,可能由于对端程序崩溃,连接已被重置。 25 | 3. 发送探测报文,对端不响应。表明对端程序崩溃 / 其他原因导致播啊文不可达。 26 | 27 |
28 | 29 | ## 2.2 应用层探活 30 | 31 | 由于TCP的Keep-Alive机制,在Linux系统中,至少需要经过2小时11分15秒才能发现一个无效连接。对于时延敏感的系统,这个时间是无法容忍的。所以,需要在应用层进行探活。 32 | 33 | 设计一个 PING-PONG机制,当客户端到达保活时间后,发起对连接的PING操作,如果服务端对PING操作有回应,则重置保活时间,否则对探测次数进行计数,到达预先设置的次数后,则判定连接无效。 34 | 35 | PING-PONG关键技术: 36 | 37 | 1. 定时器 38 | 2. PING-PONG协议 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ## --------------------------------------------------------------------------------