学校论文集汇编题目目,3.2 第四题,为什么要用word ptr,而第三题却不用

3.31子程序的参数传递有哪些方法請简单比较

(1)用寄存器传递参数:

最简单和常用的参数传递方法是通过寄存器,只要把参数存于约定的寄存器中就可以了 由于通用寄存器个数有限这种方法对少量数据可以直接传递数值,而对大量数据只能传递地址

采用寄存器传递参数注意带有出口参数的寄存器不能保护和恢复,带有入口参数的寄存器可以保护、也可以不保护但最好能够保持一致 (2)用共享变量传递参数

子程序和主程序使用同一个變量名存取数据就是利用共享变量(全局变量)进行参数传递

如果变量定义和使用不在同一个源程序中,需要利用PUBLIC、EXTREN声明 如果主程序还要利用原来的变量值则需要保护和恢复

利用共享变量传递参数,子程序的通用性较差但特别适合在多个程序段间、尤其在不同的程序模塊间传递数据

参数传递还可以通过堆栈这个临时存储区。主程序将入口参数压入堆栈子程序从堆栈中取出参数;子程序将出口参数压入堆栈,主程序弹出堆栈取得它们 采用堆栈传递参数是程式化的它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法

3.32采用堆栈传递参数的一般方法是什么?为什么应该特别注意堆栈平衡问题

方法:主程序将入口参数压入堆栈,子程序从堆栈中取出參数;子程序将出口参数压入堆栈主程序弹出堆栈取得它们

注意:压栈与弹栈必须要一一对应。

3.33 编写一个求32位数据补码的子程序通过寄存器传递入口参数

3.34编写一个计算字节校验的子程序。所谓“校验和”是指不计进位的累加常用语建厂信息的正确性。主程序提供入口參数有数据个数和数据缓冲区的首地址。子程序回送求和结果这个出口参数传递参数方法自定。

3.35编写3个子程序把一个16位二进制数用4為16进制数在屏幕上显示出来,分别运用如下3中参数传递方法并配合3个主程序验证它。 (1)采用AX寄存器传递这个16位二进制数 (2)采用temp变量传递这个16位二进制数。 (3)采用堆栈方法传递这个16位二进制数

类中构造函数调用的顺序

1. 调用基類构造函数

2. 对象成员的构造函数

3. 派生类的构造函数

注:基类的构造函数与声明顺序有关与初始化列表顺序无关

派生类的对象继承了基类所有的特性,因此派生类对象可以直接给基类对象赋值

- 编译时的多态性 (重载,函数与运算符)

- 运行时的多态性(虚函数)

- 到运行时才确定所要调用的函数

- 在基类中关键字virtual必须写在派生类中可写可不写

- 通过指向派生类的基类指针实现

- 构造函数不能是虚函数,析构函数可以是虛函数

在主函数中指向派生类的基类指针new一个派生类对象的时候delete直接调用基类的析构函数,不会调用派生类的构造函数

将基类析构函數声明为虚析构函数即可解决。(基类析构函数为虚函数派生类函数为析构函数)

纯虚函数不具备函数的功能,不能被调用仅用来继承。

萣义:包含了纯虚函数的类

1.只能作为基类使用,不能建立对象

2.一般用来声明指向派生类的指针和引用

如果这两个文件没有inlcude那这个文件就沒有任何关系,包含也没有用

- case成立说明程序从那个case开始执行但结束则根据break;

前面是判断条件,如果成立则返回后面第一个数如果不成立僦返回后面第二个数

aaa空间里的display()函数可以和bbb空间的display()函数互不干扰,而std空间里的函数是C++自己库函数的命名空间专业的术语就是指标識符的各种可见范围,

由于人类的单词有限现在的大型程序开发,尤其是各种库之间不可能没有重名的,而且大型程序不可能一个人唍成难免会有名字重复的变量或函数,这时就需要命名空间来区分

输出当前的cpp文件中的行号

__LINE__: 在源代码中插入当前源代码行号;

__FILE__: 在源文件中插入当前源文件名;

__DATE__: 在源文件中插入当前的编译日期

__TIME__: 在源文件中插入当前编译时间;

- 如果程序中没有使用关键字namespace,则程序被認为位于一个无名的命名空间中(大部分程序示例就是这样)

- 命名空间的声明可以是不连续的(也可以在不同文件中),命名空间的实際内容为所有声明的总和

1. 迭代器也可以理解为指针,主要有自增吸取,相等不等这四种运算,比指针的功能更强大一些

2. 指针是C语訁里面就有的东西,而迭代器是C++里面才有的指针用起来灵活,效率高迭代器功能更丰富一些(不见得是强大一些),c++的stl里面很多算法嘟是基于迭代器的一部分算法的参数可以传递指针作为迭代器使用。

运算符重载是创建运算符重载函数来实现的运算符重载函数定义叻重载的运算符将要进行的操作。

1) #define是预处理指令在编译预处理时进行简单的替换,不作正确性检查不关含义是否正确照样带入,只有茬编译已被展开的源程序时才会发现可能的错误并报错

如果你把#define语句中的数字9 写成字母g 预处理也照样带入。

应仔细考虑循环体内的语句昰否可以放在循环体之外使循环体内工作量最小,从而提高程序的时间效率

在多重循环中,应将最忙的循环放在最内层

示例:如下代碼效率不高 

可以改为如下方式,以提高效率 

用乘法或其它方法代替除法

浮点运算除法要占用较多CPU资源。

示例:如下表达式运算可能要占较多CPU资源

应如下把浮点除法改为浮点乘法。

-在任何位置插入/删除时间都是常数

-只支持双向迭代器,不能使用比较移动运算符

双向隊列,可以理解为vector的扩充deque是在功能上合并了vector和list。

(2) 在内部方便的进行插入和删除操作

1 如果你需要高效的随即存取而不在乎插入和删除的效率,使用vector

2 如果你需要大量的插入和删除而不关心随即存取,则应使用list

3 如果你需要随即存取而且关心两端数据的插入和删除,则应使鼡deque

在函数的返回类型前加上关键字static函数就被定义成为静态函数。

函数的定义和声明默认情况下是extern的但静态函数只是在声明他的文件当Φ可见,不能被其他文件所用

<1> 其他文件中可以定义相同名字的函数,不会发生冲突

<2> 静态函数不能被其他文件所用

-只能插入、删除、访問栈顶元素

-通过堆排序,保证最大元素总在最前面

-pop()删除最大的元素;top返回最大元素的引用

1.统一的初始化方法:

2.成员变量可以有默认的初始值: (從JAVA里面学习的)

注意:必须初始化编译器自动推倒类型

- 不能指向动态分配内存的数组

当没有指针指向new出来的对象的时候,就自动delete掉

//不会同時托管或者说不会增加托管计数。

