C++常用基础知识点总结<一>

1,指针和引用的区别总结:
(1),指针有自己的一块空间,而引用只是一个别名;
(2),使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
(3),指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象的引用;
(4),作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用的修改都会改变引用所指向的对象;
(5),指针在使用中可以指向其他对象,但是引用只能是一个对象的引用,不能被改变;
(6),指针可以有多级指针,而引用只有一级;
(7),指针和引用使用++运算符的意义不一样;
(8),如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏;

2,socket,TCP/IP网络编程
socket(套接字)编程有3种
流式套接字(SOCK_STREAM),
数据报套接字(SOCK_DGRAM),
原始套接字(SOCK_RAW)。
基于TCP的socket编程是采用的流式套接字。

服务器端编程的步骤
(1),加载套接字库,创建套接字(WSAStarup()/socket());
(2),绑定套接字到一个IP地址和一个端口上(bind());
(3),将套接字设置为监听模式等待连接请求(listen());
(4),请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
(5),用返回的套接字和客户端进行通信(send/recv());
(6),返回,等待另一个连接;
(7),关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

客户端编程的步骤:
(1),加载套接字库,创建套接字(WSAStartup/socket());
(2),向服务器发出连接请求(connect());
(3),和服务器进行通信(send/recv())
(4),关闭套接字,关闭加载的套接字库(closesocket/WSACleanup())。

3,重写,重载,重定义,这样的好处是什么?
重载:是相同的作用域,相同的函数名,参数列表不同。与返回值无关,属于静态多态。
重载的作用:重载函数通常用来在同一个作用域内,用同一个函数名命名一组功能相似的函数,这样减少了函数名的数量,避免了名字空间污染,对于程序的可读性有很大的好处。
重写:也叫覆盖。子类重新定义父类中有相同名称和参数的虚函数。函数特征相同,但具体实现不同,主要是在继承关系中出现的。
重写需要注意:
(1),被重写的函数不能是static的,必须是virtual的;
(2),重写函数必须有相同的类型,名称和参数列表。
(3),重写函数的访问修饰符可以不同。尽管virtual是private的,派生类中重写改写为public,protect也是可以的。
重写(多态)的作用:接口重用。
重定义:也叫隐藏。子类重新定义父类中有相同名称的非虚函数(参数列表可以不同)。如果一个类,存在和父类相同的函数,那么这个类将会覆盖其父类的方法,除非在调用的时候强制转换为父类类型,否则试图对子类和父类做类似重载的调用是不能成功的。

4,重入函数和不可重入函数,线程安全
重入:同一个函数被不同的执行流程调用,当前资格流程还没有执行完,就有其他的进程已经再次调用(执行流之间的相互嵌套执行);
可重入:多个流程反复执行一个代码,其结果不会发生改变,通常访问的都是各自的私有资源;
不可重入:多个执行流反复执行一段代码,其结果会发生改变;
可重入函数:当一个执行流因为异常或者被内核切换而中断正在执行的函数而转为另一个执行流时,当后者的执行流对同一个函数的操作并不影响前一个执行流恢复后执行函数产生的结果;

不可重入函数:当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时中断转而进入你内核,这个时候有一个信号需要被处理,而处理这个信号的时候又会重新调用刚才中断的函数,如果函数内部有一个全局变量需要被操作,那么,当信号处理完成之后重新返回用户态中断函数的上下文再次继续执行的时候,对同一个全局变量的操作结果可能就会发生改变而并不如我们预期的那样,这样的函数被称为不可重入函数。
可重入函数满足的条件:
(1),不使用全局变量或静态变量;
(2),不使用用malloc或者new开辟出的空间;
(3),不调用不可重入函数;
(4),不返回静态或全局数据,所有数据都有函数的调用者提供;
(5),使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。
不可重入函数符合以下条件之一:
(1),调用了malloc/free函数,因为malloc函数是用全局链表来管理的;
(2),调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构;
(3),可重入体内使用了静态的数据结构

线程安全:简单来说线程安全就是多个线程并发同一段代码时,不会出现不同的结果,我们就说线程是安全的。
线程不安全:如果多线程并发执行同一段代码时会产生不同的结果,则该线程就是不安全的。
线程不安全产生的原因:大多是因为对全局变量和静态变量的操作。
常见的线程不安全的函数
(1),不保护共享变量的函数;
(2),函数状态随着被调用,状态发生变化的函数;
(3),返回指向静态变量指针的函数;
(4),调用线程不安全函数的函数。
常见的线程安全的情况:
(1),每个线程对全局变量或者静态变量只有读取的权限,而没有写入的权限,一般来说线程是安全的;
(2),类或者接口对于线程来说都是原子操作;
(3),多个线程之间的切换不会导致该接口的执行结果存在二义性。

