自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(46)
  • 收藏
  • 关注

原创 TCP三次握手和四次挥手

如果不了解TCP报文的格式可以点击这里三次握手第一次握手:由客户端主动发起连接建立请求,发送数据包,将SYN置为 1 ,通常叫做发送SYN包,并且随机产生一个值:seq = J,然后将数据包发送给服务端,客户端进入SYN_SENT状态,等待服务端的确认第二次握手: 服务端收到SYN报文,对该报文进行回复,将报文的标志位SYN和ACK都置为 1 ,确认应答序号ack = J + 1,同样随机产生一个值seq = K,将数据报发送给客户端,服务端进入SYN_RCVD的状态第三次握手: 客户端接收到数据包

2021-07-28 22:24:57 2423 7

原创 TCP报文格式详解

TCP报文由俩部分组成:TCP报头和TCP数据TCP报文是TCP传输的数据单元端口号:用来标识一台主机的不同进程1) 源端端口号:源端口和IP层解析出来的IP地址标识报文的发送地,同时也确定了报文的返回地址2) 对端端口号:表明了该数据报是发送给接收方计算机的具体的一个应用程序序号和确定序号:TCP可靠传输的保障1) 序号:文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。例如:一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。.

2021-07-14 19:43:28 9402 1

原创 线程与进程的区别

线程是处理器任务调度和执行的基本单元进程是操作系统资源分配的基本单元也就是线程是处理器级别的,进程是操作系统级别的,这是线程与进程的根本区别。线程与进程还有一些其他地方的区别:资源开销:每一个进程都有独立的代码和数据空间,而线程可以看作轻量级进程,同一类的线程共享代码和数据空间,每一个线程都有自己独立的运行栈和程序计数器。进程之间的切换开销比较大,线程之间的切换开销比较小。包含关系:一个进程中可以有多个线程的存在(多线程),所以线程又叫做轻量级进程。内存分配:同一进程的线程共享本进程的地址空间

2021-07-08 16:13:18 188

原创 C++中的四种强制类形转换