tips:new运算符在内存中开辟一块空间的同时会返回一个地址

可以自动转换成bool类型

7.基于范围的for循环

7.右值引用囷move语义

右值:不能取地址的表达式

8.无序容器(哈希表)

注:插入和查询的时间复杂度是常数。

上面两个符号需要结合上下文理解

&:表示声明引用

&:表示取其地址

const 类型在其他cpp文件中引用

指针是一个独立的对象存放的某一个对象的地址。

引用相当于取别名并没有生成新的对象,是原对象的另一个标签

#define是预编译命令,整个cpp文件

using 自定义名 原始名字

typedef 原始名字 自定义名字 //就你最特殊

typedef使用方法:把原来为变量名的地方替换為自定义的类型名

const与类型别名混合使用的区别

上句指的是指向char类型的常量指针(指针内容(地址)不可以变地址存放的内容可以变)

上呴指的是指向const char(常量字符)的指针,(指针地址可以变但不能通过访问地址改变其所指向的内容)

判断内容只能用#define宏定义,不能使用int a=1;,因为這是预编译,在编译过程中就结束了

注:预处理变量无视c++中关于作用域的规则

声明是告诉编译器存在这么一个标识符。

定义则是为程序申请一块内存

因为定义只能一次,而声明可以有很多次不能把定义放在.h文件中,多次包含会出问题

以上说的是不能在头文件中定义變量。但是有三个例外头文件可以定义类、值在编译时就知道的const对象和inline函数。

预处理:预处理相当于根据预处理命令组装成新的C程序鈈过常以i为扩展名。

编译:将得到的i文件翻译成汇编代码.s文件

汇编:将汇编文件翻译成机器指令,并打包成可重定位目标程序的o文件該文件是二进制文件,字节编码是机器指令

链接:将引用的其他O文件并入到我们程序所在的o文件中,处理得到最终的可执行文件

c(源攵件) → I(经过预处理) → S(经过编译得到汇编代码) → o(经过汇编得到机器指令) → e(经过链接后得到可执行程序)

包含很多成员函数:判斷大小写,判断字符空格,拼接字符串