5,static成员变量和成员函数。
static成员变量:
(1),属于类,不属于某个具体的对象,即使创建多个对象,也只为其分配一份内存,所有对象使用的都是这份内存中的数据。
(2),static成员变量必须初始化,而且只能在类声明的外部初始化。初始化时可以赋值,也可以不赋值,那么会被默认初始化为0。具体形式为:
type class::name=value;
(3),静态成员变量在初始化时不能再加static,但必须要有数据类型。被private,protect,public修饰的静态成员变量都可以用这种方式初始化。
注意:static成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。没有在类外初始化的static成员变量不能使用。
(4),static成员变量既可以通过对象来访问,也可以通过类来访问。但要遵循private,protect,public关键字的访问权限限制。当通过对象名访问时,对于不同对象,访问的是同一份内存。
注意:static成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问。static成员变量和普通static变量类似,都在内存分区中的全局数据区分配内存,到程序结束时才释放。static成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。
而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
(5),一个类中可以有一个或多个静态成员变量,所有的对象都可以共享这些静态成员变量,都可以引用它。
static成员函数:
(1),静态成员函数只能访问静态成员。
(2),静态成员函数可以通过类来直接调用,编译器不会为他增加形参this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。
(3),静态成员函数不能访问普通成员变量,只能访问静态成员变量。
(4),静态成员函数与普通成员函数的根本区别在于:普通成员函数有this指针,可以访问类中的任意成员;而静态成员函数没有this指针,只能访问静态成员。
(5),C++中,静态成员函数主要目的是访问静态成员。

6,const成员变量,成员函数,对象。
const成员变量:
(1),const成员变量和普通const变量的用法相似,只需要在声明时加上const关键字。
(2),初始化const成员变量只有一种方法,就是通过构造函数的初始化列表。
const成员函数:
(1),可以使用类中所有成员变量,但是不能修改它们的值。也称为常成员函数。
(2),通常将get函数设置为常成员函数。
(3),需要强调的是:必须在成员函数的声明和定义处同时加强const关键字。
const常对象:
对象定义为常对象后,就只能调用类的const成员(包括const成员变量和const成员函数。)

7,友元函数和友元类
友元函数:
(1),在当前类以外定义的,不属于当前类的函数也可以在类中声明,但要在前面加friend关键字。
友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。
(2),友元函数可以访问当前类中的所有成员,包括public,protect,private。
(3),一个函数可以被多个类声明为友元函数,这样就可以访问多个类中的private

友元类:
(1),友元类中的所有成员函数,都是另一个类的友元函数。
(2),友元的关系是单向的,而不是双向的。如果声明了类B是类A的友元类,不等于类A是类B的友元类。类B可以访问类A的所有成员,类A不能访问类B的private成员
(3),友元的关系不能传递。如果类B是类A的友元,类C是类B的友元,不等于类C是类A的友元类。
(4),除非有必要,一般不建议把整个类声明为友元类,而只是将某些成员函数声明为友元函数。

8,C++虚函数注意事项及构成多态的条件
虚函数注意事项:
(1),只要在虚函数的声明处加上virtual关键字,函数定义处可加可不加;
(2),只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽关系的同名函数都将自动成为虚函数;
(3),当在基类中定义了虚函数,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数;
(4),只有派生类的虚函数覆盖基类的虚函数(函数原型相同),才能构成多态(通过基类指针访问派生类函数)。
(5),构造函数不能是虚函数。对于基类的构造函数,它仅仅是在派生类构造函数中被调用,派生类不继承基类的构造函数,将构造函数声明为虚函数没什么意义
(6),析构函数可以声明为虚函数
构成多态的条件:
(1),必须存在继承关系;
(2),继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)
(3),存在基类 类型的指针或引用,通过该指针或引用调用虚函数。

9,STL泛型模版
STL的基本组件:
容器,迭代器,函数对象,算法
迭代器(iterator)是算法和容器的桥梁。
容器用于存放数据的类模版。容器中可以存放基本类型的变量,也可以存放对象。对象或基本类型的变量被插入容器中时,实际插入的是对象或变量的一个复制品。

