数据结构

数据结构分类

逻辑结构

集合结构 线性结构 树形结构 图形结构

线性结构

顺序存储结构 链式存储结构

指针与数组

指针 内存与地址 指针的语法 使用指针变量 函数与参数传递 数组 结构型数据类型 数组定义与初始化 数组与指针 数组的抽象数据类型 动态内存管理 关键词new 和delete 避免内存错误

链表

单向链表 单向链表的结构 单向链表的操作算法 有序链表的合并算法 单向循环链表 单向循环链表的结构 单向循环链表的实现 约瑟夫环的问题 魔术师发牌问题 拉丁方阵的问题 双向循环链表 双向循环链表的结构 双向循环链表的实现 维吉尼亚加密法问题 游标类的设计与实现 游标类的结构 游标类的实现 遍历 元素的插入与删除 先进先出与后进先出 排队的智慧 优先级队列–兼谈页面置换算法

集合与字典

集合的概念,运算,实现 位向量集合 单链表集合 字典 字典的概念 搜索运算 散列 散列的概念 散列函数 字符串散列 处理散列冲突 不相交集 不相交集的概念 不相交集的实现 犯罪团伙的问题 路径压缩的实现 STL 中的set

算法

算法复杂度 (O(n)渐进表示法) 时间复杂度 空间复杂度

递归

递归的概念,定义,原则,递归和非递归的转化 分治法 分治法简述 汉诺塔问题 传染病问题 回溯法 回溯法简述 迷宫问题 八皇后问题 树 花开二枝分外香–二叉树及相关算法 二叉树的定义 二叉树的性质 二叉树的实现 二叉树的遍历算法 二叉树线索化算法 从树到森林 树的存储表示 树的实现 树与森林的遍历算法 森林与二叉树的转换 哈夫曼树–***优二叉树编码算法 哈夫曼编码 构造哈夫曼树 哈夫曼编码的实现 堆 堆的概念 堆的建立 堆的操作 图 图的存储与表示 图的邻接矩阵表示 图的邻接表表示 两种表示法的比较 图的遍历 欧拉路径与欧拉回路 哈密尔顿路径与哈密尔顿回路 广度优先遍历算法 深度优先遍历算法 最短短路径问题 固定起点***短路径问题 非固定起点***短路径问题 ***短路径的动态规划解法 图的最小生成树 图的最小生成树的定义 克鲁斯卡尔算法 普里姆算法 树形搜索结构 二叉搜索树 二叉搜索树的概念 二叉搜索树的操作 二叉搜索树的实现 二叉搜索树的分析 自平衡的二叉搜索树–**L 树 **L 树的概念 **L 树的旋转 **L 树的实现 树中亦有”红与黑” 红黑树的概念 红黑树的操作 红黑树的实现 基于Trie 树的单词检索 Trie 树的概念 Trie 树的表示 Trie 树的实现

排序

插入排序 直接插入排序 二分插入排序 希尔排序 选择排序 直接选择排序 堆排序 交换排序 冒泡排序 鸡尾酒排序 快速排序 归并排序 计数排序 线性表 顺序表(增,删,查,改,销毁) 静态顺序表 动态顺序表 链表(增,删,查,改,销毁) 单链表 无头双链表 有头单链表 双链表 无头双链表 有头双链表 无头循环双链表 有头循环双链表 三链表 链表的逆序 无头链表的删除和插入 链表带环问题 栈和队列 栈和队列的创建 栈和队列的初始化 栈的增容 入栈,出栈,入队,出队 取得栈顶,队头和队尾元素 求栈和队列的大小,判断栈和队列是否为空 栈 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作 顺序队列 顺序栈 链式栈 栈的应用 队列 循环队列 优先级队列 队列的应用 树形结构 节点 节点的度 叶节点 分支节点 祖先节点 双亲节点 兄弟节点 孩子节点 树的深度 树的表示方法 双亲表示法 孩子表示法 双亲孩子表示法 孩子兄弟表示法 树的存储形式 二叉树 二叉树的存储 顺序存储结构 链式存储结构 二叉树的基本操作 二叉树的创建 二叉树的遍历(递归和非递归) 前序遍历 中序遍历 后序遍历 后序遍历 二叉树的增、删、查、改、销毁 线索化二叉树 堆 堆的概念,创建 大堆 小堆 堆的插入和删除 堆的应用 优先级队列 海量数据top K问题 堆排序(高校排序算法) huffman树 搜索 线性查找 顺序查找:从前往后依次遍历O(n) 顺序有序查找:二分查找O(log(N)) 索引顺序表 树形查找 二叉树结构 二叉搜索树 平衡树 AVL树 红黑树 多叉树结构 B-树 B+树 B*树 哈希查找 哈希表 哈希冲突及解决方法 哈希函数 哈希冲突——开散列 哈希冲突——闭散列 哈希表变形 哈希表变形——位图 哈希表变形——布隆过滤器 排序 插入排序 直接插入排序 希尔排序 选择排序 选择排序 堆排序 交换排序 冒泡排序 快速排序 归并排序

字符串与模式匹配

文本的匹配 BF 算法 MP 算法 KMP 算法 BM 算法 BMH 算法 文本的模糊匹配 全局编辑距离 局部***佳对准 N 元距离模型

面向对象

面向对象说到底就是一种思想,任何事物都可以看作是一个对象,称之为OOP(Object Oriented Programming)。 面向对象就是把一个人或事务的属性,比如名字,年龄这些定义在一个实体类里面。存和取的时候直接使用存取实体类就把这个人的名字,年龄这些全部存了,这个实体类就叫对象,这种思想就叫面向对象。 特征:抽象,继承,多态。 优点:模块化便于维护,复用性强,可靠性和灵活性,可读性和可扩展性。 访问修饰符 public:公开,访问无限制 internal:本项目内可以访问 internal protected:本项目的父子类可以访问 C# 7.2之后有protected internal protected:子类可以访问 private:受保护的,只能在奔类中使用,对外完全封闭 多态的理解 解释:同一操作作用于不同的对象,实现不同的结果。 作用:增强代码的灵活性,重用性,可读性 实现:通过派生类,覆写基类的虚方法、重写基类的override方法。 构造函数 概念:构造函数的方法名与类型相同、没有返回类型 作用:完成对类的对象初始化 创建一个类的新对象时,系统会自动调用该构造函数初始化新对象, 如果没有写定义,那么系统会自动提供一个不带任何参数的public 构造函数 重写和重载的区别 重写方法:关键字用override修饰,派生类重写基类的方法,方法命名、返回类型,参数必须相同, 重载方法:方法名必须相同,参数列表必须不相同,返回类型可以不相同。 作用:重写主要是实现面向对象的多态性、重载主要是实现实例化不同的对象 class和struct的异同? 相同点: 都可以实现接口 不同点: 1.class是引用类型,struct是值类型 2.class允许继承、被继承,struct不允许,只能继承接口 3.class可以初始化变量,struct不可以 4.class可以有无参的构造函数,struct不可以,必须是有参的构造函数,而且在有参的构造函数必须初始化所有成员 使用场景: 1.Class比较适合大的和复杂的数据,表现抽象和多级别的对象层次时。Struct适用于作为经常使用的一些数据组合成的新类型,表示诸如点、矩形等主要用来存储数据的轻量级对象时,偏简单值。 2.Struct有性能优势,Class有面向对象的扩展优势。 构造函数是否能被重写? 构造器Constructor不能被继承,因此不能重写,但可以被重载 7.简述一下面向对象的三大特性 封装、继承、多态。 封装:是通过把对象的属性的实现细节隐藏起来,仅对外提供公共的访问方法。 继承:是通过子类继承基类、继承抽象类、继承接口实现的。 多态:是通过重写基类的override 方法、重写虚方法实现的。 好处是,方便维护、易扩展。 缺点是:比面向过程性能低。 抽象类和接口有什么区别? 相同点:都不能直接实例化 1.抽象类用abstract修饰、接口用interface修饰 2.抽象类中的方法可以实现,也可以不实现,有抽象方法的类一定要用abstract修饰,接口中的方法不允许实现 3.抽象类只能单继承,接口支持多继承 4.抽象类有构造方法,接口不能有构造方法 5.接口只负责功能的定义,通过接口来规范类的,(有哪些功能),而抽象类即负责功能的定义有可以实现功能(实现了哪些功能) 类的执行顺序 执行顺序:父类,子类,静态块,静态字段,非静态块,非静态字段,构造器,方法 接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实现类(concrete class)? 接口可以继承接口,抽象类可以实现接口,抽象类可以继承实现类,但前提是实现类必须有明确的构造函数。 谈谈你对设计模式的认识?结合你用得最多的一种设计模式说说它的使用。 什么是匿名类,有什么好处 匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型。 类型名由编译器生成,并且不能在源代码级使用。 每个属性的类型由编译器推断。可结合使用 new 运算符和对象初始值设定项创建匿名类型。 var v = new { Amount = 108, Message = “Hello” }; 有哪些引用类型,有哪些值类型,有什么区别 引用类型:类、接口、委托、字符串、数组 值类型:整形、浮点型、结构体、枚举、bool 值类型和引用类型的区别在于,值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址,即对象的引用。 默认值,值类型是0,引用类型null。 C#中有没有静态构造函数,如果有是做什么用的? 有. 特点: 静态构造函数既没有访问修饰符,也没有参数。 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。 无法直接调用静态构造函数。在程序中,用户无法控制何时执行静态构造函数。 用途: 当类使用日志文件时,将使用这种构造函数向日志文件中写入项。 怎样理解静态变量?静态成员和非静态成员的区别? 静态变量属于类,而不属于对象;并对所有对象所享;静态成员在加类的时候就被加载。 在项目中为什么使用接口?接口的好处是什么?什么是面向接口开发? 接口是一种约束,描述类的公共方法/公共属性,不能有任何的实现 好处是:结构清晰,类之间通信简单易懂,扩展性好,提高复用性。 面向接口开发就是指面向抽象协议编程,实现者在实现时 属性能在接口中声明吗? 可以,不能有访问修饰符,不能初始化赋值。 什么时候用重载?什么时候用重写? 当一个类需要用不同的实现来做同一件事情,此时应该用重写,而重载是用不同的输入做同一件事情 静态方法可以访问非静态变量吗?如果不可以为什么? 静态方法和非静态变量不是同一生命周期,静态方法属于类,非静态变量属于具体的对象,静态方法和具体的对象没有任何关联 IOC容器IOC即控制反转,是一种设计思想,在之前的项目中,当我们需要一个对象时,需要new一个对象,而IOC的设计思想是我们将需要的对象注入到一个容器中,就会获得我们所需要的资源 。 IOC和DI IOC是控制反转,DI是依赖注入,控制反转的解释有些模棱两可,而依赖注入就很明确,我们将需要的对象注入到容器中,获取所需要的资源。 IOC控制反转:正常情况下程序开发是上端调用下端,依赖下端,依赖倒置原则告诉我们,上端不要依赖下端,要依赖抽象,上端只依赖抽象,细节交给第三方工厂(容器)来决定,这就是IOC,就是控制反转——使系统架构可以更稳定,支持扩展。 AOP(Aspect Oriented Programming),意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