指向某种容器元素的指针(本质上是类的静态成员

1.所有的标准库容器都支持迭代器

3.循环体中使鼡迭代器就不要向容器中添加元素。

4.v.end()//尾后迭代器指向的一个容器根本就不存在的尾后

5.如果容器为空,begin和end返回的都是尾后迭代器

不一萣是无符号型的整数

定义在while循环条件部分与循环体内部的变量每次迭代都经历从创建到销毁的过程。

1.函数定义的cpp中

2.使用函数的cpp中

引用传递:引用形参是实参的别名

值传递:实参的值拷贝给形参形参和实参是两个独立的对象。

访问(修改)函数外部对象

C程序员用指针的值传遞;

C++中推荐用法(引用类型的形参代替指针)

main函数的参数传递

当使用argv时实参从argv[1]开始,argv[0]保存程序名而非用户输入。

数组指针与指针数组嘚区别

后面可以加类型也可以加对象

当返回为值的时候,函数会返回一个临时构建的对象

当返回为引用的时候,函数不会生成对象

assert()宏是用于保证满足某个特定条件,用法是:assert(表达式); 如果表达式的值为假整个程序将退出,并输出一条错误信息如果表达式的值为真则繼续执行后面的语句。

注:这个仅仅在debug模式下可以使用

上面遵循由内向外的顺序

f1有形参列表所以f1是一个函数

f1前面有*,说明返回的是一个指针

最外面说明函数返回的是一个指向xx函数的函数指针

尾置返回类型(便于理解)

注意decltype()返回的是函数的类型。要显示加指针

类中成员函數的调用过程

成员函数执行的时候隐式传入指向当前对象的this指针。

在成员函数的形参列表后面加const表示不能修改对象的数据成员(准备说昰非静态成员)

普通对象可以调用非const成员函数const成员函数

const对象,只能调用const成员函数

返回值:如果const函数返回引用,返回的是一个常量引鼡

在类声明中加friend,可以是普通函数也可以是其他类的成员函数。

构造函数初始化必不可少

类中的常量对象引用必须在构造函数中初始化(而且必须通过构造函数列表)

2.没有构造函数(全部由用户初始化)

4.没有基类,也没有virtual函数

转换构造函数:构造函数值接受一个实参(准確说应该是其他类的实参)

A(a)与A(b)都能正常执行因为实参会隐式转换成实参。

但如果加了explicitA(b)这种写法就会报错,必须类型完全一样才行

包含目录下(包括当前目录),不要在项目中添加直接#include即可。

注:由此可知很多时候,我们在项目中的头文件中添加都是没有必要的,因為解决方案管理器中的头文件,只是起到说明提示的作用没有实际作用

库目录(包含当前目录)直接#program lib(附加依赖项也行)即可。

C++不直接处悝输入输出通过定义在标准库中的类型来处理IO,支持从设备读写数据设备可以是文件,控制台窗口

静态成员必须类外初始化

静态荿员必须在类外初始化(定义)

1.在类内部声明静态变量,并没有定义

2.声明只是说明变量的数据类型属性,并没有分配内存

3.静态变量并非荿员变量,独立于类的对象

注:一个例外的情况:const static 成员就可以在类的定义体中进行初始化

元素本身并未交换,只是交换了容器的内部数据結构

注:除了array外,swap不对任何元素进行拷贝、删除、或插入操作因此可以保证在常数时间内完成。

向vector、string、或deque插入元素会使所有元素指向嫆器的迭代器、引用、指针失效

v1.push_back(Point(1,1));//调用构造函数创建一个局部的临时对象,然后把这个对象被拷贝到容器中

访问元素的成员函数返回的嘟是引用

front返回容器的首成员

back返回容器的最后一个成员

注:不能对空容器进行操作,其行为将是未定义的

Tips:当函数返回类型为引用时候,吔可以直接对对象赋值

注:这是一个左闭右开的区间最后一个位置(element2)不删除,返回也也是迭代器element2

注:此操作会导致迭代器指针,引用失效

每步循环中都必须更新迭代器,这也是成员函数返回都是迭代器的原因

reserve(n)//人工强行分配至少这么多数目,如果分配<capacity就不操作如果>当前capacity就再次分配,但分配的结果是>=n因为n是至少分配这么多。

to_string();//可以是浮点整形等【重点记忆】

stoi();//返回整型【重点记忆】

//如果能够找到就返回元素的迭代器,如果不能找到就返回最后一个迭代器(c.cend());

注:最后一个地址(迭代器)不访问

比较容器中元素是否相等,equal()函数

//按照字典顺序排序使得相同元素靠在一起。

 //把重复的元素移动到最后面,返回第一个重复位置的迭代器

注:unique的作用是将相邻的重复项消除并返回指向無效位置的迭代器

//擦除第一个重复位置至最后一个实现去除重复元素的功能

自定义排序等函数(谓词)

可以忽略参数列表和返回类型,但必須包含捕获列表函数体

捕获列表为lambda表达式所在函数的局部变量

前两个表示范围,第三个为函数指针

标准库中算法函数命名规范

_if版本(是否使用默认的比较)

_copy 拷贝元素与不拷贝元素版本

map容器与数组类似数组的索引为int类型,而map的索引可以为制定类型

set就是一个集合, map与set都有关键芓,map有值而set没有值,但两者中关键字是不能重复

map与set混用,找出不在集合中的单次例:

Insert函数有两个版本,分别接受一对迭代器,或是一个初始化列表

向map添加元素:(类型必须是pair)

vector类似于C语言中的数组它维护一段连续的内存空间,具有固定的起始地址因而能非常方便地进行隨机存取,即 [] 操作符但因为它的内存区域是连续的,所以在它中间插入或删除某个元素需要复制并移动现有的元素。此外当被插入嘚内存空间不够时,需要重新申请一块足够大的内存并进行内存拷贝值得注意的是,vector每次扩容为原来的两倍对小对象来说执行效率高,但如果遇到大对象执行效率就低了。

list类似于C语言中的双向链表它通过指针来进行数据的访问,因此维护的内存空间可以不连续这吔非常有利于数据的随机存取,因而它没有提供 [] 操作符重载

deque类似于C语言中的双向队列,即两端都可以插入或者删除的队列queue支持 [] 操作符,也就是支持随机存取而且跟vector的效率相差无几。它支持两端的操作:push_back,push_front,pop_back,pop_front等并且在两端操作上与list的效率也差不多。或者我们可以这么认为deque是vector跟list的折中。

map类似于数据库中的1:1关系它是一种关联容器,提供一对一(C++ primer中文版中将第一个译为键每个键只能在map中出现一次,第二個被译为该键对应的值)的数据处理能力这种特性了使得map类似于数据结构里的红黑二叉树。

multimap类似于数据库中的1:N关系它是一种关联容器,提供一对多的数据处理能力。

set类似于数学里面的集合不过set的集合中不包含重复的元素,这是和vector的第一个区别第二个区别是set内部用平衡二叉树实现,便于元素查找而vector是使用连续内存存储,便于随机存取

multiset类似于数学里面的集合,集合中可以包含重复的元素

在实际使鼡过程中,到底选择这几种容器中的哪一个应该根据遵循以下原则:

1、如果需要高效的随机存取,不在乎插入和删除的效率使用vector;

2、如果需要大量的插入和删除元素,不关心随机存取的效率使用list;

3、如果需要随机存取,并且关心两端数据的插入和删除效率使用deque;

4、如果打算存储数据字典,并且要求方便地根据key找到value一对一的情况使用map,一对多的情况使用multimap;

5、如果打算查找一个元素是否存在于某集匼中唯一存在的情况使用set,不唯一存在的情况使用multiset

Insert()的返回值依赖与容器和参数,返回一个pair对象第一个是指向关键字的迭代器,第二個返回是够插入成功的bool值(如果key存在就不插入,返回false)

允许一个关键字多次出现一个关键字可以对应多个不同的元素

返回值类型是左徝,可以直接改变pair的值

:对map进行下标访问的时候,如果关键字不存在则会向map中添加该元素

find()当搜索不到关键字的时候,不会自动添加

P390,count函数返回元素对应的个数

分别指向第一个与最后一个位置如果元素不在里面则指向同一个位置

方法三:[起点与终点]equal_range函数,返回一个迭代器pair

pair里面放的实际上是两个迭代器(指针)

第一个迭代器是第一个位置第二个迭代器是最后一个位置,若没有找到则指向可插入的位置

使用动态生存期的类的资源的类

使用动态内存出于以下三种原因

1.程序不知道自己需要多少对象//此处需要扩充一下

2.程序不知道对象的准确类型

3.程序需要在多个对象之间共享数据

不能将一个内置指针隐式转换为一个智能指针

智能指针向普通指针的转换

向不能使用智能指针的代码傳递一个普通指针,使用.get()函数返回一个普通指针,但这个指针不能被delete

拷贝构造函数在以下三种情况被自动调用

1.  用一个对象去初始化另外一个对象的时候。

2.  函数值传递中为某个类的对象

3.  函数返回值为某个类的对象(会创建一个临时变量)

:变量创建完成后立即释放函数的局部变量

对象之间的之间赋值(=)

内容通过重载运算符=实现,当对象中包含const成员的时候默认的重载函数就会失效。

(1)lib是编译时需要的dll是运行時需要的。

如果要完成源代码的编译有lib就够了。

如果也使动态连接的程序运行起来有dll就够了。

在开发和调试阶段当然最好都有。

  它昰指dll中说明输出的类或符号原型或数据结构的.h文件当其它应用程序调用dll时,需要将该文件包含入应用程序的源文件中    

  它是dll在编译、链接成功后生成的文件。主要作用是当其它应用程序调用dll时需要将该文件引入应用程序。否则dll无法引入。

  它是应用程序调用dll运行时真囸的可执行文件。dll应用在编译、链接成功后.dll文件即存在。开发成功后的应用程序在发布时只需要有.exe文件和.dll文件,不必有.lib文件和dll头文件 

对成员进行拷贝、移动、赋值、销毁等操作(拷贝与析构)

拷贝构造函数,移动构造函数

用同类型的对象初始化本对象时

拷贝赋值运算符迻动赋值运算符(就是重载=运算符)

将一个对象赋值给同类型另外一个对象。

1.[capture]:捕捉列表捕捉列表总是出现在Lambda函数的开始处。实际上[]昰Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;

[=]通过值捕捉所有变量

[&]通过引用捕捉所有变量

[value]通过值捕捉value,不捕捉其它变量

2.(parameters):参数列表与普通函数的参数列表一致。如果不需要参数传递则可以连同括号“()”一起省略;

3.mutable:mutable修饰符。默认情况下Lambda函数总是一个const函数,mutable可以取消其常量性在使用该修饰符时,参数列表不可省略(即使参数为空);

4.->return-type:返回類型用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略此外,在返回类型明确嘚情况下也可以省略该部分,让编译器对返回类型进行推导;就是C++11中的后置返回类型

5.{statement}:函数体内容与普通函数一样,不过除了可以使用參数之外还可以使用所有捕获的变量。

记忆方法:void fun(){}//常规函数 把返回类型后置,函数名改成[]

当且仅当通过指针或者引用调用虚函数的時候,才会在运行时解析调用这种情况下动态类型才有可能与静态类型不同,实际调用是指针所绑定的真实类型

1. 声明为虚函数(JAVA中所有函数都是虚函数)

2. 通过基类指针引用调用。

overrideC++11 支持用于确保覆盖了基类的虚函数。

final是不允许子类覆盖此虚函数

由静态绑定决定,也就是執行父类的默认形参却执行子类的函数。

有时候为了避免虚函数执行“最新”虚函数版本可以执行执行其中一个版本。

容易混淆类的靜态成员还是类中类(嵌套类)

delete与new不是函数,C++中对“运算符”进行重载是关键字//sizeof()不是函数。

  1. 调用构造函数初始化(基本类型没有)
  1. 调用析構函数(基本类型没有)

通过new一个数组的时候delete能够自动识别数组的个数,是因为 C++ 的做法是在分配数组空间时多分配了 4 个字节的大小专门保存数组的大小,在 delete [] 时就可以取出这个保存的数就知道了需要调用析构函数多少次了。

避免相等问题引起bug

函数参数值传递-指针传递

注意这裏也只是值传递把指针重新拷贝了一份,所以不会改变指针变量的地址

再次强调,这个只能改变指针所指向的对象并不能改变指针變量的地址。

需要两个调用第二次输入字符指针改成NULL;

1.,就是那些由编译器在需要的时候分配在不需要的时候自动清楚的变量的存储區。里面的变量通常是局部变量、函数参数等

2.,就是那些由new分配的内存块他们的释放编译器不去管,由我们的应用程序去控制一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后操作系统会自动回收。

3.代码区 存放程序的二进制代码

4.全局/静态存储区铨局变量和静态变量被分配到同一块内存中,在以前的C语言中全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了他们共哃占用同一块内存区。

5.常量存储区这是一块比较特殊的存储区,他们里面存放的是常量不允许修改(当然,你要通过非正当手段也可鉯修改)

构造函数为创建对象时自动调用,完成初始化工作

构造函数:用其他对象初始化

拷贝构造函数:用本对象初始化

移动构造函數:用本对象初始化(完成后对象资源转移)

左值:可以取地址的变量。

右值:无法取址的临时变量(基本变量在CPU寄存器中不在内存中)

move函数:可以将一个左值变成右值引用,也可以通过(T&&)进行类型的强制转化

移动构造函数与移动赋值函数,相对于拷贝构造函数与拷貝赋值函数前者调用后资源不存在。

在swap对象的时候调用移动构造函数会避免资源的深拷贝,提高性能如下所示。

1.智能指针托管的地址都是堆上的地址

2.不支持自动将指针转换为智能对象,必须显示调用

- auto_ptr与unique_ptr是通过转让所有权只有一个智能指针可拥有。

- auto_ptr支持赋值运算巳经被舍弃,unique_ptr不支持赋值与拷贝构造函数但支持转移构造与转移赋值

- shared_ptr赋值时计数将加1,而指针过期时计数将减1。当减为0时才调用delete

- 非类型参数(non-typetemplate parameter)可以是:整数及枚举类型、对象或函数的指针、对象或函数的引用、对象的成员指针,非类型参数是模板实例的常量;

- 模板参数可以有默认值(函数模板参数默认是从C++11 开始支持);

- 函数模板的和函数参数类型有关的模板参数可以自动推导类模板参数不存茬推导机制;

- C++11 引入变长模板参数,请见下文

找到元素第一次出现的位置则返回元素索引,没有找到则返回 string::npos;

当字符串中有一个元素与另外┅个字符串中的任意一个元素匹配则输出

注:注意find必须要完全匹配find_first_of只要匹配其中一个字符就可以。

如果参数输入为迭代器返回则为指姠被删除位置的迭代器

如果参数为数字,则返回为字串

数组名:为指向第一个元素的指针常量也就是数组第一个元素的地址。

但在以下兩中场合下数组名并不是用指针常量来表示

总结:编译器通过用户是否给出&,来决定指针变量的类型进而翻译为相应的汇编码。或者換句话说&符只是用来表明变量a取地址后得到的值,被看作什么类型的指针而不是用来表示对a进行取地址操作。

N维数组可以看成一维数組其元素是N-1维的数组

静态链接库与动态链接库区别

在程序链接过程中,将用到的库函数合并到可执行文件中

链接时记录一些重定位消息需要执行函数时,操作系统动态加载

1. 可移植性强不需要依赖库文件可以单独执行,

2. 不需要动态加载不影响性能

对比内容四个方向: 空間占用,性能移植性,维护

linux中多线程编程

作用:创建一个线程并有系统调用(一旦调用此函数,线程就开始运行) //默认是不可以分离的

输叺:线程对象指针线程属性,调用函数指针函数参数。

返回值:返回值为0代表正常返回负数代表异常

作用:用于等待某个线程退出,是当前线程阻塞等待tid线程结束,能够实现线程的合并

输入:待合并线程, 用户定义的指针用来存储被等待线程的返回值(注意是指针的指针)

返回值:0代表正确,其他值代表错误

1. 线程只是从启动例程中返回返回值是线程的退出码;

3. 线程可以被同一进程中的其他线程取消。

所谓创建进程就是创建进程实体中的PCB撤销进程就是撤销进程中的PCB

用户级线程、核心级线程

 内核级线程(KLT):切换由内核控制,当线程进行切換的时候由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp即利用多核cpu。windows线程就是这样的

 用户级线程(ULT):内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的。 


临界资源(critical resource):只允许一个进程使用的资源称

临界区:每个进程中访问临界资源的代码

std::mutex: 普通互斥量不支持同一线程多次锁定

管理的 Mutex 对象的两個类模板

//对象创建的时候,自动加锁析构的时候,自动解锁

//创建对象的时候不会自动加锁,比lock_guard拥有更多的函数控制更为灵活。

执行lock湔如果当前互斥量未锁,则加锁

如果已经锁定,则①阻塞等待(其他线程锁定)②崩溃(当前线程锁定)

①当前线程调用 wait() 后将被阻塞,该函数会自动调用 lck.unlock() 释放锁 ,在线程被阻塞时使得其他被阻塞在锁竞争上的线程得以继续执行。

②一旦当前线程获得通知(notified通常是另外某个线程调用notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock()使得 lck 的状态和 wait 函数被调用时相同。

因为可能存在虚假唤醒的情况

MMU将虚拟地址映射到物悝地址是以页(Page)为单位的对于32位CPU通常一页为4K(4096)。例如虚拟地址0xbxb700 1fff是一个页,可能被MMU映射到物理地址0xfff物理内存中的一个物理页面也称为┅个页框(Page Frame)。

现代操作系统都提供了一种内存管理的抽像即虚拟内存(virtual memory)。进程使用虚拟内存中的地址由操作系统协助相关硬件,紦它“转换”成真正的物理地址这个“转换”,是所有问题讨论的关键有了这样的抽像,一个程序就可以使用比真实物理地址大得哆的地址空间。(拆东墙补西墙,银行也是这样子做的)甚至多个进程可以使用相同的地址。不奇怪因为转换后的物理地址并非相哃的。

CPU将一个虚拟内存空间中的地址转换为物理地址需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!)CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址(=段基址加逻辑地址)再利用其页式内存管理单元,转换为最終物理地址

线程地址=段基址+逻辑地址

线性地址-->物理地址(页式存储管理单元,最简单的为页映射表如果不存在分页则线性地址为物理哋址)

在页式系统中,指令所给出的地址分为两部分:逻辑页号和页内地址

原理:CPU中的内存管理单元(MMU)按逻辑页号通过查进程页表得到物悝页框号,将物理页框号与页内地址相加形成物理地址(见图4-4)

逻辑页号,页内偏移地址->查进程页表得物理页号->物理地址:

在段式管悝系统中,整个进程的地址空间是二维的即其逻辑地址由段号和段内地址两部分组成。为了完成进程逻辑地址到物理地址的映射处理器会查找内存中的段表,由段号得到段的首地址加上段内地址,得到实际的物理地址(见图4—5)这个过程也是由处理器的硬件直接完成的,操作系统只需在进程切换时将进程段表的首地址装入处理器的特定寄存器当中。这个寄存器一般被称作段表地址寄存器

页式和段式系统有许多相似之处。比如两者都采用离散分配方式,且都通过地址映射机构来实现地址变换但概念上两者也有很多区别,主要表现茬:

1)、需求:是信息的物理单位分页是为了实现离散分配方式,以减少内存的碎片提高内存的利用率。或者说分页仅仅是由于系统管理的需要,而不是用户的需要段是信息的逻辑单位,它含有一组其意义相对完整的信息分段的目的是为了更好地满足用户的需要。

    ┅条指令或一个操作数可能会跨越两个页的分界处而不会跨越两个段的分界处。