容器分为两大类:顺序容器和关联容器。
顺序容器:
可变长动态数组vector,
双端队列deque,
双向链表list。
因为元素在容器中的位置同元素的值无关,即容器不是排序的。将元素插入容器时,指定在什么位置(尾部,头部或中间某处)插入,元素就会位于什么位置,所以称之为顺序容器。
关联容器:
set,multiset,map,multimap。
关联容器内的元素是排序的。插入元素时,容器会按一定的顺序规则将元素放到适当的位置上,因此插入元素时不能指定位置。
除了以上两类容器外,STL还在两类容器的基础上屏蔽一部分功能,突出或增加另一部分功能,实现了三种容器适配器:
栈stack,队列queue,优先级队列priority_queue。
所有容器都有以下两个成员函数:
int size():返回容器对象中元素的个数。
bool empty():判断容器对象是否为空。

顺序容器和关联容器还有以下成员函数:
begin():返回指向容器中第一个元素的迭代器。
end():返回指向容器中最后一个元素后面的位置的迭代器。
rbegin():返回指向容器中最后一个元素的反向迭代器。
rend():返回指向容器中第一个元素前面的位置的反向迭代器。
erase(…):从容器中删除一个或几个元素。该函数参数较复杂
clear():从容器中删除所有元素。
如果一个容器是空的,则begin()和end()的返回值相等,rbegin()和rend()的返回值也相等。
顺序容器还有以下常用成员函数:
front():返回容器中第一个元素的引用。
back():返回容器中最后一个元素的引用
push_back():在容器末尾增加新元素。
pop_back():删除容器末尾的元素。
insert(…):插入一个或多个元素。

10,虚拟内存分为哪几部分?各部分存储什么内容?
C++虚拟内存分为:代码段,数据段,BBS段,堆区,栈区,文件映射区六部分。
代码段:包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码。
数据段:存储程序中已经初始化的全局变量和静态变量。
BBS段:存储未初始化的全局变量和静态(局部+全局),以及所有被初始化为0的全局变量和静态变量。
堆区:调用new/malloc函数时在堆区动态分配内存,同时需要调用delete/free来手动释放申请的内存。
栈区:使用栈空间存储函数的返回地址,参数,局部变量,返回值。
映射区:存储动态链接库以及调用mmap函数进行的文件映射。

11,什么是内存泄漏?什么叫内存溢出?
什么是内存越界?什么是栈溢出?
内存泄漏:是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成的内存浪费。

内存泄漏分类
(1),堆内存泄漏:堆内存指的是程序运行中根据需要分配的一段内存,完成后必须通过调用delete/free删掉,如果没有及时释放,那么此后这段内存将不会被使用,就会产生Heap Leak。
(2),系统资源泄漏:主要指程序使用系统分配的资源,比如Bitmap、handle,socket等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。
(3),没有将基类的析构函数定义为虚函数。当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源的资源没有正确释放,因此造成内存泄漏。
内存溢出:是指程序在申请内存时没有足够的内存空间供其使用。
原因可能如下:
(1),内存中加载的数据过于庞大;
(2),代码中存在死循环;
(3),递归调用太深,导致堆栈溢出等;
(4),内存泄漏最终导致内存溢出。
内存越界:是指向系统申请一块内存后,使用时却超出申请范围。比如一些操作内存的函数:sprintf,strcpy,strcat,vsprintf,memcpy,memset,memmove。当造成内存泄漏的代码运行时,所带来的错误是无法避免的,通常会造成:
(1),破坏了堆中内存分配信息数据;
(2),破坏了程序其他对象的内存空间;
(3),破坏了空闲内存块。
栈溢出(缓冲区溢出):程序为了临时存取数据的需要,一般会分配一些内存空间称为缓冲区。如果向缓冲区中写入缓冲区无法容纳的数据,机会造成缓冲区以外的存储单元被改写,称为缓冲区溢出。而栈溢出是缓冲区溢出的一种,原理相同。分为上溢出和下溢出。上溢出是指栈满而又向其增加新的数据,导致数据溢出;下溢出是指空栈而又进行删除操作等,导致空间溢出。