面向对象设计原则

**1. 单一职责原则(Single Responsibility Principle)**每一个类应该专注于做一件事情。 **2. 里氏替换原则(Liskov Substitution Principle)**超类存在的地方,子类是可以替换的。 **3. 依赖倒置原则(Dependence Inversion Principle)**实现尽量依赖抽象,不依赖具体实现。 **4. 接口隔离原则(Interface Segregation Principle)**应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。 **5. 迪米特法则(Law Of Demeter)**又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。 **6. 开闭原则(Open Close Principle)**面向扩展开放,面向修改关闭。 **7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)**尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。

UML

在UML的定义中,描述类和对象之间的关系,包括以下几种方式:依赖(Dependency)、关联(Association)、聚合(Aggregation)、组合(Composition)、泛化(Generalization)和实现(Realization)。现分别说明如下: 1. 依赖(Dependency) 在uml中,“依赖”表示为带箭头的虚线,箭头指向被依赖的元素。是类与类之间的连接,表示为一个类依赖于另一个类的定义,其中一个类的变化将影响另一个类。依赖总是单向的,不应该存在双向依赖,这一点要特别注意。更具体的说,依赖可以理解为:一个类(A)对不在其实例作用域内的另一个类或对象(B)的任何类型的引用。大致包含以下几种情况: (1)局部变量; (2)方法的参数; (3)静态方法的调用;        下面是依赖关系的uml示意图: 2. 关联(Association) 在uml中,关联表示为带箭头的实线。关联可以是单向的,也可以是双向的。如果是双向关联,则可以表示为双向箭头,或者没有箭头。一般来说,系统设计应表现为单向关联,这样利于维护。一个关联可以附加“多重性”的修饰符,表示两个类之间的数量关系。关联可以理解为:一个类(A)持有另一个类或对象(B)。具体表现为: (1)成员变量 下面是关联关系的uml示例图: 上面的关联表示,一个Employee持有(has)0个或多个TimeCard。 3. 聚合(Aggregation) 在uml中,聚合关系表示为空心的菱形箭头线。聚合关系是关联关系的一种,表示一种“强”关联关系。对比与关联关系,两个类是处于同一个层次的。而聚合关系,两个类处于不同的层次,强调了一个整体/局部的关系。例如一辆汽车有一个引擎,4个轮胎。 在聚合关系中,体现了一种“弱拥有”的概念。也就是说,对象A拥有对象B,但B并不是A的组成部分。更具体的表现为,如果A由B聚合而成,则A包含B的全局对象,但B对象可以不在A对象创建时创建。回到前面的例子,汽车对象由轮胎对象聚合而成,但是轮胎对象的生命期并不受汽车对象的左右。当汽车对象销毁时,轮胎对象也可以单独存在! 下面是聚合关系的uml示意图: 从代码上看,聚合和关联没有任何区别。这里仅仅体现一种概念上的含义。在创建ClassA的时候,不一定需要同时创建ClassB的实例。 4. 组合(Composition) 在uml中,组合关系表示为实心菱形箭头线。组合也叫合成。合成关系强调了比聚合关系更加强的整体/部分的关联,例如人和四肢。和聚合关系所不同的是,在组合关系中,虽然局部不一定随着整体的销毁而销毁,但整体要么负责保持局部的存活状态,要么负责将其销毁。也就是说,组合关系中,局部的存活期一定是小于,最多是等于整体的存活期的。 下面是组合关系的uml示例图: ** ** 5. 泛化(Generalization)与实现(Realization) 泛化也就是通常所谓的继承关系,在uml中表示为一个带空心三角的实线。表示为is-a的关系,是对象间耦合度最大的一种关系,子类继承父类的所有细节,并可以在此基础上添加自己的特性。 下面是泛化关系的uml图: 所谓实现就是对接口的定义实现,很简单。表现为带箭头的虚线。下面的实现的uml图: 类图基本符号可拆分为虚线,箭头,实线,空心右三角,实心右三角,空心菱形和实心菱形。由这些基本的图形进行组合构成了类图的基本符号。这里要注意这几个符号的顺序,代表了类与类之间关系的耦合程度。越向右耦合度越高。 其中虚线+箭头是表示即依赖的关系 依赖关系: 是一种使用的关系,  即一个类的实现需要另一个类的协助, 所以要尽量不使用双向的互相依赖.   指C5可能要用到C6的一些方法,也可以这样说,要完成C5里的所有功能,一定要有C6的方法协助才行。C5依赖于C6的定义,一般是在C5类的头文件中包含了C6的头文件。ROSE对依赖关系不产生属性。 形式上一般是A中的某个方法把B的对象作为参数使用(假设A依赖于B)。 实线+箭头表示关联的关系 关联关系: 是一种拥有的关系, 可以分为双向关联, 单向关联和自身关联.
双向关联是指双方都拥有对方的引用, 都可以调用对方的公共属性和方法. 单向关联是指只有某一方拥有另一方的引用, 这样只有拥有对方者可以调用对方的公共属性和方法. 自身关联是指拥有一个自身的引用.   C3->C4:表示相识关系,指C3知道C4,C3可以调用C4的公共属性和方法。没有生命期的依赖。一般是表示为一种引用。 实线+空心右三角表示的是泛化,即类的继承关系。 如果两个类存在泛化的关系时就使用,例如父和子,动物和老虎,植物和花等。  泛化关系: 是一种继承关系, 表示一般与特殊的关系, 它指定了子类如何特化父类的所有特征和行为. 实现(Realization) 实现关系: 是一种类与接口的关系, 表示类是接口所有特征和行为的实现 泛化和实现的区别就在于子类是否继承了父类的实现, 如有继承则关系为泛化, 反之为实现. 实线+空心菱形表示的是聚合的关系 聚合:表示C9聚合C10,但是C10可以离开C9而独立存在(独立存在的意思是在某个应用的问题域中这个类的存在有意义。) 实线+实心菱形则表示组合的关系 组合(也有人称为包容):一般是实心菱形加实线箭头表示,如上图所示,表示的是C8被C7包容,而且C8不能离开C7而独立存在。 但这是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因 为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的, 这就可以用聚合了。在《敏捷开发》中还说到,A组合B,则A需要知道B的生存周期,即可能A负责生成或者释放B,或者A通过某种途径知道B的生成和释放。 代码和聚合是一样的。具体如何区别,可能就只能用语义来区分了。 那依赖和聚合\组合、关联等有什么不同呢? 关联是类之间的一种关系,例如老师教学生,老公和老婆,水壶装水等就是一种关系。这种关系是非常明显的,在问题领域中通过分析直接就能得出。 依赖是一种弱关联,只要一个类用到另一个类,但是和另一个类的关系不是太明显的时候(可以说是“uses”了那个类),就可以把这种关系看成是依 赖,依赖也可说是一种偶然的关系,而不是必然的关系,就是“我在某个方法中偶然用到了它,但在现实中我和它并没多大关系”。例如我和锤子,我和锤子本来是 没关系的, 但在有一次要钉钉子的时候,我用到了它,这就是一种依赖,依赖锤子完成钉钉子这件事情。 组合是一种整体-部分的关系,在问题域中这种关系很明显,直接分析就可以得出的。例如轮胎是车的一部分,树叶是树的一部分,手脚是身体的一部分这种的关系,非常明显的整体-部分关系。 上述的几种关系(关联、聚合/组合、依赖)在代码中可能以指针、引用、值等的方式在另一个类中出现,不拘于形式,但在逻辑上他们就有以上的区别。 这里还要说明一下,所谓的这些关系只是在某个问题域才有效,离开了这个问题域,可能这些关系就不成立了,例如可能在某个问题域中,我是一个木匠,需 要拿着锤 子去干活,可能整个问题的描述就是我拿着锤子怎么钉桌子,钉椅子,钉柜子;既然整个问题就是描述这个,我和锤子就不仅是偶然的依赖关系了,我和锤子的关系 变得非常的紧密,可能就上升为组合关系(让我突然想起武侠小说的剑不离身,剑亡人亡…)。这个例子可能有点荒谬,但也是为了说明一个道理,就是关系和 类一样,它们都是在一个问题领域中才成立的,离开了这个问题域,他们可能就不复存在了。