2)、大小:页大小固定且由系统决定把逻辑地址划分为頁号和页内地址两部分,是由机器硬件实现的段的长度不固定,且决定于用户所编写的程序通常由编译系统在对源程序进行编译时根據信息的性质来划分。

3)、逻辑地址表示:页式系统地址空间是一维的即单一的线性地址空间,程序员只需利用一个标识符即可表示一個地址。分段的作业地址空间是二维的程序员在标识一个地址时,既需给出段名又需给出段内地址。

4)、比页大因而段表比页表短,鈳以缩短查找时间提高访问速度。

程序运行时操作系统需要

1.在虚拟内存中分配段空间(左边) //要求连续

2.在物理内存中分配相应的页面(右边) //不一定要连续

3.把段拆开,分别映射到不同的页建立映射表

段基址保存在进程的PCB中,但是由于进程里面有很多段(代码段堆、栈、等),所以一个进程存放多个段基址(进程段表LDT表)

1. 每一个进程在用户态对应一个调用栈结构(callstack)

2. 程序中每一个未完成运行的函数对应一个栈帧(stackframe)棧帧中保存函数局部变量、传递给被调函数的参数等信息

3. 栈底对应高地址,栈顶对应低地址栈由内存高地址向低地址生长

bp(base pointer): 用于存放执行Φ的函数对应的栈帧的栈底地址

sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址

1. 被调者参数(被调用参数从右向左依次入栈)

2. 返回地址(指姠调用者下一条指令)

有四种方式:临界区、互斥量、事件、信号量。

当多个线程访问一个独占性共享资源时可以使用临界区对象。拥囿临界区的线程可以访问被保护起来的资源或代码段其他线程若想访问,则被挂起直到拥有临界区的线程放弃临界区为止。具体应用方式:

  2、在访问共享资源(代码或变量)之前先获得临界区对象,g_CriticalSection.Lock();

互斥对象和临界区对象非常相似

1. 只是其允许在进程间使用而临界区只限制与同一进程的各个线程之间使用

2. 更节省资源,更有效率

允许多个线程同时访问同一资源,我们可以指定允许个数

提供線程之间的一种通知机制当某一条件满足时,线程A可以通知阻塞在条件变量上的线程BB所期望的条件已经满足,可以解除在条件变量上嘚阻塞操作继续做其他事情。

线程有内核与用户切换之分

栈  、寄存器、 状态、 程序计数器

用户级线程有yield由用户控制(切换)

核心级线程shedule,用系统控制(切换)

能够发挥多核CPU的特性给不同的线程分配CPU核

是一种IO约束形,在IO中阻塞越久则优先级越高

2. 面包店算法(多个进程)

关中斷,但在多CPU会出问题

定义:互相等待对方持有资源导致都无法执行的情况

互斥使用:资源的固有属性

不可抢占:资源只能自动放弃

请求囷保持:进程必须占有资源,再去申请

循环等待:资源分配中形成一个环路

1. 一次性申请所有资源

每次申请资源都要执行银行家算法 O(mn^2)

许多通鼡操作系统系统都采用死锁忽略系统

以下六种计算算法时间的多项式是最常用的其关系为:

- 线性表的最大容量 //这是预先分配的

读取与存儲的时间复杂度为O(1),删除或者插入就是O(n)

一个节点中包含一个数据域和指针域

节点只包含一个指针域称为单链表

头指针指向头节点,如果沒有头节点则指向首节点。(头节点可以没有)

顺序存储与单链表性能对比

不需要分配存储空间个数不受限制

静态链表:用数组来描述的鏈表(游标实现法)

之所以成为静态链表,是因为需要预先(静态)分配内存

元素中游标存储下一个元素的下标(可以认为下标等同于地址)

第一和朂后一个元素特殊处理

1.第一个元素的cur存放 备用链表的第一节点下标

在插入和删除操作时只需要修改游标,不需要移动元素改进了顺序存儲插入和删除需要大量移动元素的缺点

没有解决连续存储分配带来表长难以确定的问题。

能够从任意一个节点开始遍历全部节点。

链表頭插与为插法对比:

  • 头插法要比尾插法算法简单
  • 头产生的链表是逆序的即第一个输入的节点实际是链表的最后一个节点。
  • 通常用尾插法來创建链表

只允许在一头插入另一端进行删除的线性表,而栈是全面都在一头进行操作

队列的顺序存储,入队列很快出队列为O(n),如丅图所示

但顺序存储结构,通过循环队列优化使得出队列仍然为O(1)。

主要是通过分析模式信息加大步进实现加速。

1.根据前缀和后缀计算出公共元素的最大长度表:

前缀为除最后一个元素外包含第一个元素的所有组合。

后缀为除第一个元素外包含最后一个元素的所有組合。

模式串右移位数=已匹配的字符数-失配字符前一字符对应的最大长度值

树、二叉树、森林的转换

1.加线 兄弟节点之间

2.去线 除第一个孩孓外所有,所有连线去掉

3.调整结构 顺时针旋转

2.加线 所有根节点变成二叉树

树到二叉树根节点只有左子树

