m.erase(mi++);
}
else++mi;
}
}
编译器的相关知识
在《编译原理》中我们可以了解到一个编译器对程序代码的编译主要分为下面几个过程:
a)词法分析b)语法分析c)语义分析d)中间代码生成e)代码优化f)代码生成g)符号表管理h)将多个步骤组合成趟i)编译器构造工。
一、编译器的概念
编译器是将一种计算机语言翻译为另一种计算机语言的程序。
编译器将源程序(source language)
编写的程序作为输入,翻译产生用目标语言(target language)编写的等价程序。
源程序一般为高级语言(high-level language),如Pascal 或Delphi,而目标语言则是汇编语言或目标机器的目标代码(object code),有时也称作机器代码(machine code)
源程序→ 编译器→ 目标程序
解释器也是同编译器一样的一种语言翻译程序。
它与编译器的不同之处在于:
它立即执行源程序而不是生成目标代码。
从原理上讲,任何程序设计语言都可以被解释或被编译。
二、编译器的组成部分
(1) 扫描程序(scanner)
在这个阶段编译器实际阅读源程序(通常以字符流的形式表示)。
扫描程序执行词法分析(Lexicalanalysis):
它将字符序列收集到称作记号(token)的有意义单元中,记号同自然语言,如英语中的字词相似。
因此可以认为扫描程序执行与拼写相似的任务。
(2) 语法分析程序(parser)
语法分析程序从扫描程序中获取记号形式的源代码,并完成定义程序结构的语法分析(syntaxanalysis),这与自然语言中句子的语法分析类似。
语法分析定义了程序的结构元素及其关系。
通常将语法分析的结果表示为分析树( parsetree)或语法树(syntaxtree)。
(3) 语义分析程序(semanticanalyzer)
程序的语义就是它的“意思”,它与语法或结构不同。
程序的语义确定程序的运行,但是大多数的程序设计语言都具有在执行之前被确定而不易由语法表示和由分析程序分析的特征。
这些特征被称作静态语义( staticsemantic),而语义分析程序的任务就是分析这样的语义(程序的“动态”语义具有只有在程序执行时才能确定的特性,由于编译器不能执行程序,所以它不能由编译器来确定)。
一般的程序设计语言的典型静态语义包括声明和类型检查。
由语义分析程序计算的额外信息(诸如数据类型)被称为属性( attribute),它们通常是作为注释或“装饰”增加到树中(还可将属性添加到符号表中)。
(4) 源代码优化程序(sourcecodeoptimizer)
编译器通常包括许多代码改进或优化步骤。
绝大多数最早的优化步骤是在语义分析之后完成的,而此时代码改进可能只依赖于源代码。
这种可能性是通过将这一操作提供为编译过程中的单独阶段指出的。
每个编译器不论在已完成的优化种类方面还是在优化阶段的定位中都有很大的差异。
(5) 代码生成器(codegenerator)
代码生成器得到中间代码(IR,并生成目标机器的代码。
尽管大多数编译器直接生成目标代码,但是为了便于理解,本书用汇编语言来编写目标代码。
正是在编译的这个阶段中,目标机器的特性成为了主要因素。
当它存在于目标机器时,使用指令不仅是必须的而且数据的形式表示也起着重要的作用。
例如,整型数据类型的变量和浮点数据类型的变量在存储器中所占的字节数或字数也很重要。
C++中的空类,默认产生哪些类成员函数?
classEmpty
{
public:
Empty();//缺省构造函数
Empty(constEmpty&);//拷贝构造函数
~Empty();//析构函数
Empty&operator=(constEmpty&);//赋值运算符
Empty*operator&();//取址运算符
constEmpty*operator&()const;//取址运算符const
};
默认构造函数
析构函数
拷贝构造函数
赋值运算符(operator=)
取址运算符(operator&)(一对,一个非const的,一个const的)
TCP/IP整体构架概述
TCP/IP协议并不完全符合OSI的七层参考模型。
传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。
该模型的目的是使各种硬件在相同的层次上相互通信。
这7层是:
物理层、数据链路层、网路层、传输层、话路层、表示层和应用层。
而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
这4层分别为:
应用层:
应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
传输层:
在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
互连网络层:
负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
网络接口层:
对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、SerialLine等)来传送数据。
TCP/IP中的协议
以下简单介绍TCP/IP中的协议都具备什么样的功能,都是如何工作的:
1.IP网际协议IP是TCP/IP的心脏,也是网络层中最重要的协议。
IP层接收由更低层(网络接口层例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层---TCP或UDP层;相反,IP层也把从TCP或UDP层接收来的数据包传送到更低层。
IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是按顺序发送的或者没有被破坏。
IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。
高层的TCP和UDP服务在接收数据包时,通常假设包中的源地址是有效的。
也可以这样说,IP地址形成了许多服务的认证基础,这些服务相信数据包是从一个有效的主机发送来的。
IP确认包含一个选项,叫作IPsourcerouting,可以用来指定一条源地址和目的地址之间的直接路径。
对于一些TCP和UDP的服务来说,使用了该选项的IP包好象是从路径上的最后一个系统传递过来的,而不是来自于它的真实地点。
这个选项是为了测试而存在的,说明了它可以被用来欺骗系统来进行平常是被禁止的连接。
那么,许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。
2.TCP
如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。
TCP将包排序并进行错误检查,同时实现虚电路间的连接。
TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。
应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
面向连接的服务(例如Telnet、FTP、rlogin、XWindows和SMTP)需要高度的可靠性,所以它们使用了TCP。
DNS在某些情况下使用TCP(发送和接收域名数据库),但使用UDP传送有关单个主机的信息。
3.UDP
UDP与TCP位于同一层,但对于数据包的顺序错误或重发。
因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询---应答的服务,例如NFS。
相对于FTP或Telnet,这些服务需要交换的信息量较小。
使用UDP的服务包括NTP(网落时间协议)和DNS(DNS也使用TCP)。
欺骗UDP包比欺骗TCP包更容易,因为UDP没有建立初始化连接(也可以称为握手)(因为在两个系统间没有虚电路),也就是说,与UDP相关的服务面临着更大的危险。
4.ICMP
ICMP与IP位于同一层,它被用来传送IP的的控制信息。
它主要是用来提供有关通向目的地址的路径信息。
ICMP的‘Redirect’信息通知主机通向其他系统的更准确的路径,而‘Unreachable’信息则指出路径有问题。
另外,如果路径不可用了,ICMP可以使TCP连接‘体面地’终止。
PING是最常用的基于ICMP的服务。
5.TCP和UDP的端口结构
TCP和UDP服务通常有一个客户/服务器的关系,例如,一个Telnet服务进程开始在系统上处于空闲状态,等待着连接。
用户使用Telnet客户程序与服务进程建立一个连接。
客户程序向服务进程写入信息,服务进程读出信息并发出响应,客户程序读出响应并向用户报告。
因而,这个连接是双工的,可以用来进行读写。
两个系统间的多重Telnet连接是如何相互确认并协调一致呢?
TCP或UDP连接唯一地使用每个信息中的如下四项进行确认:
源IP地址发送包的IP地址。
目的IP地址接收包的IP地址。
源端口源系统上的连接的端口。
目的端口目的系统上的连接的端口。
端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。
一个端口对应一个16比特的数。
服务进程通常使用一个固定的端口,例如,SMTP使用25、Xwindows使用6000。
这些端口号是‘广为人知’的,因为在建立与特定的主机或服务的连接时,需要这些地址和目的地址进行通讯。
三次握手:
1.确认目的设备存在于网络上;
2.确认目的设备有活动的服务,并且正在源客户端要使用的目的端口号上接受请求;
3.通知目的设备源客户端想要在该端口号上建立通信会话。
三次握手
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:
建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:
服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:
未连接队列:
在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。
这些条目所标识的连接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。
Backlog参数:
表示未连接队列的最大容纳数目。
SYN-ACK重传次数服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同。
半连接存活时间:
是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。
有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
(1)第一次握手:
建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
(2)第二次握手:
服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3)第三次握手:
客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
图1TCP三次握手建立连接
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。
这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。
收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。
首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。
和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
TCP采用四次挥手关闭连接如图2所示。
图2 TCP四次挥手关闭连接
1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。
但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
MySQL的操作
一、显示命令
1、显示当前数据库服务器中的数据库列表:
mysql>SHOWDATABASES;
注意:
mysql库里面有MYSQL的系统信息,我们改密码和新增用户,实际上就是用这个库进行操作。
2、显示数据库中的数据表:
mysql>USE库名;
mysql>SHOWTABLES;
3、显示数据表的结构:
mysql>DESCRIBE表名;
4、建立数据库:
mysql>CREATEDATABASE库名;
5、建立数据表:
mysql>USE库名;
mysql>CREATETABLE表名(字段名VARCHAR(20),字段名CHAR
(1));
6、删除数据库:
mysql>DROPDATABASE库名;
7、删除数据表:
mysql>DROPTABLE表名;
8、将表中记录清空:
mysql>DELETEFROM表名;
9、显示表中的记录:
mysql>SELECT*FROM表名;
10、往表中插入记录:
mysql>INSERTINTO表名VALUES(”hyq”,”M”);
11、更新表中数据:
mysql->UPDATE表名SET字段名1=’a',字段名2=’b’WHERE字段名3=’c';
12、用文本方式将数据装入数据表中:
mysql>LOADDATALOCALINFILE“D:
/mysql.txt”INTOTABLE表名;
13、导入.sql文件命令:
mysql>USE数据库名;
mysql>SOURCEd:
/mysql.sql;
14、命令行修改root密码:
mysql>UPDATEmysql.userSETpassword=PASSWORD(’新密码’)WHEREUser=’root’;
mysql>FLUSHPRIVILEGES;
15、显示use的数据库名:
mysql>SELECTDATABASE();
16、显示当前的user:
mysql>SELECTUSER();
二、一个建库和建表以及插入数据的实例
dropdatabaseifexistsschool;//如果存在SCHOOL则删除
createdatabaseschool;//建立库SCHOOL
useschool;//打开库SCHOOL
createtableteacher//建立表TEACHER
(
idint(3)auto_incrementnotnullprimarykey,
namechar(10)notnull,
addressvarchar(50)default‘深圳’,
yeardate
);//建表结束
//以下为插入字段
insertintoteachervalues(”,’allen’,'大连一中’,'1976-10-10′);
insertintoteachervalues(”,’jack’,'大连二中’,'1975-12-23′);
如果你在MySQL提示符键入上面的命令也可以,但不方便调试。
(1)你可以将以上命令原样写入一个文本文件中,假设为school.sql,然后复制到c:
\下,并在DOS状态进入目录[url=file:
//\mysql\bin]\mysql\bin[/url],然后键入以下命令:
mysql-uroot-p密码\school.sql
如果成功,空出一行无任何显示;如有错误,会有提示。
(以上命令已经调试,你只要将//的注释去掉即可使用)。
(2)或者进入命令行后使用mysql>sourcec:
\school.sql;也可以将school.sql文件导入数据库中。
三、将文本数据转到数据库中
1、文本数据应符合的格式:
字段数据之间用tab键隔开,null值用[url=file:
//\n]\n[/url]来代替.例:
3rose大连二中1976-10-10
4mike大连一中1975-12-23
假设你把这两组数据存为school.txt文件,放在c盘根目录下。
2、数据传入命令loaddatalocalinfile“c:
\school.txt”intotable表名;
注意:
你最好将文件复制到[url=file:
//\mysql\bin]\mysql\bin[/url]目录下,并且要先用use命令打表所在的库。
四、备份数据库:
(命令在DOS的[url=file:
//\mysql\bin]\mysql\bin[/url]目录下执行)
1.导出整个数据库
导出文件默认是存在mysqlbin目录下
mysqldump-u用户名-p数据库名>导出的文件名
mysqldump-uuser_name-p123456database_name>outfile_name.sql
2.导出一个表
mysqldump-u用户名-p数据库名表名>导出的文件名
mysqldump-uuser_name-pdatabase_nametable_name>outfile_name.sql
3.导出一个数据库结构
mysqldump-uuser_name-p-d–add-drop-tabledatabase_name>outfile_name.sql
-d没有数据–add-drop-table在每个create语句之前增加一个droptable
4.带语言参数导出
mysqldump-uroot-p–default-character-set=latin1–set-charset=gbk–skip-optdatabase_name>outfile_name.sql
Memset初始化类对象需要注意
void*memset(void*s,intv,size_tn);
英文释义如下:
Copiesthevaluev(convertedtotype