一、计算机网路相关知识点
1、TCP/UDP区别和联系
①、TCP面向连接的,UDP面向无连接 ②、TCP面向字节流的,UDP是基于报文的 ③、TCP可靠传输,UDP不可靠传输,可能会丢包 ④、TCP是全双工的,只能一对一通信,UDP支持一对一、一对多、多对一、多对多传输通信 ⑤、TCP 保证数据按序发送,UDP不保证数据按序发送
2、TCP三次握手
(1)、第一次握手,建立连接时,客户端发送SYN包到服务端,进入SYN_SENT状态,等待服务器确认。(SYN:不同序列编号) (2)、第二次握手,服务器收到SYN包后,确认是客户端发送的SYN包,于是自己发送一个SYN包,即SYN+ACK包此时服务器进入SYN_RECV状态。 (3)、第三次握手,客户端收到服务器发送的SYN+ACK包后,下高服务器端发送ACK包,此时发送完毕,建立三次握手成功,客户端和服务器端都进入ESTABLISHED。
3、SocKet
1> Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
2> 在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议
族隐藏在接口后面,对客户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定协议。
3> 门面模式,其实就是对外界提供一个简单的接口,外界不需要知到其内部实现过程。
二、C/C++相关知识点
1、C++注册表编程
注册表的组织方式跟文件目录相似,分别位根键、键值、子健三部分组成,与文件目录对应的话就是目录、子目录、文件
1.1、 根键
HKEY_CLASSES_ROOT HKEY_CURRENT_USER HKEY_LOCAL_MACHINE HKEY_USERS HKEY_CURRENT_CONFI 把它们理解成磁盘的五个分区就可以了
1.2、子健
可以有很多个子健和键值项,就像一个目录中有多个子目录和文件一样
1.3、键值项
可以理解成文件,它由三部分组成,分别为名称、数据、类型 类型又分为多种主要包括如下: REG_BINARY 二进制数据 REG_DWORD 32位双字节数据 REG_SZ 以0结尾的字符串 REG_DWORD_BIG_ENDIAN 高位排在底位的双字 REG_EXPAND_SZ 扩展字符串,可以加入变量如%PATH% REG_LINK UNICODE 符号链接 REG_RESOURCE_LIST 设备驱动程序资源列表 REG_MULTI_SZ 多字符串 注册表数据项的数据类型有8种,但最常用的主要是前3种。 有了这些基础下面我们讨论如何编程实现对注册表的操作。
2、vector
(1). 容量 向量大小: vec.size(); 向量最大容量: vec.max_size(); 更改向量大小: vec.resize(); 向量真实大小: vec.capacity(); 向量判空: vec.empty(); (2). 修改 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值 末尾添加元素: vec.push_back(); 末尾删除元素: vec.pop_back(); 任意位置插入元素: vec.insert(); 任意位置删除元素: vec.erase(); 交换两个向量的元素: vec.swap(); 清空向量元素: vec.clear(); (3)迭代器 开始指针:vec.begin(); 末尾指针:vec.end(); //指向最后一个元素的下一个位置 (4)元素的访问 下标访问: vec[1]; //并不会检查是否越界 at方法访问: vec.at(1);//以上两者的区别就是at会检查是否越界,是则抛出out of range异常 访问第一个元素: vec.front(); 访问最后一个元素: vec.back();
vector类为内置数组提供了一种替代表示,与string类一样 vector 类是随标准 C++引入的标准库的一部分 ,为了使用vector 我们必须包含相关的头文件 : #include 使用vector有两种不同的形式,即所谓的数组习惯和 STL习惯。
3、sort函数
sort() 函数受到底层实现方式的限制,它仅适用于普通数组和部分类型的容器。换句话说,只有普通数组和具备以下条件的容器,才能使用 sort() 函数:
-
容器支持的迭代器类型必须为随机访问迭代器。这意味着,sort() 只对 array、vector、deque 这 3 个容器提供支持。 -
如果对容器中指定区域的元素做默认升序排序,则元素类型必须支持<小于运算符;同样,如果选用标准库提供的其它排序规则,元素类型也必须支持该规则底层实现所用的比较运算符; -
sort() 函数在实现排序时,需要交换容器中元素的存储位置。这种情况下,如果容器中存储的是自定义的类对象,则该类的内部必须提供移动构造函数和移动赋值运算符。 -
另外还需要注意的一点是,对于指定区域内值相等的元素,sort() 函数无法保证它们的相对位置不发生改变。
4、构造函数和析构函数
构造函数和析构函数用来创建和释放该类的对象,当这个类是派生类时,其对象的创建和释放应与其基类对象及成员对象相联系。 在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的 派生类对象的创建和初始化与基类对象的创建和初始化有关。即构造派生类对象时,要对其基类数据成员、所含对象成员的数据成员以及其他的新增数据成员一起进行初始化。这种初始化工作是由派生类的构造函数来完成的。 派生类成员包括两部分: (1)从基类继承的成员:由基类构造函数完成 (2)自身定义的成员: 由派生类构造函数完成 调用基类构造函数的两种方式: (1)显式方式:在派生类的构造函数中,通过参数化表为基类的构造函数提供参数 derived::derived(arg_derived-list):base(arg_base-list) (2)隐式方式:在派生类/基类的构造函数都缺省时,派生类的构造函数则自动调用基类的默认构造函数。
5、内联函数
在C++中我们通常定义以下函数来求两个整数的最大值: 复制代码 代码如下:
int max(int a, int b) { return a > b ? a : b; } 为这么一个小的操作定义一个函数的好处有: ① 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多 ② 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多 ③ 使用函数可以确保统一的行为,每个测试都保证以相同的方式实现 ④ 函数可以重用,不必为其他应用程序重写代码
6、深拷贝和浅拷贝
编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针name拷贝后会出现两个指针指向同一个内存空间。所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝,这样就避免了内存泄漏发生。 当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应该考虑以下两种情形: 1.当函数的参数为对象时,实参传递给形参的实际上是实参的一个拷贝对象,系统自动通过拷贝构造函数实现; 2.当函数的返回值为一个对象时,该对象实际上是函数内对象的一个拷贝,用于返回函数调用处。 3.浅拷贝带来问题的本质在于析构函数释放多次堆内存,使用std::shared_ptr,可以完美解决这个问题。
|