在了解c++的强制类形转换的时候,先看看在c语言中是怎么进行强制类形转换的。C语言中的强制类形转换分为两种隐式类型转换显示类型转换int main(){ int a = 97; char ch = a; // 隐式类型转换 int b = (int)ch; // 显示类型转换 cout << "a = " << a << endl; cout << "ch = " << ch << endl; cout &

2021-07-07 00:06:59 258

原创 函数指针的应用场景

应用场景函数指针的最重要的一个用法就是将函数指针作为参数,在不同场景调用不同的函数指针作为参数举个例子,怎么将函数指针作为一个函数的参数void Cout(int* n) // 输出函数{ cout << *n << " ";}void Abs(int* n) // 取绝对值函数{ *n = *n > 0 ? *n : -*n;}void Op(int* n) // 取相反数{ *n = -*n;}typedef void (*fun_pt

2021-07-04 01:57:01 818

原创 指针函数与函数指针的区别

指针函数指针函数,顾名思义就是一个函数,是一个返回值为指针的一个函数,其形式:int *fun(int a, int b);当然也可以这样写:int* fun(int a, int b);让指针标准* 和 int 紧贴在一起,这样就很符合我们之前函数的书写习惯,int*是函数...

2021-07-02 00:40:32 747 1

原创 C++11——智能指针

智能指针智能指针主要用于管理在堆上分配的内存,它的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上的避免这个问题,因为智能指针是一个类,当超出了类的实例对象的作用域时,会自动调用对象的析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。C++11中的智能指针有三个:1. unique_ptr 2. shared_ptr 3. weak_ptr unique_ptr

2021-06-28 23:58:42 267 3

原创 using namespace std这样的写法好吗?

我们在写代码的时候为了方便,经常会有这样的一种习惯,不知道现在看的你有没有,就是在写完头文件的时候,会直接声明命名空间,using namespace …我们不推荐这样的书写格式,为什么呢?我们举一个例子:int max(int x, int y){ return x + y;}int main(){ int a = 10, b = 11; cout << max(a, b) << endl; // 21 cout << std::max(a, b)

2021-06-28 22:29:41 167

原创 C++11中的特性

C++11中的特性 auto 范围for循环nullptr在类中声明成员变量的时候,可以带默认值申请一段连续空间的时候,可以初始化可变的模板参数列表STL新增容器:序列式:array-静态顺序表 forward_list-带头结点循环单链表,关联式:底层为哈希的unordered的系列final和override智能指针delete 和default 控制默认成员函数```cpp```cpp```cpp```cpp```cpp```cpp```cpp`

2021-06-19 19:09:46 415

原创 冯诺依曼体系结构

冯诺依曼体系结构是现代计算机的硬件体系结构,包含五大硬件单元。输入设备:采集数据,比如,键盘,网卡接受网络中的数据输出设备:数据输出,比如,显示器,网卡想网络中发送数据存储器:在输入设备和输出设备中间进行数据缓冲,也就是我们经常说的内存运算器:进行数据运算控制器:对设备进行控制CPU = 运算器 + 控制器所有的设备都是围绕着存储器进行工作的:CPU不会直接从输入设备获取数据进行处理,而是先把数据放到存储器里,然后CPU从存储器中获取数据进行处理同样,CPU不会直接把数据交给输出设备进行

2021-04-23 20:19:10 596

原创 五种IO模型

五种IO模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、 异步IO。一、阻塞IO——最常见的IO模型在内核将数据准备好之前,系统调用会一直等待,所有的套接字默认都是阻塞的。二、非阻塞IO如果内核还未将数据准备好, 系统调用仍然会直接返回,,并且返回EWOULDBLOCK错误码。非阻塞IO往往需要程序员采用循环的方式,反复尝试读写文件描述符, 这个过程称为轮询.。这对CPU来说是较大的浪费,,一般只有特定场景下才使用。...

2021-04-11 13:13:19 185

原创 c++多态(四)——抽象类

概念:抽象类也叫做接口类,在虚函数的后面写上=0;那么这个函数就变成了一个纯虚函数,包含纯虚函数的类叫做抽象类,其不能实例化出对象。继承了基类的派生类也不能实例化出对象,除非重写纯虚函数,只有重写了纯虚函数,派生类才能实例化对象。也就是说,纯虚函数规范了派生类必须重写虚函数,另外,纯虚函数更体现出了接口继承。class car{public: virtual void Drive() = 0;};class BMW :public car{public: virtual void Dr

2020-08-11 11:17:46 247

原创 c++多态(三)—— C++11 中的override 和 final

由来:C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序 写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来 debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。final:修饰虚函数,表示该虚函数不能再被继承class Car { public: virtual void Drive() final {} }; class Maserati:public

2020-07-31 16:22:17 151

原创 c++多态(二)——虚函数以及虚函数的重写

虚函数:即被virtual修饰的类成员函数称为虚函数。class Person{public: virtual void BuyTicket() { cout << "全价票” << endl; }};虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类 型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。class Person{public: virtual void BuyTicket()

2020-07-31 15:47:42 5454

原创 c++多态(一)——多态的构成条件

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Child\Adult继承了Person。 Adult对象买票全价,Child对象买票半价。那么在继承中要构成多态还有两个条件:必须通过基类的指针或者引用调用虚函数被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写class Person{public: virtual void BuyTicket() {}};class Child :public Person{public: void BuyT

2020-07-10 11:48:09 471

原创 c++继承(九)——继承和组合

继承是is-a的关系,就是每一个派生类的对象都是一个基类对象class A{};class B :public A{};组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。class A{};class B{ public: A a;};继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用 术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对子类可见 。 继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的

2020-07-10 11:00:51 220

原创 c++继承(八)——虚拟菱形继承(详解)

上一篇我们提到菱形继承有数据冗余和二义性的问题。我们看下面的代码class fruit{public: string _name;};class apple :public fruit{protected: int _appleMoney;};class banana :public fruit{protected: int _bananaMoney;};class store :public apple, public banana{protected: str

2020-07-08 17:59:36 219

原创 c++继承(七)——单继承、多继承(菱形继承)

单继承:一个子类只有一个直接父类时称这个继承关系为单继class A{};class B : public A{};class C : public B{};多继承:一个子类有两个或以上直接父类时称这个继承关系为多继class apple{};class banana{};class fruit :public apple, public banana{};菱形继承:菱形继承是多继承的一种特殊情况。class Person{};class Student

2020-07-08 15:41:04 361

原创 c++继承(六)——继承与静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一 个static成员实例 。在这里需要注意的有static修饰的成员,只能在类中进行声明,类外定义,至于为什么我们可以参考这一篇博客:为什么static数据成员一定要在类外初始化class Person{public: Person() { _count++; }private: string _name;public: static int _count;};int Pers

2020-07-03 15:45:31 957 3

原创 为什么static数据成员一定要在类外初始化?

因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。在《c++primer》里面说在类外定义和初始化是保证static成员变量只被定义一次的好方法。class A{private: static int num; //类内声明}; int A::num = 0; //类外定义初始化 不仅仅是static的成员不能在类内定义,const类的也不能在类内定义...

2020-07-03 15:06:28 1547 2

原创 c++继承(五)——基类与友元(了解)

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员class Student;class Person{public: friend void fun(const Person& p, const Student& s);protected: int Ppro = 0;private: int Ppri = 1;};class Student :public Person{protected: int Spro = 0;private: int Sp

2020-07-03 13:57:45 709

原创 c++继承(四)——6个默认成员函数

在一个类中,至少有六个默认的成员函数,所谓的“默认”就是,我们不写,编译器自动给我们生成。class Person{public: Person(string name = "jason") :_name(name) { cout << "Person():" << endl; } Person(const Person& p) :_name(p._name) { cout << "Person(const Person&amp

2020-07-01 21:52:08 168

原创 c++继承(三)——继承的作用域

在继承的体系中,我们的派生类和基类都有自己独立的作用域。看代码:class A{public: int num = 1;};class B:public A{public: void fun() { cout << A::num << endl << num << endl; } int num = 2;};int main(){ B b; b.fun(); return 0;}这样写代码的编译是没有问题的,但

2020-06-30 16:57:48 206

原创 c++继承(二)——public、protected、private

访问限定符中的public、protected、privateclass A{public: void fun() { cout << pro << pri << pub; }protected: int pro = 1;private: int pri = 1;public: int pub = 1;};int main(){ A a; a.fun(); a.pub; return 0;}在一个类体中,自己可以访问自己的

2020-06-24 11:45:19 99

原创 c++继承(一)——初识继承

继承的概念继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。继承的定义class Base{public: int base;};class Derive:public Base{public: int derive;};Base就是基类,Derive是派生类cl

2020-06-24 10:16:57 235 1

原创 c++模板(三)——类模板

类模板的格式:template<class T1, class T2, ..., class Tn> class 类模板名{ // 类内成员定义 }; template<class T>class Vector{public: Vector(size_t capacity = 10) :_arr(new T[capacity]) , _size(0) ,_capacity(capacity) {} ~Vector() { if (_

2020-05-29 22:17:36 148

原创 c++模板(二)——模板参数的匹配

一个非模板函数是可以和一个模板函数同时存在的,并且这该函数的模板还可以被实例化为这个非模板函数int add(int num1, int num2){ return num1 + num2;}template<typename T>T add(T num1, T num2){ return num1 + num2;}int main(){ add(1, 2); //与非函数模板匹配,编译器不需要特化 add<int>(1, 2); //调用编译器特化的a

2020-05-29 21:52:35 750

原创 c++模板(一)——函数模板的使用

为什么在c++中我们引入了模板,在我们的代码中,有一些代码的使用率非常高,所以我们为了简化我们的代码,从而引入了模板。模板如果细分的话:函数模板、类模板举个例子来看:我们就写一个加法器吧int add(int num1, int num2){ return num1 + num2;}double add(double num1, double num2){ return num1 + num2;}long add(long num1, long num2){ return num1

2020-05-29 21:10:10 219

原创 详解new、delete与malloc、free的区别

malloc、calloc、realloc都是在C语言中动态开辟内存的函数,注意他们是函数,而在c++中我们采用一种新的方式来开辟内存,new、delete,他们不是函数而是运算符,他们直接有一定的联系,还有不同。malloc:其函数原型为void *malloc(unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的连续空间。new:是c++中的一个运算符,其作用是在内存的动态存储空间中分配一个连续的空间在这一点上,malloc和new好像是没有区别的我们用代码

2020-05-26 23:01:08 151

原创 sizeof和strlen的区别

sizeof和strlen经常被大家拿来作对比,但是他们之间的区别还是很大的。一、定义不同:sizeof是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。strlen是个函数,它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。二、语法不同strlen是函数,要在运行时才能计算。参数必须是字符型指针。当数...

2020-05-09 13:26:59 5309

原创 非比较排序——计数排序

计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 [1] 当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(nlog(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(nlog(n)), ...

2020-05-05 13:01:11 152

原创 C语言——归并排序(循环)

上一篇我们写到的是归并排序分治算法是用递归来实现的,但是其实我们自己观察可以写出一种不需要递归的方法,就是我们可以不需要分解的步骤,直接把序列当做已经分解好的序列来进行合并即可。代码实现:// 归并排序非递归实现 void MergeSortNonR(int* arr, int size){ int gap = 1; int* temp = (int*)malloc(size * s...

2020-05-05 11:49:32 405

原创 C语言——归并排序(分治)

归并排序该排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。图示:代码实现 // 归并排序递归实现 void MergeData(int* arr, int left, int m...

2020-05-05 10:49:45 735

原创 C语言——快速排序(前后指针法)

前后指针法思想就是俩个指针一前一后,然后从头开始遍历,当遇到比基准值小的值,俩个指针往后走一步,遇到比基准值大的就prev指针不动,cur往后走,当cur遇到比基准值小的就停下来, 然后cur指针每一次停止俩个指针之间的位置比较一下,如果俩个之间的差不是一的话,就交换俩个位置的数据,一直循环,知道遍历结束,用prev的后一个不是基准元素的位置的话,就,让prev和基准值进行交换。图示:代码...

2020-05-04 13:17:17 4237

原创 C语言——快速排序(挖坑法)

挖坑法原理图示:代码实现:// 挖坑法 int PartSort2(int* arr, int left, int right){ int end = right; int key; int mid = GetIndexMid(arr, left, right); if (mid != end) { int temp = arr[mid]; arr[mid] = a...

2020-05-03 13:17:49 561

原创 C语言——快速排序(hoare版本)

快速排序其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。具体的区间划分方式我这里总结了三种:hoare版本挖坑法前后指针法图示:代码实现://快速排序hoare版本 int PartSort1(int*...

2020-05-01 22:29:57 435

原创 冒泡排序以及优化

冒泡排序原理:就是遍历一次,然后将最大的数据给移动到序列尾部,这个遍历的过程是从头开始,一个个的比较前面的比后面的大,就交换位置,从后面的开始继续往后比较,一组遍历下来之后,最大的数据就移动到了尾部,然后控制下一次的遍历,遍历到倒数第二个元素的时候就不在往后比较了,当最后只有一个数据的时候就将数据按照升序排好了。原理图示:一次遍历走下来的整个过程和结果然后按照这样的遍历方式一直遍历下去,...

2020-04-28 15:47:26 196

原创 (直接)选择排序和堆排序

选择排序其思想是: 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。图示:代码实现:void swap(int* arr, int num1, int num2){ int temp = arr[num1]; arr[num1] = arr[num2]; arr[num2] = temp;}void SelectS...

2020-04-27 13:13:35 276 1

原创 插入排序和希尔排序

插入排序也叫直接插入排序是一种简单的插入排序法其基本思想就是:把待排序的记录按其关键码值的大小逐个插入到一 个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。整个排序的过程如下图:代码实现:void InsertSort(int* arr, int size){ int i = 1; for (; i < size; i++) { /*这种写法...

2020-04-26 17:19:52 199

原创 数据结构——排序

排序基本上可以分为四大类:插入排序、选择排序、交换排序、归并排序。从占用的空间来看还可以分为内部排序、和外部排序。当然,还有很特殊的排序的方法,比如计数排序、基数排序。所谓排序,就是讲一串有相同特征的数据,按照从小到大或者从大到小的顺序给排列。每一种排序都有自己的优点,不同的排序方法可能适用于不同的场景,衡量一个排序的好坏有以下几个数据来判断:时间复杂度、空间复杂度、稳定性。...

2020-04-26 13:32:43 178

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除