阿里c++面经

1、c++基础知识

  • 变量的声明和定义有什么区别 .为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但是只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。 说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。 
  • sizeof和strlen的区别 
    • sizeof是一个操作符,strlen是库函数。 
    • sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。 
    • 编译器在编译时就计算出了sizeof的结果。而strlen函数必须在运行时才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。  数组做sizeof的参数不退化,传递给strlen就退化为指针了。 
  • C语言的关键字 static 和 C++ 的关键字 static 有什么区别 
    • 在C中static用来修饰局部静态变量和外部静态变量、函数。
    • 而C++中除了上述功能外,还用来定义类的成员变量和函数。即静态成员和静态成员函数。 
    • 编程时static的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传递信息,而C++的静态成员则可以在多个对象实例间进行通信,传递信息。 
    • static有什么作用 
      • static在C中主要用于定义全局静态变量、定义局部静态变量、定义静态函数。在C++中新增了两种作用:定义静态数据成员、静态函数成员。 
      • 因为static定义的变量分配在静态区,所以其定义的变量的默认值为0,普通变量的默认值为随机数,在定义指针变量时要特别注意。 
  • 一个指针可以是volatile吗 .可以,因为指针和普通变量一样
  • volatile(易变的)关键字,volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化
  • 简述C、C++程序编译的内存分配情况 C、C++中内存分配方式可以分为三种: 
    • 从静态存储区域分配: 内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static变量等。 
    • 在栈上分配: 在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 
    • 从堆上分配: 即动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。 
  • 简述strcpy、sprintf与memcpy的区别  
    • 操作对象不同,strcpy的两个操作对象均为字符串,sprintf的操作源对象可以是多种数据类型,目的操作对象是字符串,memcpy 的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。 
    • 执行效率不同,memcpy最高,strcpy次之,sprintf的效率最低。 
    • 实现功能不同,strcpy主要实现字符串变量间的拷贝,sprintf主要实现其他数据类型格式到字符串的转化,memcpy主要是内存块间的拷贝。
  • 面向对象的三大特征 
    • 封装性:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)。 
    • 继承性:广义的继承有三种实现形式:实现继承(使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。 
    • 多态性:是将父类对象设置成为和一个或更多它的子对象相等的技术。用子类对象给父类对象赋值之后,父类对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。 
  • C++的空类有哪些成员函数 
    • 缺省构造函数。 
    • 缺省拷贝构造函数。 
    • 缺省析构函数。 
    • 缺省赋值运算符。 
    • 缺省取址运算符。 
    • 缺省取址运算符 const。
      • 注意:有些书上只是简单的介绍了前四个函数。没有提及后面这两个函数。但后面这两个函数也是空类的默认函数。另外需要注意的是,只有当实际使用这些函数的时候,编译器才会去定义它们。 
  • 谈谈你对拷贝构造函数和赋值运算符的认识 
    • 拷贝构造函数生成新的类对象,而赋值运算符不能。 
    • 由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉 
  • 简述类成员函数的重写、重载和隐藏的区别  
    • 重写和重载主要有以下几点不同
      • 范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中。 
      • 参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参数列表一定不同。 
      • virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函数可以被virtual修饰,也可以没有。
    • 隐藏和重写、重载有以下几点不同。 
      • 与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中。 
      • 参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同,也可不同,但是函数名肯定要相同。
      • 当参数不相同时,无论基类中的参数是否被virtual修饰,基类的函数都是被隐藏,而不是被重写。 
    • 说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也是完全不同的,覆盖是动态态绑定的多态,而重载是静态绑定的多态。
  • 简述多态实现的原理    编译器发现一个类中有虚函数,便会立即为此类生成虚函数表 vtable。虚函数表的各表项为指向对应虚函数的指针。编译器还会在此类中隐含插入一个指针vptr(对vc编译器来说,它插在类的第一个位置上)指向虚函数表。调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,。如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。 
  • typedef和define有什么区别 
    • 用法不同:typedef用来定义一种数据类型的别名,增强程序的可读性。define主要用来定义常量,以及书写复杂使用频繁的宏。 
    • 执行时间不同:typedef是编译过程的一部分,有类型检查的功能。define是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。 
    • 作用域不同:typedef有作用域限定。define不受作用域约束,只要是在define声明后的引用都是正确的。 
    • 对指针的操作不同:typedef和define定义的指针时有很大的区别。 
    • typedef定义是语句,因为句尾要加上分号。而define不是语句,千万不能在句尾加分号。
  • 关键字const是什么 
    • const用来定义一个只读的变量或对象。主要优点:便于类型检查、同宏定义一样可以方便地进行参数的修改和调整、节省空间,避免不必要的内存分配、可为函数重载提供参考。 
    • 说明:const修饰函数参数,是一种编程规范的要求,便于阅读,一看即知这个参数不能被改变,实现时不易出错
  • extern有什么作用 ,extern标识的变量或者函数声明其定义在别的文件中,提示编译器遇到此变量和函数时在其它模块中寻找其定义。 
  • 流操作符重载为什么返回引用   在程序中,流操作符>>和<<经常连续使用。因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用。其他的数据类型都无法做到这一点。 
  • 简述指针常量与常量指针区别 
    • 指针常量是指定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变。常量指针是指定义了一个指针,这个指针指向一个只读的对象,不能通过常量指针来改变这个对象的值。 
    • 指针常量强调的是指针的不可改变性,而常量指针强调的是指针对其所指对象的不可改变性。 
    • 注意:无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数中的不可改变特性。 
  • 如何避免“野指针” 
    • 指针变量声明时没有被初始化。解决办法:指针声明时初始化,可以是具体的地址值,也可让它指向NULL。 
    • 指针 p 被 free 或者 delete 之后,没有置为 NULL。解决办法:指针指向的内存空间被释放后指针应该指向NULL。 
    • 指针操作超越了变量的作用范围。解决办法:在变量的作用域结束前释放掉变量的地址空间并且让指针指向NULL。 
    • 注意:“野指针”的解决方法也是编程规范的基本原则,平时使用指针时一定要避免产生“野指针”,在使用指针前一定要检验指针的合法性。 
  • 常引用有什么作用 
    • 常引用的引入主要是为了避免使用变量的引用时,在不知情的情况下改变变量的值。常引用主要用于定义一个普通变量的只读属性的别名、作为函数的传入形参,避免实参在调用函数中被意外的改变。 
    • 很多情况下,需要用常引用做形参,被引用对象等效于常对象,不能在函数中改变实参的值,这样的好处是有较高的易读性和较小的出错率。 
  • 构造函数能否为虚函数 
    • 构造函数不能是虚函数。而且不能在构造函数中调用虚函数,因为那样实际执行的是父类的对应函数,因为自己还没有构造好。析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的。析构函数也可以是纯虚函数,但纯虚析构函数必须有定义体,因为析构函数的调用是在子类中隐含的。
  • 谈谈你对面向对象的认识 
    • 面向对象可以理解成对待每一个问题,都是首先要确定这个问题由几个部分组成,而每一个部分其实就是一个对象。然后再分别设计这些对象,最后得到整个程序。传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象的角度来考虑问题。这样做能够使得程序更加的简洁清晰。 
  • 空结构体sizeof的返回值   sizeof(空类/空结构体) = 1; 空类,没有任何成员变量或函数,即没有存储任何内容;但是由于空类仍然可以实例化,一个类能够实例化,编译器就需给它分配内存空间,来指示类实例的地址。这里编译器默认分配了一个字节(如:char),以便标记可能初始化的类实例,同时使空类占用的空间也最少(即1字节)。
  • free和delete区别,free和mall匹配:释放malloc出来动态内存; delete和new匹配:释放new出来的动态内存空间。
    • new、delete 是操作符,可以重载,只能在C++中使用。 
    • malloc、free是函数,可以覆盖,C、C++中都可以使用。 
    • new 可以调用对象的构造函数,对应的delete调用相应的析构函数。 
    • malloc仅仅分配内存,free仅仅回收内存,并不执行构造和析构函数 
    • new、delete返回的是某种数据类型指针,malloc、free返回的是void指针。 
    • 它们都是只把指针所指向的内存释放掉了,并没有把指针本身干掉。在free和delete之后,都需要把指向清理内存的指针置为空,即p=NULL,否则指针指向的内存空间虽然释放了,但是指针p的值还是记录的那块地址,该地址对应的内存是垃圾,p就成了“野指针”。同样会使人认为p是个合法的指针,如果程序较长,我们通常在使用一个指针前会检查p!=NULL,这样就起不到作用了。此时如果再释放p指向的空间,编译器就会报错,因为释放一个已经被释放过的空间是不合法的。而将其置为NULL之后再重复释放就不会产生问题,因为delete一个0指针是安全的。
  • int i=1;sizeof(i++); i的值变为多少,sizeof是一个编译时刻就起效果的运算符,在其内的任何运算都没有意义,j = sizeof(i++); 在编译的时候被翻译成 j=sizeof((i++的数据类型)) 也就是 j = sizeof(int); 也就是 j= 4; (32bit系统,如果是16位系统,则j=2) 然后才会继续编译成最终的程序,当然在最终程序执行的时候,自然不会执行任何++i了。
  • 一个char跟int的结构体大小是多少。结构体内存对齐的规则【未指定#pragma pack时】a.第一个成员起始于0偏移处; b.每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐;
  • 构造函数可以抛出异常么?析构函数可以吗?                                                                                                                                                     从语法上来说,构造函数和析构函数都可以抛出异常。但从逻辑上和风险控制上,构造函数可以,析构函数不推荐抛出异常,构造函数可以抛出异常:无论何时,从构造函数中抛出异常都是可以的。动态创建对象要进行两个操作:分配内存和调用构造函数。若在分配内存时出错,会抛出bad_alloc异常。c++不推荐从析构函数中抛出异常,必须要求在析构函数内消化所有异常。因为析构函数可能在对象正常结束生命周期时调用,也可能在有异常发生时从函数堆栈清理时调用。前一种情况抛出异常不会有无法预料的结果,可以正常捕获;但后一种情况下,因为已经发生了异常而导致函数的局部变量的析构函数被调用,此时析构函数又抛出异常。在两个异常同时存在的情况下,异常处理机制只能调用terminate()。
  • C++ 只有explicit关键字,没有implicit关键字。编译器允许解析函数的参数时,对参数作隐式转换。也就是说,编译器能够使用带单个参数的构造函数,将函数参数转换为正确的类型。带有单个形参的构造函数定义了一种由实参类型到类类型的隐式转换由于无意中的隐式转换会隐藏bug, 这就是构造函数前面加explicit的原因。
  • 模板声明与定义要放在同一文件中?“通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。因此,最好的办法就是将模板的声明和定义都放置在同一个.h文件中。这就是为什么所有的STL头文件都包含模板定义的原因。”[1]"标准要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。https://blog.csdn.net/lqk1985/article/details/3136364因为C++标准明确表示,当一个模板不被用到的时 //侯它就不该被具现出来。编译没错,链接出错。找不到模块函数的实现。编译模版的定义cpp时如果该cpp中没有该模版的具体实例,那么该cpp中就不会处理和模块有关的代码。链接时就找不到模版函数的定义。
  • 模板特化和偏特化C++中的模板分为类模板和函数模板
  • 讲下虚函数的机制,C++中虚函数的唯一用处就是构成多态,C++提供多态的目的是:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。如果没有多态,我们只能访问成员变量。 前面我们说过,通过指针调用普通的成员函数时会根据指针的类型(通过哪个类定义的指针)来判断调用哪个类的成员函数,但是通过本节的分析可以发现,这种说法并不适用于虚函数,虚函数是根据指针的指向来调用的,指针指向哪个类的对象就调用哪个类的虚函数
  • 讲下虚继承,虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类
  • unsigned char a=-1,printf("%d",a)输出什么;255【-1的补码是11111111】
  • 访问类private成员的方法,比如编写单元测试,私有成员没有暴露接口。
  • std::string怎么实现的;线程安全吗,中间有'\0'时cout输出;用printf的输出,输出一样,都是遇到\0结束
  • 了解C++11吗,讲下auto关键字与类中的delete。 auto关键字实现自动类型推断,让编译器能够将变量的类型设置为初始值的类型,auto声明的变量必须要初始化,否则编译器不能判断变量的类型,auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响。另外,auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。
  • 智能指针的原理是什么? C++11有哪些智能指针?主要用来处理忘记delete或者程序运行中抛异常无法执行到delete等导致的内存泄露问题。简单来说即为将指针类型封装为对象,当其“彻底”消亡时将调用析构函数,从而自动地将其从堆中分配的内存释放掉,而不用去关心内存泄露的问题。两种智能指针 shared_ptr 和 unique_ptr, 还有一个名为weak_ptr的伴随类。shared_ptr, 共享所有权,允许多个指针指向同一个对象,其内部有一个关联的引用计数,用来记录有多少个其他的shared_ptr指向相同的对象,当引用计数为0时将调用析构函数释放对应空间。unique_ptr遵循独占语义,在任何时间点,资源只能唯一地被一个unique_ptr占有,当其离开作用域,所包含的资源被释放。weak_ptr解决shared_ptr循环引用时的bug
  • 讲讲函数参数是多个参数怎么传递,比如说printf的参数,怎么确定大小等,一个int printf%s会出什么情况。
  • gcc跟vs哪个比较熟,问了gdb的断点怎么实现的。C++里用过汇编语言吗。

2、操作系统

  • 请分别简单说一说进程和线程以及它们的区别。进程是具有一定功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源调度和分配的一个独立单位。线程是进程的实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程可以有多个线程,多个线程也可以并发执行
  • 线程同步的方式有哪些?互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
  • 说一说进程同步有哪几种机制,和进程同步的方式相同
  • 进程的通信方式有哪些?主要分为:管道、系统IPC(Inter-Process Communication,进程间通信,包括消息队列、信号量、共享存储)、SOCKET,管道主要分为:普通管道PIPE 、流管道(s_pipe)、命名管道(name_pipe),管道是一种半双工的通信方式,数据只能单项流动,并且只能在具有亲缘关系的进程间流动,进程的亲缘关系通常是父子进程命名管道也是半双工的通信方式,它允许无亲缘关系的进程间进行通信信号量是一个计数器,用来控制多个进程对资源的访问,它通常作为一种锁机制。消息队列是消息的链表,存放在内核中并由消息队列标识符标识。信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。共享内存就是映射一段能被其它进程访问的内存,这段共享内存由一个进程创建,但是多个进程可以访问。
  • 什么是缓冲区溢出?有什么危害?其原因是什么?缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。危害有以下两点:程序崩溃,导致拒绝额服务,跳转并且执行一段恶意代码,造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。 
  • 什么是死锁?死锁产生的条件?在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗的讲就是两个或多个进程无限期的阻塞、相互等待的一种状态。死锁产生的四个条件(有一个条件不成立,则不会产生死锁)互斥条件:一个资源一次只能被一个进程使用;请求与保持条件:一个进程因请求资源而阻塞时,对已获得资源保持不放;不剥夺条件:进程获得的资源,在未完全使用完之前,不能强行剥夺;循环等待条件:若干进程之间形成一种头尾相接的环形等待资源关系 
  • 说一说死锁的处理基本策略和常用方法。产生死锁的原因:(1)竞争系统资源 (2)进程的推进顺序不当产生死锁的必要条件产生死锁的必要条件互斥条件,请求和保持条件,不剥夺条件,环路等待条件;解决死锁的基本方法如下: 预防死锁【资源一次性分配:(破坏请求和保持条件),可剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件),资源有序分配法((破坏环路等待条件))】、避免死锁(系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。)、检测死锁(首先为每个进程和每个资源指定一个唯一的号码;然后建立资源分配表和进程等待表)、解除死锁剥夺资源从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。
    ) 。
  • 进程有哪几种状态?就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源;运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数;阻塞状态: 进程等待某种条件,在条件满足之前无法执行
  • 进程三种状态间的转换一个进程在运行期间,不断地从一种状态转换到另一种状态,它可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态。图3_4描述了进程的三种基本状态及其转换。(1) 就绪→执行处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态(2) 执行→就绪处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。(3) 执行→阻塞正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。(4) 阻塞→就绪处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
  • 操作系统中进程调度策略有哪几种?FCFS(先来先服务),短作业(进程)优先调度算法、优先级(优先权调度算法的类型【1、非抢占式优先权算法;2、抢占式优先权调度算法】,高响应比优先调度算法【等待时间与服务时间之和就是系统对该作业的响应时间】),时间片轮转(时间片轮转法、多级反馈队列调度算法)
  • 分页和分段有什么区别?段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定;段向用户提供二维地址空间;页向用户提供的是一维地址空间,段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制
  • 什么是内部碎片,什么是外部碎片?。内部碎片:已经被分配出去的的内存空间大于请求所需的内存空间。外部碎片:还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块
  • Window内存管理方式主要分为:页式管理、段式管理、段页式管理

    1、页式管理

               用户程序的逻辑地址空间被划分成若干固定大小的页,相应地,内存物理空间也分成相对应的若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,这些块不必连续,实现了离散分配。由于最后一页经常装不满一块而形成了不可利用的碎片,称之为“内碎片”。

              逻辑地址映射成物理地址的过程:页表寄存器中存放页表长度和页表起始地址,指令给出的地址包括页号和页内地址,用页号去索引页表,索引之前,先比较页号与页表长度,若页号大于等于页表长度,则发生越界中断,否则,将页表起始地址与页号相加可以得到该页在页表中的位置,进而得到对应的物理块地址,将物理块地址和页内地址相加即可得到物理地址。

            优点:没有外碎片,每个内碎片不超过页的大小,程序不必连续存放。

            缺点:要求程序全部装入内存,没有足够的内存,程序就不能执行。

                2、段式管理

               用户程序的逻辑地址空间被划分成若干大小不等的段,每段可以定义一组相对完整的逻辑信息,段的长度由相应的逻辑信息组的长度决定。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。

               逻辑地址映射成物理地址的过程:段表寄存器中存放段表长度和段表起始地址,指令给出的地址包括段号和段内地址,用段号去索引段表,索引之前,先比较段号与段表长度,若段号大于等于段表长度,则发生越界中断,否则,将段表起始地址与段号相加可以得到该段在段表中的位置,进而得到物理段地址,将物理段地址和段内地址相加即可得到物理地址。

                优点:每次交换的是一组相对完整的逻辑信息,而不像页式管理那样只交换固定大小的页从而需要多次缺页中断才能把信息完整地调入内存。

                 缺点:会产生外部碎片。

                 3、段页式管理

                  分页系统能有效地提高内存的利用率,而分段系统能反映程序的逻辑结构,将分页与分段结合起来,就形成了段页式管理方式。在段页式管理系统中,用户程序的逻辑地址空间首先被划分成若干个逻辑分段,每段都有自己的段号,然后再将每段分成若干个大小相等的页。

                  逻辑地址映射成物理地址的过程:段表寄存器中存放段表长度和段表起始地址,指令给出的地址包括段号、段内页号和页内地址,用段号去索引段表,段表中存放段号、页表长度、页表起始地址,索引之前,先比较段号与段表长度,若段号大于等于段表长度,则发生越界中断,否则,将段表起始地址与段号相加可以得到该段在段表中的位置,进而得到页表起始地址,将页表起始地址与段内页号相加可以得到对应的物理块地址,将物理块地址和页内地址相加即可得到物理地址。

                  优点:程序是以段为单位分割的,每个段内是连续的,但段间可以不连续;没有外碎片,能减少存储空间的浪费。

                  缺点:有内部碎片;由于管理软件的增加,复杂性和开销也随之增加。

  • 什么是虚拟内存?

       1、内存的发展历程

      没有内存抽象(单进程,除去操作系统所用的内存之外,全部给用户程序使用) —>

             有内存抽象(多进程,进程独立的地址空间,交换技术(内存大小不可能容纳下所有并发执行的进程) )—>

             连续内存分配(固定大小分区(多道程序的程度受限),可变分区(首次适应,最佳适应,最差适应),碎片) —>

             不连续内存分配(分段,分页,段页式,虚拟内存)
            2、虚拟内存允许执行进程不必完全在内存中。虚拟内存的基本思想是:每个进程拥有独立的地址空间,这个空间被分为大小相等的多个块,称为页(Page),每个页都是一段连续的地址。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立刻进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令。这样,对于进程而言,逻辑上似乎有很大的内存空间,实际上其中一部分对应物理内存上的一块(称为帧,通常页和帧大小相等),还有一些没加载在内存中的对应在硬盘上,
              注意,请求分页系统、请求分段系统和请求段页式系统都是针对虚拟内存的,通过请求实现内存与外存的信息置换。

  • 页面置换算法 ,FIFO先进先出算法:在操作系统中经常被用到,比如作业调度(主要实现简单,很容易想到);LRU(Least recently use)最近最少使用算法:根据使用时间到现在的长短来判断;LFU(Least frequently use)最少使用次数算法:根据使用次数来判断;OPT(Optimal replacement)最优置换算法:理论的最优,理论;就是要保证置换出去的是不再被使用的页,或者是在实际内存中最晚使用的算法。
  • 虚拟内存的应用与优点,虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把CPU交给另一个进程使用。虚拟内存的使用可以带来以下好处:在内存中可以保留多个进程,系统并发度提高,解除了用户与内存之间的紧密约束,进程可以比内存的全部空间还大。颠簸
  • 颠簸本质上是指频繁的页调度行为,具体来讲,进程发生缺页中断,这时,必须置换某一页。然而,其他所有的页都在使用,它置换一个页,但又立刻再次需要这个页。因此,会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸(抖动)。内存颠簸的解决策略包括:如果是因为页面替换策略失误,可以修改替换算法来解决这个问题;如果是因为运行的程序太多,造成程序无法同时将所有频繁访问的页面调入内存,则要降低多道程序的数量;否则,还剩下两个办法:终止该进程或增加物理内存容量。
  • 局部性原理(1). 时间上的局部性:最近被访问的页在不久的将来还会被访问;(2). 空间上的局部性:内存中被访问的页周围的页也很可能被访问。
  • 请阐述动态链接库与静态链接库的区别,静态链接库是.lib格式的文件,一般在工程的设置界面加入工程中,程序编译时会把lib文件的代码加入你的程序中因此会增加代码大小,你的程序一运行lib代码强制被装入你程序的运行空间,不能手动移除lib代码,动态链接库是程序运行时动态装入内存的模块,格式*.dll,在程序运行时可以随意加载和移除,节省内存空间。在大型的软件项目中一般要实现很多功能,如果把所有单独的功能写成一个个lib文件的话,程序运行的时候要占用很大的内存空间,导致运行缓慢;但是如果将功能写成dll文件,就可以在用到该功能的时候调用功能对应的dll文件,不用这个功能时将dll文件移除内存,这样可以节省内存空间。
  • 中断,所谓的中断就是在计算机执行程序的过程中,由于出现了某些特殊事情,使得CPU暂停对程序的执行,转而去执行处理这一事件的程序。等这些特殊事情处理完之后再回去执行之前的程序。中断一般分为三类:由计算机硬件异常或故障引起的中断,称为内部异常中断; 由程序中执行了引起中断的指令而造成的中断,称为软中断(这也是和我们将要说明的系统调用相关的中断); 由外部设备请求引起的中断,称为外部中断。简单来说,对中断的理解就是对一些特殊事情的处理。 与中断紧密相连的一个概念就是中断处理程序了。当中断发生的时候,系统需要去对中断进行处理,对这些中断的处理是由操作系统内核中的特定函数进行的,这些处理中断的特定的函数就是我们所说的中断处理程序了。另一个与中断紧密相连的概念就是中断的优先级。中断的优先级说明的是当一个中断正在被处理的时候,处理器能接受的中断的级别。中断的优先级也表明了中断需要被处理的紧急程度。每个中断都有一个对应的优先级,当处理器在处理某一中断的时候,只有比这个中断优先级高的中断可以被处理器接受并且被处理。优先级比这个当前正在被处理的中断优先级要低的中断将会被忽略。典型的中断优先级如下所示:机器错误 > 时钟 > 磁盘 > 网络设备 > 终端 > 软件中断 ,当发生软件中断时,其他所有的中断都可能发生并被处理;但当发生磁盘中断时,就只有时钟中断和机器错误中断能被处理了。
  • 系统调用   在讲系统调用之前,先说下进程的执行在系统上的两个级别:用户级和核心级,也称为用户态和系统态(user mode and kernel mode)。程序的执行一般是在用户态下执行的,但当程序需要使用操作系统提供的服务时,比如说打开某一设备、创建文件、读写文件等,就需要向操作系统发出调用服务的请求,这就是系统调用。Linux系统有专门的函数库来提供这些请求操作系统服务的入口,这个函数库中包含了操作系统所提供的对外服务的接口。当进程发出系统调用之后,它所处的运行状态就会由用户态变成核心态。但这个时候,进程本身其实并没有做什么事情,这个时候是由内核在做相应的操作,去完成进程所提出的这些请求。系统调用和中断的关系就在于,当进程发出系统调用申请的时候,会产生一个软件中断。产生这个软件中断以后,系统会去对这个软中断进行处理,这个时候进程就处于核心态了。
  • 那么用户态和核心态之间的区别是什么呢?(以下区别摘至《UNIX操作系统设计》)用户态的进程能存取它们自己的指令和数据,但不能存取内核指令和数据(或其他进程的指令和数据)。然而,核心态下的进程能够存取内核和用户地址 ,某些机器指令是特权指令,在用户态下执行特权指令会引起错误 ,对此要理解的一个是,在系统中内核并不是作为一个与用户进程平行的估计的进程的集合,内核是为用户进程运行的。