森林到二叉树根节点既有左子树又囿右子树

因为右子树为其兄弟,森林有好多同级的树

1.加线 右孩子与父节点连接

2.去线 去除兄弟之间的连线

树,森林前根遍历与二叉树的湔序遍历结果相同

树森林后根遍历与二叉树的中序遍历结果相同

赫夫曼树(最优二叉树)

结点路径长度:根节点到该节点的连接数

树的路径長度:所有叶子结点的长度之和

带权路径就要*相应的权值。

WPL:树的带权路径长度越小越好,当达到最小值时就是赫夫曼树。

定长编码:ASCII编码

变长编码:根据整体频率灵活调节

前缀码:没有任何码字是其他码的前缀

2.线性结构(一对一)

顶点都存储在一个数组中然后与其相邻嘚顶点的(下标/地址)存在一个链表中

有向图需要存储两个领接表(邻接表和逆邻接表),分别表示其出度与入度

十字链表(针对有向表优化) 可鉯同时知道节点的入度和出度信息

//分别是数据入边表第一个节点,出边表第一个节点

//分别是弧尾节点、弧头节点、弧头节点与当前弧头節点相同的边的指针、省略

邻接多重表(针对无向表优化) 删除某条边只需删除一个边表节点

//边端点i端点为i的另外一条边的指针,边端点j端点为j的另外一条边的指针

线性表可以没有数据元素称为空表

()表示无序边,顺序可颠倒,(A,D)

<>表示有向边顺序不可颠倒,<A,D>有向边称为"弧"分别昰弧头,弧尾

完全图:任意两个直接存在连接

有向完全图:任意两个顶点之间存在互为相反的两条弧,边数:n*(n-1)

度:表示某顶点上边的连接數

其中有向图分为入度和出度

简单回路:出端点外节点不重复出现

连通图:任意两个顶点可以连接

有向树:一个结点的入度为0,其余结点叺度为1

生成树: n个顶点、n-1条边、连通图

DFS(深度优先遍历)

在没有遇到标记点就用右手/左手原则。

BFS(广度优先遍历)

DFS(深度优先遍历)

BFS(广度优先遍历)

在沒有遇到标记点就用右手/左手原则。

最小生成树:(极小连通子图)

有一种小树苗生长的思想:
1.选择离当前树最近的顶点
2.加入到当前树更噺节点离树的最短距离

注:步骤2中取最小边,要注意检查是否形成回路可以通过并查集实现

逐顶点检查每个顶点能否缩短其他两个顶点の间的距离
注:检查一个顶点时,就要两个for循环遍历所有情况所以最终需要三个for循环


1.将距离最小的顶点作为确定点
2.更新源点到不确定顶點的最小距离
注:此过程中确定顶点数目不断增加,直至全部遍历

1.逐边检查经过这条边能够使点到终点距离变短
2.遍历N-1次,N为顶点数目

计算出任意两点之间的最小距离

计算出某点到任意点的最小距离

桶排序、基数排序、箱排序

如果输入数据变化有限此方法效率很高

1.如果数據输入波动很大,则占用空间大

1.逐个遍历左右邻居互相比较来确定最小值
2.重复上述操作,确定次小值

1.确定基准数的位置(左侧≤基准数≤右侧)
2.对左右区间分别快速排序

递归实现海量数据会栈溢出

1.对两个字序列分别排序
2.对已经排序好的序列进行归并

递归实现,海量数据會栈溢出

每次遍历找到最小的元素并交换

复杂度与冒泡一样,性能稍优于冒泡

每次将根节点值输出(最大/最小)

不需要额外空间适合海量數据

最后一个非叶结点为第n/2个节点

堆与堆排序(优先队列)

堆是一种特殊的完全二叉树,所有的父节点都要比子节点小/大

法一:建立一个树嘫后不断插入

法二:(更加高效)算法复杂度为O(n)

1. 将n个节点放入一个完全二叉树

2. 从n/2个节点(非叶子节点)开始逐个向下调整

为了便于操作,将最後一个元素移至第0位然后执行下沉操作

从最后一个位置插入,然后向上调整

法一:删除最小堆的最顶元素(最小),然后调整顺序鈈断重复,可以生成排序好的数组

1.先按最大堆完全二叉树,

2.建立将顶端(最大)与最后一个元素h[n-1]交换并n--,//此时n的最终位置已经确定

4.偅复上述2,3。最终数组h就是排序号的

应用:寻找第K大的数,建立最小堆;寻找第K小的数建立最大堆

用于确定有森林中有多少颗树。

2.合并(1.各自头目比较 2.头目归顺)

3.检查数组中索引号为自身的(头目/根节点)就能知道有多少树。

元素之间没有关系是基于数据的集合,要想获嘚较高的查找性能就必须改变数据元素之间的关系。

1.简单顺序查找(挨个遍历与元素对比)

2.顺序查找优化(将待查找元素放在数组第0个元素位置从最后开始搜索)

2.插值查找(二分法改进,下一查找位置与元素值有关),线性

3.斐波那契查找(二分法插值位置的改进)

注:有序查找比较如下图所示

1.稠密索引 每一个记录对应一个索引项

2.分块索引 块之间有序块内无序

3.倒排索引 由一个属性进行确定。(结构为次关键码、记录号表)

咗子树所有节点值小于根节点右子树所有节点值大于根节点

查找:递归,如果比节点小就左边大就右边,直到相等结束

增加:先查找昰否存在插入到合适的位置

删除:较为复杂需要分情况

平衡二叉排序树(AVL树)

2. 所有节点的左右子树高度差(abs(BF))不超过1(BF值=左子树高度-祐子树)

定义:每个节点孩子数可多于2个

阶:节点最大孩子的数目称为B树的阶。

2-3树:每个节点具有两个或者三个孩子

2节点:包含一个元素与兩个孩子

3节点:包含两个元素与三个孩子

1.要么有两个孩子要么没有孩子,不能只有一个孩子

2.所有叶子节点都在同一层上

B树:平衡多路查找树主要用于内外存的数据交换

B+树:解决B树的遍历问题,使其不需要来回切换

1.叶子节点会再次出现分支节点元素

2.每个叶子节点包含指向丅一个元素的指针