Gof设计模式

创建型模式

Singleton(单例模式):保证一个类仅有一个实例,并提供一个访问它的全局访问点。 在这里插入图片描述 Prototype(原型模式):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。 在这里插入图片描述 Builder(建造者模式):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 在这里插入图片描述 Factory Method(工厂模式):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。 在这里插入图片描述 Factory Method使一个类的实例化延迟到其子类。 Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 在这里插入图片描述

结构型模式

Bridge(桥接模式):将抽象部分与它的实现部分分离,使它们都可以独立地变化。 在这里插入图片描述 Facade(外观模式):为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 在这里插入图片描述 Composite(组合模式):将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。 在这里插入图片描述 Decorator(装饰模式):动态地给一个对象添加一些额外的职责。就扩展功能而言, 它比生成子类方式更为灵活。 在这里插入图片描述 Adapter(适配器模式):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 在这里插入图片描述 Proxy(代理模式):为其他对象提供一个代理以控制对这个对象的访问。 在这里插入图片描述 Flyweight(享元模式):运用共享技术有效地支持大量细粒度的对象。 在这里插入图片描述

行为型模式

Iterator(迭代器模式):提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。 在这里插入图片描述 Interpreter(解析器模式):给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。 在这里插入图片描述 Observer(观察者模式):定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。 在这里插入图片描述 Mediator(中介者模式):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 在这里插入图片描述 Visitor(访问者模式):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 在这里插入图片描述 Memento(备忘录模式):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。 在这里插入图片描述 State(状态模式):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。 在这里插入图片描述 Strategy(策略模式):定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。 在这里插入图片描述 Template Method(模板方法模式):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在这里插入图片描述 Command(命令模式):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。 在这里插入图片描述 Chain of Responsibility(职责链模式):为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。 将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。 在这里插入图片描述

消息队列

所谓的**消息中间件大道至简:一发一存一消费,没有最好的消息中间件,只有最合适的消息中间件。 **

常见

ActiveMQ Apache出品,Java开发,目前所占的市场份额不多。

RabbitMQ Erlang语言实现AMQP协议的消息中间件,并发能力很强,性能及其好,延时很低(达到微妙级),特点:可靠性,可用性,扩展性,功能丰富。

Kafka LinkedIn使用Scala开发的分布式,多分区,多副本且基于zookeeper协调的分布式消息系统,提供了超高的吞吐量,毫秒级延迟,极高的可用性和可靠性。

RocketMQ 阿里出品,Java开发,高吞吐,高可用,适合大规模分布式应用,经过多次双十一的洗礼,实力不容小觑。

MSMQ的介绍 MSMQ全称是Microsoft Message Queue——微软消息队列。它是一种异步传输模式,可以在不同的应用之间实现相互通信,相互通信的应用可以分布在同一台机器上,也可以分布于相连的网络空间中的任一位置。

两种模式


小结 消息队列主要分为两种模式:点对点模式(一个生产者对口一个消费者)和发布/订阅模式(一对多)。

CCPP