4 、计算机网络

  • Http和Https的区别,Http协议运行在TCP之上,明文传输,客户端与服务器端都无法验证对方的身份;Https是身披SSL(Secure Socket Layer)外壳的Http,运行于SSL上,SSL运行于TCP之上,是添加了加密和认证机制的HTTP。二者之间存在如下不同:端口不同:Http与Http使用不同的连接方式,用的端口也不一样,前者是80,后者是443;资源消耗:和HTTP通信相比,Https通信会由于加减密处理消耗更多的CPU和内存资源;开销:Https通信需要证书,而证书一般需要向认证机构购买; Https的加密机制是一种共享密钥加密和公开密钥加密并用的混合加密机制。
  • 对称加密与非对称加密:对称密钥加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方;而非对称加密是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,它非常的慢,所以我们还是要用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。
  • TCP的三次握手与四次挥手

           第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认

           第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

           第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

           第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

           第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。此时TCP链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。

          第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态

          第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

  • 为什么TCP链接需要三次握手,两次不可以么,为什么?为了防止 已失效的链接请求报文突然又传送到了服务端,因而产生错误。客户端发出的连接请求报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到链接释放以后的某个时间才到达Server。这是,Server误以为这是Client发出的一个新的链接请求,于是就向客户端发送确认数据包,同意建立链接。若不采用“三次握手”,那么只要Server发出确认数据包,新的链接就建立了。由于client此时并未发出建立链接的请求,所以其不会理睬Server的确认,也不与Server通信;而这时Server一直在等待Client的请求,这样Server就白白浪费了一定的资源。若采用“三次握手”,在这种情况下,由于Server端没有收到来自客户端的确认,则就会知道Client并没有要求建立请求,就不会建立链接。
  • TCP协议如何来保证传输的可靠性,TCP提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信;而字节流服务意味着两个应用程序通过TCP链接交换8bit字节构成的字节流,TCP不在字节流中插入记录标识符。对于可靠性,TCP通过以下方式进行保证:数据包校验,目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;对失序数据包重排序,既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;丢弃重复数据,对于重复数据,能够丢弃重复数据;应答机制,当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;超时重发,当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
  • 客户端不断进行请求链接会怎样?DDos(Distributed Denial of Service)攻击?服务器端会为每个请求创建一个链接,并向其发送确认报文,然后等待客户端进行确认。DDos 攻击:客户端向服务端发送请求链接数据包,服务端向客户端发送确认数据包客户端不向服务端发送确认数据包,服务器一直等待来自客户端的确认。DDos 预防 ( 没有彻底根治的办法,除非不使用TCP )限制同时打开SYN半链接的数目,缩短SYN半链接的Time out 时间,关闭不必要的服务
  • 计算机网络七层协议:OSI(open system interconnect开放系统互联)七层模型:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。对等层之间不能相互直接通信,各层之间是严格单向依赖,上层使用下层提供的服务,下层向上层提供服务。                                                                           

          1.物理层(比特bit):通过媒介传输比特,确定机械及电气规范。规定如何为网络通信实现最底层的物理连接。如:如何使用电缆和接头的类型、用来传送信号的电压等。物理层实际上是一种规定,规定物理媒介设备在连接网络时的各种规格、参数以及工作方式。