12,浅拷贝和深拷贝
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝的指针是指向两个不同地址的指针。
当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应考虑以下情形:
(1),当函数的参数为对象时,实参传递给形参的实际上是实参的一个拷贝对象,系统自动通过拷贝构造函数实现;
(2),当函数的返回值为一个对象时,该对象实际上是函数内对象的一个拷贝,用于返回函数调用处;
(3),当用一个已创建的对象,初始化一个同类型的对象时,实际上是用已创建对象的拷贝对象初始化,系统自动通过拷贝构造函数实现;
(4),浅拷贝带来问题的本质在于析构函数释放多次堆内存,使用std::shared_ptr,可以完美解决这个问题。

13,多线程,多进程编程
区别:进程是操作系统资源分配的最小单位;
线程是任务调度和执行的基本单位。
在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计算器,线程之间切换的开销小。
所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
内存分配方面:系统在运行的时候为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的医院来自其所属进程的资源),线程组之间只能共享资源。
包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或轻量级进程。

14,线程间通讯
(1)全局变量
(2),自定义消息
(3),IO完成端口
(4),生产者-消费者模式

15,进程间通信(IPC)
(1),管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与他有共同祖先的进程之间通信。
(2),命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3),信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction。
(4),消息队列(Message):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5),共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率低而设计的。往往与其他通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6),信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
(7),套接字(Socket):更为一般的进程通信机制,可用于不同机器之间的进程间通信。起初是由Uinx系统的BSD分支开发出来的,但现在一般可以移植到其他Uinx系统上;Linux和System V的变种都支持套接字。

16,sizeof和strlen的区别
(1),sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
(2),sizeof是运算符,strlen是函数。
(3),sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以“\0”结尾的
sizeof还可以用函数做参数。
(4),数组做sizeof的参数不退化,传递给strlen就退化成指针了。
(5),大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度。这就是sizeof(x)可以用来定义数组维数的原因。
(6),strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,不是类型占内存的大小。
(7),sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
(8),当使用了一个结构类型或变量时,sizeof返回实际的大小,当使用一静态地址空间数组,sizeof返回全部数组的尺寸。sizeof操作符不能返回被动态分配的数组或外部的数组的尺寸。

17,mallo()/free(),new()/delete()的区别
相同点:
(1),new/delete和malloc/free都可以动态分配内存和释放内存。
(2),delete和free都不能重复释放内存
(3),delete和free都可以释放空指针。
不同点:
(1),new/delete是C++的运算符,编译时需要加参数,malloc/free是C语言中的函数,编译时需要头文件的支持。
(2),new返回指定类型的指针,并且可以自动计算所需要大小,而malloc则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。
(3),malloc只管分配内存,并不能对所得内存进行初始化,而new可以对所得到的内存进行初始化。
(4)new在分配内存失败时会抛出异常,而malloc在分配失败的时候会返回NULL
(5),new会调用构造函数,而malloc不会调用构造函数。
(6),delete会调用析构函数,而free不会调用析构函数。
(7),new/delete都可以被重载,而malloc/free都不可以被重载。

18,作用域和生命周期
作用域:是一个变量可以被引用的范围。
生命周期:这个变量被引用的时间段。
全局变量:
作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件)
生命周期:程序运行期一直存在
引用方法:其他文件中要使用必须用extern关键字声明要引用的全局变量
内存分布:全局数据区
注意:如果在两个文件中都定义了相同名字的全局变量,连接出错:变量重定义

全局静态变量
作用域:文件作用域(只在被定义的文件中可见)
生命周期:程序运行期一直存在
内存分布:全局数据区
定义方法:static关键字,const关键字
注意:只要文件不互相包含,在两个不同的文件中是可以定义完全相同的两个静态变量的,他们是两个完全不同的变量。

静态局部变量
作用域:局部作用域(只在局部作用域中可见)
生命周期:程序运行期一直存在
内存分布:全局数据区
定义方法:局部作用域中用static定义
注意:只被初始化一次,多线程中需加锁保护

局部变量
作用域:局部作用域(只在局部作用域中可见)
生命周期:程序运行出局部作用域即被销毁
内存分布:栈区
注意:auto指示符标示

19,TCP和UDP的相同点和不同点有哪些?
(1),TCP面向连接;UDP是无连接的,即发送数据前不需要建立连接。
(2),TCP提供可靠的服务。通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;
UDP尽最大努力交付,即不保证可靠交付。
(3),TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;
UDP是面向报文的。
(4),每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
(5),TCP首部开销20字节;UDP的首部开销小,只有8字节。
(6),TCP的逻辑通信信道是全双工的可靠信道;UDP则是不可靠信道。