对于 Web 性能优化,您有哪些了解和经验吗? 前端优化 1.求下面函数的返回值( 微软) int func(x){int countx =0;while(x){countx ++;x = x&(x-1);}return countx;} 假定x = 9999。 答案:8 思路:将x转化为2进制,看含有的1的个数。 2. 什么是“引用”?申明和使用“引用”要注意哪些问题? 答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。 3. 将“引用”作为函数参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。 4. 在什么时候需要使用“常引用”?  如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名; 例1 int a;constint\&ra = a;ra = 1; // 错误 a = 1; // 正确 例2 string foo( );void bar(string\&s) // 那么下面的表达式将是非法的: bar(foo( ));bar(“hello world”); 原因在于foo( )和”hello world”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。 引用型参数应该在能被定义为const的情况下,尽量定义为const 。 5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式: 类型标识符 &函数名(形参列表及类型说明){  //函数体 } 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error! 注意: (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了”无所指”的引用,程序会进入未知状态。 (2)不能返回函数内部new分配的内存的引用(这个要注意啦,很多人没意识到,哈哈。。。)。 这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。 (3)可以返回类成员的引用,但最好是const。 这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。 (4)流操作符重载返回值申明为“引用”的作用: 流操作符«和»,这两个操作符常常希望被连续使用,例如:cout «“hello” « endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个«操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用«操作符。 因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。 例3 #include  int\&put(int n);int vals[10];int error = -1; void main(){  put(0) = 10; // 以put(0)函数值作为左值,等价于vals[0]=10;   put(9) = 20; // 以put(9)函数值作为左值,等价于vals[9]=20;   cout « vals[0];  cout « vals[9];} int\&put(int n){  if (n>=0&& n<=9 )    {      return vals[n];     }   else    {     cout « ”subscript error”;       return error;    } } (5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一 个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。 6. “引用”与多态的关系? 引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例(见:C++中类的多态与虚函数的使用)。 例4 0 Class A;Class B : Class A{  // … };B b;A\&ref= b; 0 7. “引用”与指针的区别是什么? 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差; 而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。 8. 什么时候需要“引用”? 流操作符«和»、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。 9. 结构与联合有和区别? 1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。  2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。 10. 下面关于“联合”的题目的输出? a) 0 #include union{  int i;  char x[2];}a;void main(){  a.x[0] =10;  a.x[1] =1;  printf(“%d”,a.i);} 0 答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A) b) 0 main(){union{ /*定义一个联合*/ int i;struct{ /*在联合中定义一个结构*/ char first;char second;}half;}number;number.i=0x4241; /*联合成员赋值*/printf(“%c%c\n”, number.half.first, mumber.half.second);number.half.first=’a’; /*联合中结构成员赋值*/number.half.second=’b’;printf(“%x\n”,number.i);getch();} 0 答案: AB   (0x41对应’A’,是低位;Ox42对应’B’,是高位)        6261 (number.i和number.half共用一块地址空间) 11. 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。 答案: 0 /*编写strcpy函数(10分)已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。(1)不调用C++/C的字符串库函数,请编写函数 strcpy(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?答:为了 实现链式表达式。 // 2分例如 int length = strlen( strcpy( strDest, “hello world”) );*/#include #include  char*strcpy(char*strDest, constchar*strSrc){assert((strDest!=NULL) && (strSrc !=NULL)); // 2分 char* address = strDest;   // 2分 while( (*strDest++=*strSrc++) !=’\0’ )       // 2分 NULL;return address ;    // 2分 } 0 另外strlen函数如下: 0 #include#include int strlen( constchar*str ) // 输入参数const {assert( str != NULL ); // 断言字符串地址非0 int len = 0;while( (*str++) !=’\0’ ){len++;}return len;} 0 12. 已知String类定义如下: 0 class String{public:  String(const char *str = NULL); // 通用构造函数   String(const String \&another); // 拷贝构造函数   ~String(); // 析构函数   String& operater =(const String \&rhs); // 赋值函数 private:  char* m_data; // 用于保存字符串 }; 0 尝试写出类的成员函数实现。 答案: 0 String::String(constchar*str){if ( str == NULL ) // strlen在参数为NULL时会抛异常才会有这步判断 {m_data =newchar[1] ;m_data[0] =’\0’ ;}else{m_data =newchar[strlen(str) +1];strcpy(m_data,str);}}String::String(const String \&another){m_data =newchar[strlen(another.m_data) +1];strcpy(m_data,other.m_data);}String& String::operator=(const String \&rhs){if ( this==\&rhs)return*this ;delete []m_data; //删除原来的数据,新开一块内存 m_data =newchar[strlen(rhs.m_data) +1];strcpy(m_data,rhs.m_data);return*this ;}String::~String(){delete []m_data ;} 0 13. .h头文件中的ifndef/define/endif 的作用? 答:防止该头文件被重复引用。 14. #include 与#include “file.h”的区别? 答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。 15.在C++程序中调用被C 编译器编译后的函数,为什么要加extern “C”? 首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数 extern “C”是连接申明(linkage declaration),被extern “C”修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似。 C的函数是怎样编译的: 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。 _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。 同 样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以”.”来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。 未加extern “C”声明时的连接方式 假设在C++中,模块A的头文件如下: // 模块A头文件 moduleA.h #ifndef MODULE_A_H#define MODULE_A_H int foo( int x, int y );#endif   在模块B中引用该函数: // 模块B实现文件 moduleB.cpp #include ”moduleA.h”foo(2,3); 实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号! 加extern “C”声明后的编译和连接方式 加extern “C”声明后,模块A的头文件变为: // 模块A头文件 moduleA.h #ifndef MODULE_A_H#define MODULE_A_H extern”C”int foo( int x, int y );#endif  在模块B的实现文件中仍然调用foo( 2,3 ),其结果是: (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式; (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。 如果在模块A中函数声明了foo为extern “C”类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。 所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):实现C++与C及其它语言的混合编程。   明白了C++中extern “C”的设立动机,我们下面来具体分析extern “C”通常的使用技巧: extern “C”的惯用法  (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理: extern”C”{  #include”cExample.h”} 而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern “C”声明,在.c文件中包含了extern”C”时会出现编译语法错误。 C++引用C函数例子工程中包含的三个文件的源代码如下: /* c语言头文件:cExample.h */#ifndef C_EXAMPLE_H#define C_EXAMPLE_H externint add(int x, inty);#endif /* c语言实现文件:cExample.c */#include ”cExample.h” int add( int x, int y ){  return x + y;} 0 // c++实现文件,调用add:cppFile.cpp extern”C”{  #include”cExample.h”}int main(int argc, char* argv[]){  add(2,3);  return0;} 0 如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern “C” { }。 (2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern “C”,但是在C语言中不能直接引用声明了extern “C”的该头文件,应该仅将C文件中将C++中定义的extern”C”函数声明为extern类型。 C引用C++函数例子工程中包含的三个文件的源代码如下: //C++头文件cppExample.h #ifndef CPP_EXAMPLE_H#define CPP_EXAMPLE_H extern”C”int add( int x, int y );#endif //C++实现文件 cppExample.cpp #include”cppExample.h” int add( int x, int y ){  return x + y;} 0 /* C实现文件 cFile.c/* 这样会编译出错:#i nclude “cExample.h” */ externint add( int x, int y );int main( int argc, char* argv[] ){  add( 2, 3 );  return0;} 0 16. 关联、聚合(Aggregation)以及组合(Composition)的区别? 涉及到UML中的一些概念: 关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系; 聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系: 从实现的角度讲,聚合可以表示为: class A {…}  class B { A* a; …..} 组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系: 实现的形式是: class A{…} class B{ A a; …} 17.面向对象的三个基本特征,并简单叙述之? 1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public) 2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。 3. 多态:系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性。(见:C++中类的多态与虚函数的使用) 18. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别? 常考的题目。 从定义上来说: 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。 重写:是指子类重新定义父类虚函数的方法。 从实现原理上来说: 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关! 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。 19. 多态的作用? 主要是两个: 1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用; 2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。 20. Ado与Ado.net的相同与不同? 除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。 21. New delete 与mallocfree 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor. (可以看看:显式调用构造函数和析构函数) 22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?答案:i 为30。(注意直接展开就是了) 5 * 5 + 5  23. 有哪几种情况只能用intializationlist 而不能用assignment? 答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。 24. C++是不是类型安全的? 答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。 25. main 函数执行以前,还会执行什么代码?答案:全局对象的构造函数会在main 函数之前执行,为malloc分配必要的资源,等等。 26. 描述内存分配方式以及它们的区别? 1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。 3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 4) 代码区。 27.struct 和 class 的区别 答案:struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。 从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服 务,有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在 的!)时,你也许应该使用 struct 关键字,否则,你应该使用 class 关键字。  28.当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)答案:肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。 29. 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel) 答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。 30. 比较C++中的4种类型转换方式? 重点是static_cast, dynamic_cast和reinterpret_cast的区别和应用。(以后再补上吧) 31.分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。 答案: BOOL :  if ( !a ) or if(a)int :   if ( a ==0)float : const EXPRESSION EXP =0.000001  if ( a < EXP&& a >-EXP)pointer : if ( a != NULL) or if(a == NULL) 32.请说出const与#define 相比,有何优点?1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。 33.简述数组与指针的区别? 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 (1)修改内容上的差别 char a[] = “hello”; a[0] = ‘X’; char *p = “world”; // 注意p 指向常量字符串 p[0] = ‘X’; // 编译器不能发现该错误,运行时错误 (2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。 char a[] =”hello world”;char*p = a;cout<<sizeof(a) « endl; // 12 字节 cout<<sizeof(p) « endl; // 4 字节 计算数组和指针的内存容量 void Func(char a[100]){  cout<<sizeof(a) « endl; // 4 字节而不是100 字节 } 34.类成员函数的重载、覆盖和隐藏区别? 答案: a.成员函数被重载的特征: (1)相同的范围(在同一个类中); (2)函数名字相同; (3)参数不同; (4)virtual 关键字可有可无。 b.覆盖是指派生类函数覆盖基类函数,特征是: (1)不同的范围(分别位于派生类与基类); (2)函数名字相同; (3)参数相同; (4)基类函数必须有virtual 关键字。 c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下: (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。 (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 35. There are twoint variables: a and b, don’t use “if”, “? :”, “switch”or other judgementstatements, find out the biggest one of the two numbers. 答案:( ( a + b ) + abs( a- b ) ) / 2 36. 如何打印出当前源文件的文件名以及源文件的当前行号?答案: cout « __FILE__ ; cout«__LINE__ ; __FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的 。 37. main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void),fn4 (void); 0 void main( void ){  String str(“zhanglin”);  _onexit( fn1 );  _onexit( fn2 );  _onexit( fn3 );  _onexit( fn4 );  printf( ”This is executed first.\n” );}int fn1(){  printf( ”next.\n” );  return0;}int fn2(){  printf( ”executed ” );  return0;}int fn3(){  printf( ”is ” );  return0;}int fn4(){  printf( ”This ” );  return0;} 0 The _onexit function is passed the address of a function (func) to be called whenthe program terminates normally. Successive calls to _onexit create a registerof functions that are executed in LIFO (last-in-first-out) order. The functionspassed to _onexit cannot take parameters. 38. 如何判断一段程序是由C 编译程序还是由C++编译程序编译的? 答案: #ifdef __cplusplus  cout«“c++”;#else  cout«“c”;#endif 注意,后面很多代码啊。代码不看也罢。 39.文件中有一组整数,要求排序后输出到另一个文件中(面试官,超级喜欢考排序的。你要去面试,数据结构的那几个排序一定要非常熟悉,用笔也可以写出代码来,用笔写代码,就是这样变态啊,其实感觉没有必要这样笔试) 答案: 0 #include#include usingnamespace std;void Order(vector<int>& data)//bubble sort {int count = data.size() ;int tag =false ; // 设置是否需要继续冒泡的标志位 for ( int i =0 ; i < count ; i++){for ( int j =0 ; j < count - i -1 ; j++){if ( data[j] > data[j+1]){tag =true ;int temp = data[j] ;data[j] = data[j+1] ;data[j+1] = temp ;}}if ( !tag )break ;}}void main( void ){vector<int>data;ifstream in(“c:\\data.txt”);if ( !in){cout«“file error!”;exit(1);}int temp;while (!in.eof()){in»temp;data.push_back(temp);}in.close(); //关闭输入文件流 Order(data);ofstream out(“c:\\result.txt”);if ( !out){cout«“file error!”;exit(1);}for ( i =0 ; i < data.size() ; i++)out<”“;out.close(); //关闭输出文件流 } 0 40. 链表题:一个链表的结点结构 struct Node{int data ;Node *next ;};typedef struct Node Node ; (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel) 0 Node * ReverseList(Node *head) //链表逆序 {if ( head == NULL || head->next == NULL )return head;Node *p1 = head ;Node *p2 = p1->next ;Node *p3 = p2->next ;p1->next = NULL ;while ( p3 != NULL ){p2->next = p1 ;p1 = p2 ;p2 = p3 ;p3 = p3->next ;}p2->next = p1 ;head = p2 ;return head ;} 0 (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同) 0 Node * Merge(Node *head1 , Node *head2){if ( head1 == NULL)return head2 ;if ( head2 == NULL)return head1 ;Node *head = NULL ;Node *p1 = NULL;Node *p2 = NULL;if ( head1->data < head2->data ){head = head1 ;p1 = head1->next;p2 = head2 ;}else{head = head2 ;p2 = head2->next ;p1 = head1 ;}Node *pcurrent = head ;while ( p1 != NULL && p2 != NULL){if ( p1->data <= p2->data ){pcurrent->next = p1 ;pcurrent = p1 ;p1 = p1->next ;}else{pcurrent->next = p2 ;pcurrent = p2 ;p2 = p2->next ;}}if ( p1 != NULL )pcurrent->next = p1 ;if ( p2 != NULL )pcurrent->next = p2 ;return head ;} 0 (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。(Autodesk)答案: 0 Node * MergeRecursive(Node *head1 , Node *head2){if ( head1 == NULL )return head2 ;if ( head2 == NULL)return head1 ;Node *head = NULL ;if ( head1->data < head2->data ){head = head1 ;head->next = MergeRecursive(head1->next,head2);}else{head = head2 ;head->next = MergeRecursive(head1,head2->next);}return head ;} 0 41. 分析一下这段程序的输出(Autodesk) 0 class B{public:B(){cout«“default constructor”<”destructed”<int i):data(i) //B(int) works as a converter ( int ->instance of B) {cout«“constructed by parameter ”« data <private:int data;};B Play( B b){return b ;}(1) results:int main(int argc, char* argv[]) constructedby parameter 5{ destructed B(5)形参析构B t1 = Play(5); B t2 = Play(t1);   destructed t1形参析构return0;               destructed t2 注意顺序!} destructed t1(2) results:int main(int argc, char* argv[]) constructedby parameter 5{ destructed B(5)形参析构B t1 = Play(5); B t2 = Play(10);   constructed by parameter 10 return0;               destructed B(10)形参析构} destructed t2 注意顺序!destructed t1 0 42. 写一个函数找出一个整数数组中,第二大的数(microsoft) 答案: 0 constint MINNUMBER =-32767 ;int find_sec_max( int data[] , int count){int maxnumber = data[0] ;int sec_max = MINNUMBER ;for ( int i =1 ; i < count ; i++){if ( data[i] > maxnumber ){sec_max = maxnumber ;maxnumber = data[i] ;}else{if ( data[i] > sec_max )sec_max = data[i] ;}}return sec_max ;} 0 43. 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。 KMP算法效率最好,时间复杂度是O(n+m)。 44. 多重继承的内存分配问题:   比如有class A : public class B, public classC {}   那么A的内存结构大致是怎么样的? 这个是compiler-dependent的, 不同的实现其细节可能不同。 如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。 可以参考《深入探索C++对象模型》 45. 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针) 0 struct node { char val; node* next;}bool check(const node* head) {} //return false : 无环;true: 有环一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):bool check(const node* head){if(head==NULL) returnfalse;node *low=head, *fast=head->next;while(fast!=NULL && fast->next!=NULL){low=low->next;fast=fast->next->next;if(low==fast) returntrue;}returnfalse;} 0 1.求下面函数的返回值( 微软) 0 0 ![0](<”0”) int func(x)  {  int countx =0;  while(x)  {  countx ++;  x = x&(x-1);  }  return countx;  } ![0](<”0”) 0 0 假定x = 9999。 答案:8 思路:将x转化为2进制,看含有的1的个数。 2. 什么是“引用”?申明和使用“引用”要注意哪些问题? 答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。 3. 将“引用”作为函数参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。 4. 在什么时候需要使用“常引用”?  如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名; 例1int a; constint\&ra = a; ra = 1; // 错误 a = 1; // 正确 例2string foo( ); void bar(string\&s) // 那么下面的表达式将是非法的: bar(foo( )); bar(“hello world”); 原因在于foo( )和”hello world”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。 引用型参数应该在能被定义为const的情况下,尽量定义为const 。 5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式:类型标识符 &函数名(形参列表及类型说明) {    //函数体 } 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error! 注意: (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了”无所指”的引用,程序会进入未知状态。 (2)不能返回函数内部new分配的内存的引用(这个要注意啦,很多人没意识到,哈哈。。。)。 这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。 (3)可以返回类成员的引用,但最好是const。 这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。 (4)流操作符重载返回值申明为“引用”的作用: 流操作符«和»,这两个操作符常常希望被连续使用,例如:cout «“hello” « endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个«操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用«操作符。 因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。 例3 0 0 ![0](<”0”) #include  int\&put(int n); int vals[10]; int error = -1; void main() {   put(0) = 10; // 以put(0)函数值作为左值,等价于vals[0]=10;   put(9) = 20; // 以put(9)函数值作为左值,等价于vals[9]=20;   cout « vals[0];   cout « vals[9]; } int\&put(int n) {   if (n>=0&& n<=9 )    {      return vals[n];     }   else    {     cout « ”subscript error”;       return error;    } } ![0](<”0”) 0 0 (5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一 个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。 6. “引用”与多态的关系? 引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例(见:C++中类的多态与虚函数的使用)。 例4 0 0 ![0](<”0”) Class A;  Class B : Class A {   // … };  B b; A\&ref= b; ![0](<”0”) 0 0 7. “引用”与指针的区别是什么? 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差; 而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。 8. 什么时候需要“引用”? 流操作符«和»、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。 9. 结构与联合有和区别? 1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。  2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。 10. 下面关于“联合”的题目的输出? a) 0 0 ![0](<”0”) #include  union {   int i;   char x[2]; }a; void main() {   a.x[0] =10;    a.x[1] =1;   printf(“%d”,a.i); } ![0](<”0”) 0 0 答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A) b) 0 0 ![0](<”0”) main()  {  union{ /*定义一个联合*/  int i;  struct{ /*在联合中定义一个结构*/  char first;  char second;  }half;  }number;  number.i=0x4241; /*联合成员赋值*/  printf(“%c%c\n”, number.half.first, mumber.half.second);  number.half.first=’a’; /*联合中结构成员赋值*/  number.half.second=’b’;  printf(“%x\n”,number.i);  getch();  } ![0](<”0”) 0 0 答案: AB   (0x41对应’A’,是低位;Ox42对应’B’,是高位)        6261 (number.i和number.half共用一块地址空间) 11. 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。 答案: 0 0 ![0](<”0”) /* 编写strcpy函数(10分) 已知strcpy函数的原型是 char *strcpy(char *strDest, const char *strSrc); 其中strDest是目的字符串,strSrc是源字符串。 (1)不调用C++/C的字符串库函数,请编写函数 strcpy (2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值? 答:为了 实现链式表达式。 // 2分 例如 int length = strlen( strcpy( strDest, “hello world”) ); */ #include  #include  char*strcpy(char*strDest, constchar*strSrc) { assert((strDest!=NULL) && (strSrc !=NULL)); // 2分 char* address = strDest;   // 2分 while( (*strDest++=*strSrc++) !=’\0’ )       // 2分 NULL;  return address ;    // 2分 } ![0](<”0”) 0 0 另外strlen函数如下: 0 0 ![0](<”0”) #include #include  int strlen( constchar*str ) // 输入参数const { assert( str != NULL ); // 断言字符串地址非0 int len = 0; while( (*str++) !=’\0’ )  {  len++;  }  return len; } ![0](<”0”) 0 0 12. 已知String类定义如下: 0 0 ![0](<”0”) class String { public:   String(const char *str = NULL); // 通用构造函数   String(const String \&another); // 拷贝构造函数   ~String(); // 析构函数   String& operater =(const String \&rhs); // 赋值函数 private:   char* m_data; // 用于保存字符串 }; ![0](<”0”) 0 0 尝试写出类的成员函数实现。 答案: 0 0 ![0](<”0”) String::String(constchar*str) { if ( str == NULL ) // strlen在参数为NULL时会抛异常才会有这步判断 { m_data =newchar[1] ; m_data[0] =’\0’ ; } else { m_data =newchar[strlen(str) +1]; strcpy(m_data,str); } }  String::String(const String \&another) { m_data =newchar[strlen(another.m_data) +1]; strcpy(m_data,other.m_data); } String& String::operator=(const String \&rhs) { if ( this==\&rhs) return*this ; delete []m_data; //删除原来的数据,新开一块内存 m_data =newchar[strlen(rhs.m_data) +1]; strcpy(m_data,rhs.m_data); return*this ; } String::~String() { delete []m_data ; } ![0](<”0”) 0 0 13. .h头文件中的ifndef/define/endif 的作用? 答:防止该头文件被重复引用。 14. #include 与#include “file.h”的区别? 答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。 15.在C++程序中调用被C 编译器编译后的函数,为什么要加extern “C”? 首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数 extern “C”是连接申明(linkage declaration),被extern “C”修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似。 C的函数是怎样编译的: 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。 _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。 同 样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以”.”来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。 未加extern “C”声明时的连接方式 假设在C++中,模块A的头文件如下:// 模块A头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H int foo( int x, int y ); #endif   在模块B中引用该函数:// 模块B实现文件 moduleB.cpp #include ”moduleA.h” foo(2,3); 实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号! 加extern “C”声明后的编译和连接方式 加extern “C”声明后,模块A的头文件变为:// 模块A头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H extern”C”int foo( int x, int y ); #endif  在模块B的实现文件中仍然调用foo( 2,3 ),其结果是: (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式; (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。 如果在模块A中函数声明了foo为extern “C”类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。 所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):实现C++与C及其它语言的混合编程。   明白了C++中extern “C”的设立动机,我们下面来具体分析extern “C”通常的使用技巧: extern “C”的惯用法  (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:extern”C” {   #include”cExample.h” } 而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern “C”声明,在.c文件中包含了extern”C”时会出现编译语法错误。 C++引用C函数例子工程中包含的三个文件的源代码如下:/* c语言头文件:cExample.h */ #ifndef C_EXAMPLE_H #define C_EXAMPLE_H externint add(int x, inty); #endif 0 /* c语言实现文件:cExample.c */ #include ”cExample.h” int add( int x, int y ) {   return x + y; } 0 0 0 ![0](<”0”) // c++实现文件,调用add:cppFile.cpp extern”C”  {   #include”cExample.h” } int main(int argc, char* argv[]) {   add(2,3);    return0; } ![0](<”0”) 0 0 如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern “C” { }。 (2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern “C”,但是在C语言中不能直接引用声明了extern “C”的该头文件,应该仅将C文件中将C++中定义的extern”C”函数声明为extern类型。 C引用C++函数例子工程中包含的三个文件的源代码如下://C++头文件cppExample.h #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_H extern”C”int add( int x, int y ); #endif 0 //C++实现文件 cppExample.cpp #include”cppExample.h” int add( int x, int y ) {   return x + y; } 0 0 0 ![0](<”0”) /* C实现文件 cFile.c /* 这样会编译出错:#i nclude “cExample.h” */ externint add( int x, int y ); int main( int argc, char* argv[] ) {   add( 2, 3 );    return0; } ![0](<”0”) 0 0 16. 关联、聚合(Aggregation)以及组合(Composition)的区别? 涉及到UML中的一些概念: 关联是表示两个类的一般性联系,比如“学生”和“老师”就是一种关联关系; 聚合表示has-a的关系,是一种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系: 从实现的角度讲,聚合可以表示为: class A {…}  class B { A* a; …..} 组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系: 实现的形式是: class A{…} class B{ A a; …} 17.面向对象的三个基本特征,并简单叙述之? 1. 封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public) 2. 继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。 3. 多态:系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性。(见:C++中类的多态与虚函数的使用) 18. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别? 常考的题目。 从定义上来说: 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。 重写:是指子类重新定义父类虚函数的方法。 从实现原理上来说: 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关! 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。 19. 多态的作用? 主要是两个: 1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用; 2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。 20. Ado与Ado.net的相同与不同? 除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。 21. New delete 与mallocfree 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor. (可以看看:显式调用构造函数和析构函数) 22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?答案:i 为30。(注意直接展开就是了) 5 * 5 + 5  23. 有哪几种情况只能用intializationlist 而不能用assignment? 答案:当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。 24. C++是不是类型安全的? 答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。 25. main 函数执行以前,还会执行什么代码?答案:全局对象的构造函数会在main 函数之前执行,为malloc分配必要的资源,等等。 26. 描述内存分配方式以及它们的区别? 1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。 3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 4) 代码区。 27.struct 和 class 的区别 答案:struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。 从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服 务,有牢固的封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在 的!)时,你也许应该使用 struct 关键字,否则,你应该使用 class 关键字。  28.当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)答案:肯定不是零。举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。 29. 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel) 答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。 30. 比较C++中的4种类型转换方式? 重点是static_cast, dynamic_cast和reinterpret_cast的区别和应用。(以后再补上吧) 31.分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。 答案:BOOL :  if ( !a ) or if(a) int :   if ( a ==0) float : const EXPRESSION EXP =0.000001   if ( a < EXP&& a >-EXP) pointer : if ( a != NULL) or if(a == NULL) 32.请说出const与#define 相比,有何优点?1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。 33.简述数组与指针的区别? 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 (1)修改内容上的差别 char a[] = “hello”; a[0] = ‘X’; char *p = “world”; // 注意p 指向常量字符串 p[0] = ‘X’; // 编译器不能发现该错误,运行时错误 (2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。char a[] =”hello world”; char*p = a; cout<cout< 计算数组和指针的内存容量void Func(char a[100]){  cout<} 34.类成员函数的重载、覆盖和隐藏区别?答案:a.成员函数被重载的特征:(1)相同的范围(在同一个类中);(2)函数名字相同;(3)参数不同;(4)virtual 关键字可有可无。b.覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有virtual 关键字。c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 35. There are twoint variables: a and b, don’t use “if”, “? :”, “switch”or other judgementstatements, find out the biggest one of the two numbers.答案:( ( a + b ) + abs( a- b ) ) / 2 36. 如何打印出当前源文件的文件名以及源文件的当前行号?答案:cout « __FILE__ ;cout«__LINE__ ;__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。37. main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void),fn4 (void); 0 0 ![0](<”0”) void main( void ){  String str(“zhanglin”);  _onexit( fn1 );  _onexit( fn2 );  _onexit( fn3 );  _onexit( fn4 );  printf( ”This is executed first.\n” );}int fn1(){  printf( ”next.\n” );  return0;}int fn2(){  printf( ”executed ” );  return0;}int fn3(){  printf( ”is ” );  return0;}int fn4(){  printf( ”This ” );  return0;} ![0](<”0”) 0 0 The _onexit function is passed the address of a function (func) to be called whenthe program terminates normally. Successive calls to _onexit create a registerof functions that are executed in LIFO (last-in-first-out) order. The functionspassed to _onexit cannot take parameters. 38. 如何判断一段程序是由C 编译程序还是由C++编译程序编译的?答案:#ifdef __cplusplus  cout«“c++”;#else  cout«“c”;#endif 注意,后面很多代码啊。代码不看也罢。 39.文件中有一组整数,要求排序后输出到另一个文件中(面试官,超级喜欢考排序的。你要去面试,数据结构的那几个排序一定要非常熟悉,用笔也可以写出代码来,用笔写代码,就是这样变态啊,其实感觉没有必要这样笔试)答案: 0 0 ![0](<”0”) #include#includeusingnamespace std;void Order(vector& data)//bubble sort{int count = data.size() ;int tag =false ; // 设置是否需要继续冒泡的标志位for ( int i =0 ; i < count ; i++){for ( int j =0 ; j < count - i -1 ; j++){if ( data[j] > data[j+1]){tag =true ;int temp = data[j] ;data[j] = data[j+1] ;data[j+1] = temp ;}}if ( !tag )break ;}}void main( void ){vectordata;ifstream in(“c:\\data.txt”);if ( !in){cout«“file error!”;exit(1);}int temp;while (!in.eof()){in»temp;data.push_back(temp);}in.close(); //关闭输入文件流Order(data);ofstream out(“c:\\result.txt”);if ( !out){cout«“file error!”;exit(1);}for ( i =0 ; i < data.size() ; i++)out<out.close(); //关闭输出文件流} ![0](<”0”) 0 0  40. 链表题:一个链表的结点结构 0 struct Node{int data ;Node *next ;};typedef struct Node Node ; 0  (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel) 0 0 ![0](<”0”) Node * ReverseList(Node *head) //链表逆序{if ( head == NULL || head->next == NULL )return head;Node *p1 = head ;Node *p2 = p1->next ;Node *p3 = p2->next ;p1->next = NULL ;while ( p3 != NULL ){p2->next = p1 ;p1 = p2 ;p2 = p3 ;p3 = p3->next ;}p2->next = p1 ;head = p2 ;return head ;} ![0](<”0”) 0 0  (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同) 0 0 ![0](<”0”) Node * Merge(Node *head1 , Node *head2){if ( head1 == NULL)return head2 ;if ( head2 == NULL)return head1 ;Node *head = NULL ;Node *p1 = NULL;Node *p2 = NULL;if ( head1->data < head2->data ){head = head1 ;p1 = head1->next;p2 = head2 ;}else{head = head2 ;p2 = head2->next ;p1 = head1 ;}Node *pcurrent = head ;while ( p1 != NULL && p2 != NULL){if ( p1->data <= p2->data ){pcurrent->next = p1 ;pcurrent = p1 ;p1 = p1->next ;}else{pcurrent->next = p2 ;pcurrent = p2 ;p2 = p2->next ;}}if ( p1 != NULL )pcurrent->next = p1 ;if ( p2 != NULL )pcurrent->next = p2 ;return head ;} ![0](<”0”) 0 0  (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。(Autodesk)答案: 0 0 ![0](<”0”) Node * MergeRecursive(Node *head1 , Node *head2){if ( head1 == NULL )return head2 ;if ( head2 == NULL)return head1 ;Node *head = NULL ;if ( head1->data < head2->data ){head = head1 ;head->next = MergeRecursive(head1->next,head2);}else{head = head2 ;head->next = MergeRecursive(head1,head2->next);}return head ;} ![0](<”0”) 0 0  41. 分析一下这段程序的输出(Autodesk) 0 0 ![0](<”0”) class B{public:B(){cout«“default constructor”<}~B(){cout«“destructed”<}B(int i):data(i) //B(int) works as a converter ( int ->instance of B){cout«“constructed by parameter ”« data <}private:int data;};B Play( B b) {return b ;}(1) results:int main(int argc, char* argv[]) constructedby parameter 5{ destructed B(5)形参析构B t1 = Play(5); B t2 = Play(t1);   destructed t1形参析构return0;               destructed t2 注意顺序!} destructed t1(2) results:int main(int argc, char* argv[]) constructedby parameter 5{ destructed B(5)形参析构B t1 = Play(5); B t2 = Play(10);   constructed by parameter 10return0;               destructed B(10)形参析构} destructed t2 注意顺序!destructed t1 ![0](<”0”) 0 0  42. 写一个函数找出一个整数数组中,第二大的数(microsoft)答案: 0 0 ![0](<”0”) constint MINNUMBER =-32767 ;int find_sec_max( int data[] , int count){int maxnumber = data[0] ;int sec_max = MINNUMBER ;for ( int i =1 ; i < count ; i++){if ( data[i] > maxnumber ){sec_max = maxnumber ;maxnumber = data[i] ;}else{if ( data[i] > sec_max )sec_max = data[i] ;}}return sec_max ;} ![0](<”0”) 0 0  43. 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。KMP算法效率最好,时间复杂度是O(n+m)。 44. 多重继承的内存分配问题:   比如有class A : public class B, public classC {}   那么A的内存结构大致是怎么样的?这个是compiler-dependent的, 不同的实现其细节可能不同。如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。可以参考《深入探索C++对象模型》 45. 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)        0 0 ![0](<”0”) struct node { char val; node* next;}bool check(const node* head) {} //return false : 无环;true: 有环一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):bool check(const node* head){if(head==NULL) returnfalse;node *low=head, *fast=head->next;while(fast!=NULL && fast->next!=NULL){low=low->next;fast=fast->next->next;if(low==fast) returntrue;}returnfalse;} 0