物理媒介(网线,电缆)不属于物理层,双绞线,线缆等物理媒介等是物理层的实现。

          2.数据链路层(帧frame):将比特组装成帧和点到点的连接。规定了如何进行物理地址寻址,如何在物理线路上进行数据(帧frame)的可靠传递以及流量控制。协议有SLIP协议,CSLIP协议,PPP协议等。交换机工作在数据链路层,对帧解码并根据帧中包含的信息把数据发送到正确的接收方。
           3.网络层(包packet):负责数据包从源到宿的传递和网际互连。

           4.传输层(段segment):提供端到端的可靠报文段和错误恢复。TCP UDP协议

           5.会话层(会话协议数据单元SPDU):在网络中的两个节点之间建立、维持和终止通信。

           6.表示层(表示协议数据单元PPDU):对数据进行翻译、加密、解密和压缩,在应用程序和网络之间对数据进行格式化,使之能够被另一方理解,即发送方的表示层将应用程序数据的抽象语法转换成网络适用于OSI网络传输的传送语法,接收方则相反。

           7.应用层(应用协议数据单元APDU):允许访问OSI环境的手段,最顶层的OSI层,为应用程序提供网络服务。如为电子邮件、文件传输功能提供协议支持应用层协议有HTTP协议、FTP协议、SMTP协议等

           https://blog.csdn.net/taotongning/article/details/81352985

           集线器工作在 OSI  模型的物理层,网卡工作在 OSI  模型的物理层,交换机工作在数据链路层,路由器工作在网络层。

  • TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议,它们之间的区别包括:TCP是面向连接的,UDP是无连接的;TCP是可靠的,UDP是不可靠的;TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多的通信模式;TCP是面向字节流的,UDP是面向报文的;TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;
  • TCP的拥塞处理,计算机网络中的带宽、交换结点中的缓存及处理机等都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏,这种情况就叫做拥塞。拥塞控制就是 防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。注意,拥塞控制和流量控制不同,前者是一个全局性的过程,而后者指点对点通信量的控制拥塞控制的方法主要有以下四种:1). 慢启动不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小;2). 拥塞避免拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。3). 快重传快重传要求接收方在收到一个 失序的报文段 后就立即发出 重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。4). 快恢复快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半,但是接下去并不执行慢开始算法:因为如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
  • 从输入网址到获得页面的过程。1). 浏览器查询 DNS,获取域名对应的IP地址:具体过程包括浏览器搜索自身的DNS缓存、搜索操作系统的DNS缓存、读取本地的Host文件和向本地DNS服务器进行查询等。对于向本地DNS服务器进行查询,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析(此解析具有权威性);如果要查询的域名不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析(此解析不具有权威性)。如果本地域名服务器并未缓存该网址映射关系,那么将根据其设置发起递归查询或者迭代查询;(2). 浏览器获得域名对应的IP地址以后,浏览器向服务器请求建立链接,发起三次握手;(3). TCP/IP链接建立起来后,浏览器向服务器发送HTTP请求;(4). 服务器接收到这个请求,并根据路径参数映射到特定的请求处理器进行处理,并将处理结果及相应的视图返回给浏览器;(5). 浏览器解析并渲染视图,若遇到对js文件、css文件及图片等静态资源的引用,则重复上述步骤并向服务器请求这些资源;(6). 浏览器根据其请求到的资源、数据渲染页面,最终向用户呈现一个完整的页面
  • Session、Cookie 与 Application。Cookie和Session都是客户端与服务器之间保持状态的解决方案,具体来说,cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie,而客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器,服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。同样地,会话状态也可以保存在服务器端。客户端请求服务器,如果服务器记录该用户状态,就获取Session来保存状态,这时,如果服务器已经为此客户端创建过session,服务器就按照sessionid把这个session检索出来使用;如果客户端请求不包含sessionid,则为此客户端创建一个session并且生成一个与此session相关联的sessionid,并将这个sessionid在本次响应中返回给客户端保存。保存这个sessionid的方式可以采用 cookie机制 ,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器;若浏览器禁用Cookie的话,可以通过 URL重写机制 将sessionid传回服务器。ApplicationApplication(Java Web中的ServletContext):与一个Web应用程序相对应,为应用程序提供了一个全局的状态,所有客户都可以使用该状态。
     
  • Session 与 Cookie 的对比,实现机制,Session的实现常常依赖于Cookie机制,通过Cookie机制回传SessionID;大小限制:Cookie有大小限制并且浏览器对每个站点也有cookie的个数限制,Session没有大小限制,理论上只与服务器的内存大小有关;安全性:Cookie存在安全隐患,通过拦截或本地文件找得到cookie后可以进行攻击,而Session由于保存在服务器端,相对更加安全;服务器资源消耗:Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。
  • SQL 注入,SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。SQL注入攻击的总体思路(1). 寻找到SQL注入的位置 (2). 判断服务器类型和后台数据库类型 (3). 针对不同的服务器和数据库特点进行SQL注入攻击
  • XSS 攻击,XSS是一种经常出现在web应用中的计算机安全漏洞,与SQL注入一起成为web中最主流的攻击方式。XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些脚本代码嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
  • TCP和UDP分别对应的常见应用层协议。TCP对应的应用层协议:FTP:定义了文件传输协议,使用21端口。常说某某计算机开了FTP服务便是启动了文件传输服务。下载文件,上传主页,都要用到FTP服务。Telnet:它是一种用于远程登陆的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是-纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。SMTP:定义了简单邮件传送协议,现在很多邮件服务器都用的是这个协议,用于发送邮件。如常见的免费邮件服务中用的就是这个邮件服务端口,所以在电子邮件设置-中常看到有这么SMTP端口设置这个栏,服务器开放的是25号端口。POP3:它是和SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。也是说,只要你有相应的使用POP3协议的程序(例如Fo-xmail或Outlook),就可以不以Web方式登陆进邮箱界面,直接用邮件程序就可以收到邮件(如是163邮箱就没有必要先进入网易网站,再进入自己的邮-箱来收信)。HTTP:从Web服务器传输超文本到本地浏览器的传送协议。
  • UDP对应的应用层协议。DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。TFTP(Trival File Transfer Protocal):简单文件传输协议,该协议在熟知端口69上使用UDP服务。
  • 网络层的ARP协议工作原理,网络层的ARP协议完成了IP地址与物理地址的映射首先,每台主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址的对应关系。当源主机需要将一个数据包要发送到目的主机时,会首先检查自己ARP列表中是否存在该IP地址对应的MAC地址:如果有,就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个ARP响应数据包,告诉对方自己是它需要查找的MAC地址;源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
  • B/S架构与C/S架构的区别,架构,即大家熟知的客户机和服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。那么常见的C/S架构和B/S架构有什么区别?                    CS架构,就是你的电脑,需要装个软件,才能连接服务器。而BS架构,就是你的电脑,只需要用浏览器,就可以连接服务器了

              C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。C/S 架构也可以看做是胖客户端架构。因为客户端需要实现绝大多数的业务逻辑和界面展示。这种架构中,作为客户端的部分需要承受很大的压力,因为显示逻辑和事务处理都包含在其中,通过与数据库的交互(通常是SQL或存储过程的实现)来达到持久化数据,以此满足实际项目的需要。

            C/S 架构的优缺点,优点:1.C/S架构的界面和操作可以很丰富。2.安全性能可以很容易保证,实现多层认证也不难。3.由于只有一层交互,因此响应速度较快。缺点:1.适用面窄,通常用于局域网中。2.用户群固定。由于程序需要安装才可使用,因此不适合面向一些不可知的用户。3.维护成本高,发生一次升级,则所有客户端的程序都需要改变。

            B/S架构的全称为Browser/Server,即浏览器/服务器结构。Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现,Browser客户端,WebApp服务器端和DB端构成所谓的三层架构。B/S架构的系统无须特别安装,只有Web浏览器即可。B/S架构中,显示逻辑交给了Web浏览器,事务处理逻辑在放在了WebApp上,这样就避免了庞大的胖客户端,减少了客户端的压力。因为客户端包含的逻辑很少,因此也被成为瘦客户端。

  • IP地址的分类,IP地址是指互联网协议地址,是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP地址编址方案将IP地址空间划分为A、B、C、D、E五类,其中A、B、C是基本类,D、E类作为多播和保留使用,为特殊地址。A类地址:以0开头,第一个字节范围:0~127;B类地址:以10开头,第一个字节范围:128~191;C类地址:以110开头,第一个字节范围:192~223;D类地址:以1110开头,第一个字节范围为224~239;E类地址:以1111开头,保留地址
  • IP地址与物理地址,物理地址是数据链路层和物理层使用的地址,IP地址是网络层和以上各层使用的地址,是一种逻辑地址,其中ARP协议用于IP地址与物理地址的对应。
  • 常见状态码及原因短语,HTTP请求结构: 请求方式 + 请求URI + 协议及其版本 ;HTTP响应结构: 状态码 + 原因短语 + 协议及其版本,1×× : 请求处理中,请求已被接受,正在处理;2×× : 请求成功,请求被成功处理 200 OK;3×× : 重定向,要完成请求必须进行进一步处理 301 : 永久性转移 302 :暂时性转移 304 : 已缓存;4×× : 客户端错误,请求不合法 400:Bad Request,请求有语法问题 403:拒绝请求 404:客户端所访问的页面不存在;5×× : 服务器端错误,服务器不能处理合法请求 500 :服务器内部错误 503 : 服务不可用,稍等 ;
  • GET和POST也是HTTP协议中的两种方法。HTTP全称为Hyper Text Transfer Protocol,中文翻译为超文本传输协议,目的是保证浏览器与服务器之间的通信。HTTP的工作方式是客户端与服务器之间的请求-应答协议。                                                                                       HTTP协议中定义了浏览器和服务器进行交互的不同方法,基本方法有4种,分别是GET,POST,PUT,DELETE。这四种方法可以理解为,对服务器资源的查,改,增,删。                                                                                                                                                 GET交互方式是从服务器上获取数据,而并非修改数据,所以GET交互方式是安全的。就像数据库查询一样,从数据库查询数据,并不会影响数据库的数据信息,对数据库来说,也就是安全的。                                                                                                                 GET:从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改。POST:向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据。

 3、数据结构

  • 数组和链表的区别。
    • 从逻辑结构上来看,数组必须实现定于固定的长度,不能适应数据动态增减的情况,即数组的大小一旦定义就不能改变。当数据增加是,可能超过原先定义的元素的个数;当数据减少时,造成内存浪费;链表动态进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。
    • 从内存存储的角度看;数组是一块连续的空间,声明时就要确定长度。链表是一块可不连续的动态空间,长度可变,每个结点要保存相邻结点指针。 
    • 从访问方式类看,数组在内存中是连续的存储,因此可以利用下标索引进行访问;链表是链式存储结构,在访问元素时候只能够通过线性方式由前到后顺序的访问,所以访问效率比数组要低。
    • 数据插入或删除:链表可以快速插入和删除结点,而数组则可能需要大量数据移动。 
    • 越界问题:链表不存在越界问题,数组有越界问题。
  • 简述队列和栈的异同 
    • 队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是“先进先出”,栈是“后进先出”。 
    • 注意:区别栈区和堆区。堆区的存取是“顺序随意”,而栈区是“后进先出”。栈由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。 
    • 它与本题中的堆和栈是两回事。堆栈只是一种数据结构,而堆区和栈区是程序的不同内存存储区域。 、                                                                      
  • 简述快速排序过程
    • 选择一个基准元素,通常选择第一个元素或者最后一个元素,
    • 通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的元素值比基准值大。
    • 此时基准元素在其排好序后的正确位置
    • 然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。
  • 快速排序的改进
    • 对于分治算法,当每次划分时,算法若都能分成两个等长的子序列时,那么分治算法效率会达到最大
  • 各类排序算法对比
    • 时间复杂度来说:
      • (1)平方阶(O(n2))排序:各类简单排序:直接插入、直接选择和冒泡排序;
      • 线性对数阶(O(nlog2n))排序:快速排序、堆排序和归并排序;
      • O(n1+§))排序,§是介于0和1之间的常数。希尔排序
      • 线性阶(O(n))排序:基数排序,此外还有桶、箱排序。
      • 当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。
    • 稳定性:
      • 排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序,这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对次序发生了改变,则称该算法是不稳定的。
      • 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排
      •  不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序
  • 邻接矩阵与邻接表:
    • 邻接矩阵表示法:在一个一维数组中存储所有的点,在一个二维数组中存储顶点之间的边的权值
    • 邻接表表示法:图中顶点用一个一维数组存储,图中每个顶点vi的所有邻接点构成单链表
    • 对比:
      • 在邻接矩阵表示中,无向图的邻接矩阵是对称的。矩阵中第 i 行或 第 i 列有效元素个数之和就是顶点的度。在有向图中 第 i 行有效元素个数之和是顶点的出度,第 i 列有效元素个数之和是顶点的入度。
      • 在邻接表的表示中,无向图的同一条边在邻接表中存储的两次。如果想要知道顶点的度,只需要求出所对应链表的结点个数即可。有向图中每条边在邻接表中只出现一次,求顶点的出度只需要遍历所对应链表即可。求入度则需要遍历其他顶点的链表。
      • 邻接矩阵与邻接表优缺点:邻接矩阵的优点是可以快速判断两个顶点之间是否存在边,可以快速添加边或者删除边。而其缺点是如果顶点之间的边比较少,会比较浪费空间。因为是一个 n∗n 的矩阵。而邻接表的优点是节省空间,只存储实际存在的边。其缺点是关注顶点的度时,就可能需要遍历一个链表。
  • 用循环比递归效率高吗?递归和循环两者完全可以互换。不能完全决定性地说循环地效率比递归的效率高。
    • 递归算法:
      • 优点:代码简洁、清晰,并且容易验证正确性。
      • 缺点:它的运行需要较多次数的函数调用,如果调用层数比较深,需要增加额外的堆栈处理(还有可能出现堆栈溢出的情况),比如参数传递需要压栈等操作,会对执行效率有一定影响。但是,对于某些问题,如果不使用递归,那将是极端难看的代码。在编译器优化后,对于多次调用的函数处理会有非常好的效率优化,效率未必低于循环。
    • 循环算法:
      • 优点:速度快,结构简单。
      • 缺点:并不能解决所有的问题。有的问题适合使用递归而不是循环。如果使用循环并不困难的话,最好使用循环。

 

 

 

 

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值