红黑树:就是用红链接表示3-结点的2-3树(将三节点转换成二节点,中间用红链连接

规则1、根节点必须是黑色

规则2、任意从根到叶子的路径不包含连续的红色节点。

规则3、任意从根到叶子的路径的黑色节点总数相同

红黑树是牺牲了严格的高度平衡的优樾条件为代价,

红黑树能够以O(logN)的时间复杂度进行搜索、插入、删除操作与AVL树是一样的,但统计性能优于AVL

定义:数据之间没有关系,建立叻数据(key)索引(index)之间的关系其算法复杂度达到O(1).

散列技术既是存储也是查找技术:都是通过散列函数计算关键字的地址 

2.数字分析法、平方取中法、折叠法、求余数法、随机数

1.开放定址法:(f(key)+d)mod m(这个可以线性,二次随机的)

2.再散列函数法:使用多种散列函数

3.链地址法:┅个位置加上一个链表

4.公共区域溢出法:有溢出的就存储到溢出表中

stack的升级版,支持中间插入(insert)、移除(erase)

//基础的数据机构实际中很尐用

普通数组,不可以调整大小

分解成若干子问题先求解子问题,在逐渐向上求解

1.子问题之间互相关联
2.保存子问题答案不需要反复求解

2.相同的子问题需要重复求解,复杂度指数级别增长


依赖于当前已经做出的所有选择采用自顶向下(每一步根据策略得到当前一个最优解,保证每一步都是选择当前最优的)的解决方法

Prime、Krusal最小生成树Dijstra最短路径,哈夫曼编码、背包问题

与前两种不同这采用自顶向下的设计

1.随機选取基准值(枢轴),随机选择K个、取中间值(默认k=3)

3.子数组很小的时候不使用快排使用插入排序

如果没有重复字符串,那就不必要偅复匹配

next[j] = 0, 0的含义就是让主串的这个字符和模式串的首字符前面那个不存在的字符进行比较换种说法就是前面所讲的让主串移动,让主串嘚下一个字符和模式串的第一个字符进行匹配 

next[j] = 1  没有上图所示情况,且匹配不成功的模式串字符不是第一个此时需要让主串没有匹配成功嘚字符和模式串的首字符进行匹配

递归= 递+结束条件+归

拓扑排序:把有向顶点图构造成拓扑序列

实施步骤:(输入为邻接表,顶点表结点中存放其入度) 算法复杂度:O(n)

寻找入度为0的结点并删除弧尾为该结点的弧,重复此操作(最终得到的序列不唯一)

作用:检查有向图中是否存在環

定义:从源点到会点的最大长度

关键活动:关键路径上的活动

注意:当关键路径不唯一的时候,提高关键活动速度并不能解决问题

1. 寫出状态转移方程

问题分解:分两种情况拿了第i个物体,以及没有拿第i个物体 //因为这里物品只有一个

其中i表示可以拿物品的种类j表示包嘚最大重量。

数据库中单独的执行单元

原子性:要么全部完成要么全部不完成,不可能停滞在中间某个环节事务在执行过程中发生错誤,会被回滚(Rollback)到事务开始前的状态

一致性:事务执行前后满足所有指定约束。

隔离性:为了防止事务操作间的混淆必须串行化或序列化请求,即在同一时间仅有一个请求用于同一数据

持久性:事务所对数据库所作的更改持久的保存在数据库之中

一特殊类型的存储過程,由事件触发不是程序调用或者,手动启动

目的:保证数据的有效性与完整性。

根据SQL语句不同触发器可分为两类:DML和DDL

DML:(数据操莋语言事件时执行) 有After(在之后执行)与Instead Of(在之前执行)两种

DDL:(数据定义语言事件时执行)

存储过程是一个预编译的SQL语句,优点是允许模块化的设計就是说只需创建一次,以后在该程序中就可以调用多次如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快可以用一個命令对象来调用存储过程。

触发器与存储过程非常相似触发器也是SQL语句集,两者唯一的区别是触发器不能用EXECUTE语句调用而是在用户执荇Transact-SQL语句时自动触发(激活)执行

主键(主码):一个字段或者多个字段、为表中位移的标识符。

注:主键不能为空且一个表只能有一个主键。

外键(外码):公共关键字在一个关系中为主键时此关键字为另外一个关系的外键。

程序并发执行中不断申请与释放,由于争奪资源处于无限期的等待

防止进入不安全的状态(代表性算法如银行家算法)

共享锁(读锁、S锁):用于不更改或不更新的数据操作,洳果事务T对数据A加共享锁其他事务只能再加共享锁,不能加排他锁

互斥锁(排他锁、写锁、X锁):用于数据修改保证在任意时刻只能囿一个线程访问对象。

1NF:表中每一列都具有不可分割的基本数据项即实体的某个属性不能有多个值,或者不能有重复的属性

比如:如果一个职工有两个电话,那就要分成办公电话,与移动电话不能合在一个属性里面

2NF:数据库中的每一个实例(行)必须唯一的区分,通常我们會在为表加上一列用于区分,以存储各个实例的唯一标识

注:第二范式必须先满足第一范式

3NF:非主属性不依赖于其它主属性。//说明这是独竝的不会造成数据冗余。

BCNF:符合3NF并且,主属性不依赖于主属性也就是说,所有属性(包括主属性和非主属性)都不传递依赖于R的任哬候选关键字

4NF:要求把同一表内的多对多关系删除

超键、候选键(候选码)主键

超键:在关系中能唯一标识元组的属性集

候选键:某个關系变量的一组属性所组成的集合,它需要同时满足下列两个条件:

1.这个属性集合始终能够确保在关系中能唯一标识元组

2.在这个属性集匼中找不出合适的子集能够满足条件。

主键:认为指定某个候选键

候选键就是把超键里面多于的属性给去除。(候选键是最精简的)

主屬性:某一个候选关键字的属性集中的一个属性

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

行为型模式,共十一种:筞略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

开闭原则就是说对扩展开放,对修改关闭在程序需要进行拓展的时候,不能去修改原有的代码实现一个热插拔的效果。所以┅句话概括就是:为了使程序的扩展性好易于维护和升级。想要达到这样的效果我们需要使用接口和抽象类,后面的具体设计中我们會提到这点

子类可以扩展父类的功能,但不能改变父类原有的功能它包含以下4层含义:

子类可以实现父类的抽象方法,但不能覆盖父類的非抽象方法

子类中可以增加自己特有的方法。

当子类的方法重载父类的方法时方法的前置条件(即方法的形参)要比父类方法的輸入参数更宽松。

当子类的方法实现父类的抽象方法时方法的后置条件(即方法的返回值)要比父类更严格。

这个是开闭原则的基础具体内容:真对接口编程,依赖于抽象而不依赖于具体

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好还是一个降低類之间的耦合度的意思,从这儿我们看出其实设计模式就是一个软件的设计思想,从大型软件架构出发为了升级和维护方便。所以上攵中多次出现:降低依赖降低耦合。

为什么叫最少知道原则就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立

原则是尽量使用合成/聚合的方式,而不是使用继承

静态变量,只会创建一次线程安全  

物理层:建立、维护、断开粅理连接。

数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能(由底层网络定义协议)将比特组合成字节进而组合成帧,用MAC地址访问介质错误发现但不能纠正。

网络层:进行逻辑地址寻址实现不同网络之间的路径选择。协议有:ICMP IGMP IP(IPV4 IPV6) ARP RARP

传输层:定义传输數据的协议端口号以及流控和差错校验。协议有:TCPUDP,数据包一旦离开网卡即进入网络传输层

会话层:建立、管理、终止会话(在五層模型里面已经合并到了应用层)

表示层:数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)格式有JPEG、ASCll、DECOIC、加密格式等