* * *

C++常见的面试题目整理 本文列出C++面试中经常遇到的一些问题,都是一些常见的面试考点,如果后续遇到其他常见面试问题还会再次更新。希望对近期参加面试的同学有一些帮助。先后顺序与问题的重要性无关,查看的时候,最好是全面了解一下。 C++语言基础、语言特性、数据结构、操作系统知识甚至是一些内核相关的知识、网络相关知识、数据库操作、多线程多进程数据同步互斥、内存相关知识等等。 1、关键字及基本问题 const的作用,const怎么使用,有哪些应用场景? static的作用,static类成员变量怎么初始化?static成员可以调用哪些成员函数,非static成员函数可以调用哪些成员函数? static成员函数怎么使用,与普通成员函数有什么区别? 指针和引用的区别? new和malloc的区别? 程序的内存分布?堆栈的生长方向?为什么是相反的生长方向? 了解哪些创建堆的函数? 2、类相关的题目 为什么要进行封装? 什么是多态,多态是怎么实现的?多态的应用场景? 虚函数表是属于类的还是属于成员的?虚指针呢? 虚函数,纯虚函数?什么时候使用虚函数,什么时候使用纯虚函数?有了虚函数为什么还要用纯虚函数,可以用虚函数替代纯虚函数吗? 类的构造函数可以定义为虚函数吗?析构函数呢? 基类的析构函数为什么通常需要定义为虚函数?如果不定义为虚函数会有什么问题?什么场景下会产生这种问题? 定义拷贝构造函数的时候参数有什么要求?为什么要将参数定义为引用,如果不定义为引用会产生什么问题? 什么是深拷贝?怎么实现深拷贝? 构造函数的成员初始化列表的使用场景?什么时候必须使用初始化列表? 3、C++11+的新特性 你了解哪些C++11新的特性? static_cast 与dynamic_cast有什么区别?分别是基于什么原理实现?为什么要使用他们而不是使用之前标准里面的强制类型转换? nullptr的作用?为什么要引入nullptr而不使用NULL? 你了解哪些智能指针? 智能指针的内部是怎么实现的? 左值右值,左值引用与右值引用? 4、STL及数据结构(注意效率与复杂度) vector和list的内部实现是什么?分别适用于什么应用场景? vector随机访问的时间复杂度是多少?怎么优化vector的查找速度? vector扩容的过程? 怎么彻底清空vector? vector怎么查找元素?如果是一个结构怎么查找一个vector结构中的指定元素?(find find_if) map查找的复杂度? map的底层是怎么实现的?map与hashmap的区别?什么时候应该使用map什么时候应该使用hashmap? 常见排序算法及其时间和空间复杂度?桶排序有了解的吗? 给定一个场景,选择一种合适的容器? 怎么定义一个环形队列?怎么判断环形队列的空与满? C/C++的学习裙【105+302+9869】,无论你是小白还是进阶者,是想转行还是想入行都可以来了解一起 进步一起学习!裙内有开发工具,很多干货和技术资料分享! 5、计算机网络 三次握手与四次挥手的过程及状态的转变? 为什么是三次握手而不是两次握手? 为什么是需要四次挥手? soket通信实现的基本过程? 使用原生的socket不使用网络库的时候,怎么防止粘包,需要怎么定义相关请求的结构? 接口的幂等性? http协议是长连接还是短链接,怎么改为长链接? http请求头包含哪些内容?一个http请求包含哪些内容? 6、多线程与多进程 windows下怎么创建线程?使用哪些线程函数?为什么建议使用_beginthreadex与endthreadex而不是createthread与endthread? 线程间同步互斥的方法有哪些? 进程间通信进程间同步的方法有哪些? 互斥、事件、临界区、信号量之间区别?(临界区控制同步的时候不需要进入内核态,其他的都需要进入内核态) 说一说临界区的使用?CRITICAL_SECTION InitializeCriticalSection EnterCriticalSection LeaveCriticalSection 同一线程可以多次进入临界区吗? 什么是死锁,什么情况下会产生死锁,怎么避免产生死锁,如果产生了死锁该怎么调试? 多线程情况下,怎么只让某个线程调用指定的函数? 7、数据库 mysql数据库中的左连接 右链接 内连接的区别? 关系型数据库与非关系型数据库的区别? 存储过程? 了解redis吗? 8、设计模式 你了解哪些设计模式? 怎么实现一个懒汉式的线程安全的单例模式? 9、git使用的问题 git pull 与git rebase 10、windows相关问题 说说windows的消息机制?有哪些相关的函数? MFC窗体的生命周期,涉及到哪些函数? 模态对话框与非模态对话框的区别? 怎么产生一个dump文件?dump分析工具你知道哪些?windbg windows下你了解哪些定时器类?自己怎么实现一个定时器类? 什么时候会产生内存泄漏?怎么调试内存泄漏?用到哪些内存泄漏的调试方式? 说一说windwos的消息映射机制? 一个dll大入口函数是什么?mfc程序的入口函数是什么? 线程切换的时候操作系统做了哪些事情? sendmessage与postmessage的区别是什么?什么是同步消息什么是异步消息? 11、代码实现(手写代码) strcpy、memcpy、单例模式 、二叉树的前序中序后序遍历、二叉树的层序遍历遍历、不完全二叉树的序列化与反序列化 