20,三次握手,四次分手。Seq,Ack
三次握手过程:
(1),服务器端处于监听状态时,客户端调用connect函数后,TCP协议会组建一个数据包,并设置SYN标志位。同时生成一个随机数字a,填充“序号Seq”,表示该数据包的序号,客户端将该数据包发送给服务器端,请求连接;
(2),服务器端收请求连接数据包,检测到SYN标志位,就知道该包是建立连接的“请求包”。服务器端也会组建一个数据包,并设置SYN和ACK标志位,SYN表示该数据包用来建立连接,ACK用来确认收到了刚才发来的请求连接数据包。
服务器端生成一个随机数b,填充“序号Seq”字段,b和客户端数据包没有关系;
服务器端将客户端数据包序号a,加1,得到a+1,并用这个数字填充“确认号Ack”字段。
(3),客户端收到数据包,检测到SYN和ACK标志位,知道该数据包是服务器发来的“确认包”。客户端会检测“确认号Ack”的值是否为a+1,如果是就说明连接成功。
客户端会继续组建数据包,并设置ACK标志位,表示客户端正确接收到了服务器端发来的“确认包”。同时,将刚发来的数据包序号b加1,得到b+1,用这个数字来填充“确认号Ack”字段。客户端将该数据包发送后,进入ESTABLISED状态。
(4),服务器端接收到数据包,检测到ACK标志位,知道是客户端发来的“确认包”。服务器会检测“确认号Ack”字段的值是否为b+1,如果是则连接成功,服务器进入ESTABLISED状态。
服务器端和客户端都进入ESTABLISED状态后,建立连接成功,接下来就可以发送数据了。
四次分手:
(1),客户端调用close函数后,向服务器端发送设置有FIN标志位,会生成一个随机数a,填充“序号Seq”字段,的数据包。进入FIN_WAIT_1状态;
(2),服务器收到数据包后,检测到设置FIN标志位,知道要断开连接。服务器端组建数据包:设置ACK标志位,随机生成一个数字b填充“序号Seq”字段,服务器端将客户端序号a加1,得到a+1填充“确认号Ack”字段。将这个确认数据包发送给客户端,进入CLOSE_WAIT状态。
(3),客户端收到确认包后,检查确认号的值是否为a+1,如果是,则进去CLOSE_WAIT_2状态。
(4),等待片刻后,服务器端准备好后,组建数据包:设置有FIN标志位,
上次随机生成的数字b加1,得到b+1,填充“序号Seq”字段,
上次确认号a+1的值填充“确认号Ack”字段。服务器端将该数据包发送给客户端后,进入LAST_ACK状态。

(5),客户端收到服务器端的数据包后,组建数据包:设置有ACK标志位,
将服务器端发来的数据包,确认号a+1填充“序号Seq”字段,
将服务器端发来的数据包,序号b+1再加1,得到b+2填充“确认号Ack”字段。
客户端将该ACK包发送给服务器端后,进入TIME_WAIT状态。
(6),服务器端收到客户端ACK包后,就断开连接,关闭套接字,进入CLOSE状态

21,TCP数据传输过程,序号Seq的值和确认号Ack的值之间的关系:
Ack号=Seq号+传递的字节数+1
在这里插入图片描述
在这里插入图片描述
22,,printf,sprintf,fprintf
相同点:将格式化字符串输出。
printf:是把格式化字符串输出到标准输出(一般是屏幕)
函数原型
int printf(const char* format……)
调用格式
printf()函数的调用格式为:printf(“格式化字符串”,输出列表)
格式化字符串包含三种对象,分别为
(1),字符串常量;
(2),格式控制字符串;
(3),转义字符

sprintf:是把格式化字符串输出到指定字符串,所以参数比printf多了个char*,那就是目标字符串的地址
函数原型:
int sprintf(char* buffer, const char* format,.……)

fprintf:是把格式化字符串输出到指定文件中,所以参数比printf多了个文件指针File*,那是目标文件的文件描述符(文件流指针)

23,C++必须使用初始化列表初始化的情况:
类对象构造顺序
1,分配内存,调用构造函数时,隐式/显示的初始化各数据成员;
2,进入构造函数后在构造函数中执行一般赋值与计算。

使用初始化列表的原因:
1,类成员为const类型;
2,类成员为引用类型;
3,类成员为没有默认构造函数的类类型;
4,如果类存在继承关系,派生类必须在其初始化列表中调用基类的构造函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值