网络服务与最终用户的一个接口。

物理层:网卡网线,集线器(采用广播的形式来传输信息)调制解调器、中继器(Repeater,也叫放大器)

数据链路层:网桥交换机

网关工作在第四层传输层及其以上

物理层:主要负责在物理线路上传输原始的二进制数据;

数据链路层:主偠负责在通信的实体间建立数据链路连接;

网络层:创建逻辑链路,以及实现数据包的分片和重组实现拥塞控制、网络互连等功能;

传輸层:负责向用户提供端到端的通信服务,实现流量控制以及差错控制;

应用层:为应用程序提供了网络服务

有时候也会说成是四层:网絡接口层(物理层+数据链路层)、 IP层(网络层)、传输层、应用层

IP地址有32位二进制数组成(4个字节)

A类地址:以0开头,第一个字节范围:0~127;

B类地址:以10开头第一个字节范围:128~191;

C类地址:以110开头,第一个字节范围:192~223;

D类地址:以1110开头第一个字节范围为224~239;

UDP是面向无连接的,不可靠的数据报服务;

TCP的可靠性如何保证

TCP的可靠性是通过顺序编号和确认(ACK)来实现的。

上图中有几个字段需要重点介绍下:

(1)序號:Seq序号占32位,用来标识从TCP源端向目的端发送的字节流发起方发送数据时对此进行标记。

(2)确认序号:Ack序号占32位,只有ACK标志位为1時确认序号字段才有效,Ack=Seq+1

(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等具体含义如下:

(B)ACK:确认序号有效。

(C)PSH:接收方应该尽快将这个報文交给应用层

(D)RST:重置连接。

(E)SYN:发起一个新连接

(F)FIN:释放一个连接。

(A)不要将确认序号Ack与标志位中的ACK搞混了

(B)确认方Ack=发起方Req+1,两端配对

检查ACK是否为1以及ack是否为J+1,

如果正确ACK置为1,ack=K+1并将该数据包发送给Server,

Server检查ack是否为K+1ACK是否为1,如果正确则连接建立成功

例子:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求于是就向client发出确认报攵段,同意建立连接假设不采用“三次握手”,那么只要server发出确认新的连接就建立了。由于现在client并没有发出建立连接的请求因此不會理睬server的确认,也不会向server发送ack包

connect),此时Server处于SYN_RCVD状态当收到ACK后,Server转入ESTABLISHED状态SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包Server回复确认包,并等待Client的确认由于源地址是不存在的,因此Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪

当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了

1.笁作层次不同:交换机(数据链路层)路由器(网络层)。

2.数据转发对象不同:利用物理地址确定转发数据的目的地址(交换机)路甴器根据IP地址确定数据转发地址。

3.传统的交换机只能分割冲突域不能分割广播域,而路由器可以分割广播域

4.交换机负责同一网段的通信,路由器负责不同网段的通信

传输层定义:在不同的Host上应用进程提供了一种逻辑通信机制,处理的基本对象是一个个segment (segment)

注:区分网络层网络层是提供主机之间的逻辑通信机制(网络层只有一个协议 IP协议)

多路分用接收端有多个应用进程,传输层依据首部信息把不同的报文茭给不同的进程

多路复用发送端有多个应用进程传输层为每一个数据块封装正确的头部信息,从而产生正确的报文段再交给网络层。

源IP地址 源端口号 目的IP地址 目的端口号

l  一对一一个客户端进程对应一个服务器进程,假如说服务器只有一个进程那内部可以穿个多个線程,来维持一对一的服务

目的IP地址 目的端口号

l  不同源IP地址如果目标目的端口号相同,将被导向同一个socket

可靠数据传输(不错、不丢、不乱)

l  無需建立连接延迟少

可以在应用层增加可靠性机制

网络层是主机之间的连接,中间参与的设备要全程参与

传输层是端到端的传输,只偠两端之间记录即可

l  核心功能:转发与路由

路由器匹配原则:路由器最长匹配优先原则尽可能匹配更多前缀

每个分组携带目的地址,独立選择路径

传输之前连接已经建立

协议字段:实现复用与分解,6代表TCP17代表UDP数据报

首部校验和:每次转发重新计算

填充:保证头部是4字节嘚倍数

标识:标识一个IP分组(计时器产生)

标志位:是否允许分片(DF),以及是否为最后一片(MF)

片偏移:单位是8个字节

注:当较大的IP分组向较小嘚MTU(最大传输单元)转发时可以分片

提高ip4地址空间效率

DHCP(此协议是应用层协议)

替换外出IP数据报(源ip,源端口号)

记录内外网ip对应关系

替换接收IP数据報(源ip源端口号)

目的:把数据从一个节点通过链路传给另外一个节点。

解决问题:停等协议由于每次发一个帧都要停下来等待导致效率佷低。

回退N协议:如果某一帧没有收到就会重传窗口内所有已发送的帧。

点对点传输提供认证,加密、压缩功能

将多个局域网组成一個更大的局域网

防止形成环路导致广播风暴。

交换机(Switch)是一种基于MAC(网卡的硬件地址)识别能完成封装转发数据包功能的网络设备。交換机可以“学习”MAC地址并把其存放在内部地址表中,通过在数据帧的始发者和目标接收者之间建立临时的交换路径使数据帧直接由源哋址到达目的地址。

令牌帧绕环而行当需要发数据帧的时候,拥有令牌的节点才能发送数据帧

l  网络中各个概念区分:

集线器:它把一個端口接收的所有信号向所有端口分发出去

网桥:局域网之间的桥梁,根据mac地址转发帧

交换机:高级的网桥硬件实现(网桥软件实现),性能优

路由器:根据ip地址寻找最佳传输路径

网关:网络的关口连接两个不同网络的接口,一般运行在应用层

将16位寄存器AX中的数据复制传送箌变量X所指向的两个字节16位存储单元中。

本来若变量X定义成了16位的字类型变量(即用DW定义),可以直接写 MOV X, AX

但因为X未定义成字可能是用DB萣义成了8位的字节,也可能是用DD定义成了32位的双字直接那样写会出现两个操作数类型不一致的错误。所以就加上WORD PTR指定这一次将X变量地址當成字类型变量使用

MOV 是数据传送指令。

前面一个操作数 WORD PTR X是目的操作数也就是说数据住这儿存放。其中X是变量名。

后面的AX是通用寄存器中的16位累加器

你对这个回答的评价是?

我要回帖

更多关于 学校论文集汇编题目 的文章

 

随机推荐