Php


IIS PHP配置

https://help.aliyun.com/zh/ecs/how-do-i-use-iis-to-build-a-php-environment-on-a-windows-instance

https://www.cnblogs.com/xiaohi/p/17734691.html

https://github.com/edgardo001/PHPManagerForIIS-Versiones?spm=a2c4g.11186623.0.0.6b744285BJlYd6

<?php
    function OpenConnection()
    {
        $serverName = "(local)";
        $connectionOptions = array("Database"=>"TestDB",
            "Uid"=>"sa", "PWD"=>"123456");
        $conn = sqlsrv_connect($serverName, $connectionOptions);
        if($conn == false)
            die(FormatErrors(sqlsrv_errors()));

        return $conn;
    }
    function ReadData()
    {
        try
        {
            $conn = OpenConnection();
            $tsql = "SELECT * FROM T_USER";
            $getProducts = sqlsrv_query($conn, $tsql);
            if ($getProducts == FALSE)
                die(FormatErrors(sqlsrv_errors()));
            $productCount = 0;
            while($row = sqlsrv_fetch_array($getProducts, SQLSRV_FETCH_ASSOC))
            {
                echo($row['ID']);
                echo("<br/>");
                $productCount++;
            }
            sqlsrv_free_stmt($getProducts);
            sqlsrv_close($conn);
        }
        catch(Exception $e)
        {
            echo("Error!");
        }
    }
    ReadData();
?>

LabView

LabⅥEW基础知识

LabⅥEW编程环境 前面板 程序框图 菜单栏 工具栏 项目浏览器窗口 Xcontrol XControl对于用户来说,和普通的控件没有区别,但XControl对于开发者来说,除了有自定义外观外,还能自定义行为。 可以将控件的功能封装起来,使其和应用程序代码分离。同时有助于重用。 创建XControl 新建XCtrl: Data.ctl: 指定了XCtrl的数据类型; State.ctl: 指定了除数据类型之外其他影响XCtrl外观的信息,其他所有数据的定义放在此处; Init.vi: 当XCtrl第一次被放置在前面板上或含有XCtrl的vi第一次被载入内存时,初始化显示状态。 新建Method,定义XCtrl支持的方法(类似于类的成员函数),用于操作State中的数据;这里实现各种具体的操作。 新建Property,定义了XCtrl的可读取属性(类似于LabVIEW类的accessor的工作),用于读取XCtrl中的数据; 修改facade vi,用于定制XControl的外观,创建各种状态改变事件。 X控件的本质是为控件事先定义好一系列可以响应的事件,之后使用控件时,就可以在控件的属性或调用节点中看到这些事件,像操作普通控件一样,调用这些节点来执行特定操作。 以LabVIEW自带的摄氏华氏温度转换XCtrl为例:

前面板设计

前面板 “工具”选板 图标/连接器 选板可见性设置 前面板控件 “控件”选板 控件样式 对象的设置 选择对象 删除对象 变更对象位置 属性节点 设置前面板的外观 改变对象的大小 改变对象的颜色 设置对象的字体 菜单设计 菜单编辑器 “菜单”函数

程序框图与程序结构

程序框图 循环结构 For循环及并行循环 移位寄存器 While循环 反馈节点 条件结构 顺序结构 事件结构 程序框图禁用结构 条件禁用结构 定时循环 定时循环和定时顺序结构 配置定时循环和定时顺序结构 同步开始定时结构和中止定时结构的执行 公式节点 程序逻辑的公式节点

数值字符串与布尔运算

数值控件 数值型控件 布尔型控件和单选按钮 字符串与路径控件 数值运算 数值函数 三角函数 字符串运算 字符串常量 字符串函数 其余运算 布尔运算 比较运算 定时运算 图形与声音运算

数组、矩阵与簇

数组控件

数组、矩阵和簇控件

列表框、树形控件和表格

容器控件

实例——数组分类

数组

数组的组成

实例——创建数组控件

实例——创建多维数组控件

数组函数

实例——比较数组

实例——选项卡数组

簇的组成

创建簇

实例——创建簇控件

实例——调整“簇”控件顺序

簇函数

实例——使用“捆绑”函数创建“簇”控件

矩阵

创建矩阵

矩阵函数

实例——创建矩阵控件

实例——矩阵变换

综合实例——矩形的绘制

数据图形显示

图形控件 图形和图表 下拉列表与枚举控件 I/O控件 修饰控件 对象和应用程序的引用 .NET与ActiveX控件 图表图形 波形图 波形图表 XY图 强度图 强度图表 二维图形 罗盘图 误差线图 羽状图 XY曲线矩阵 三维图形 三维曲面图 三维参数图 三维曲线图 极坐标图

数学函数

数学函数运算 线性代数Ⅵ 特殊矩阵 矩阵的基本运算 矩阵的分解 特征值 线性方程组 初等与特殊函数 指数函数 双曲函数 离散数学 贝塞尔曲线 Gamma函数 超几何函数 椭圆积分函数 指数积分函数 误差函数 椭圆与抛物函数 拟合Ⅵ 曲线拟合 拟合函数 内插与外推Ⅵ 概率与统计Ⅵ 累积分布函数(连续) 逆累积分布函数(连续 累积分布函数(离散) 逆累积分布函数(离散) 方差分析Ⅵ 很优化Ⅵ 微分方程Ⅵ 多项式Ⅵ

波形运算

波形数据 变体函数 时间标识 波形生成 基本函数发生器 正弦波形 公式波形 基本混合单频 混合单频与噪声波形 基本带幅值混合单频 混合单频信号发生器 均匀白噪声波形 周期性随机噪声波形 伯努利噪声波形 仿真信号 基本波形函数 获取波形成分 创建波形 “设置波形属性”函数和“获取波形属性”函数 “索引波形数组”函数 “获取波形子集”函数 模拟波形 数字波形Ⅵ和函数 波形调理 数字FIR滤波器 数字IIR滤波器 按窗函数缩放 波形对齐(连续) 波形对齐(单次) 连续卷积(FIR) 滤波器 对齐和重采样 触发与门限 波形测量 基本平均直流——均方根 瞬态特性测量 提取单频信息 快速傅里叶变换频谱(幅度——相位) 频率响应函数(幅度——相位) 频谱测量 失真测量 幅值和电平测量 波形监测 信号生成与处理 信号生成 基于持续时间的信号发生器 混合单频与噪声 高斯调制正弦波 正弦信号 正弦波 均匀白噪声 任意波形发生器 信号运算 卷积和相关ExpressⅥ 缩放和映射 窗 滤波器 巴特沃斯滤波器 切比雪夫滤波器 FIR加窗滤波器 贝塞尔滤波器 谱分析 变换 FFT FHT 反FFT 反FHT 逐点

信号生成

信号运算 滤波器 谱分析 变换 线性代数

文件管理

文件数据 路径 文件I/O格式 文件操作 文件常量 文件类型 文本文件 带分隔符电子表格文件 二进制文件 配置文件 TDMS 存储/数据插件 Zip文件 XML格式 波形文件I/O函数 不错文件函数 数据记录文件的创建和读取 记录前面板数据 数据与XML格式间的相互转换

数据采集

数据采集基础 DAQ功能概述

通信技术

串行通信技术 串行通信介绍 ⅥSA配置串口 DataSocket技术 读取DataSocket 写入DataSocket 打开DataSocket 关闭DataSocket TCP TCP侦听 打开TCP连接 读取TCP数据 写入TCP数据 UDP通信