C++笔试选择题

时间:2017-06-12 编辑:少伟 手机版

  C++由于语言本身过度复杂,这甚至使人类难于理解其语义。更为糟糕的是C++的编译系统受到C++的复杂性的影响,非常难于编写,下面是小编搜集的C++笔试选择题,欢迎大家阅读。

  C++笔试选择题

  1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。

  A.12345ABCDE B.EDCBA54321 C.ABCDE12345 D.54321EDCBA

  【答案】B

  【解析】栈的特点是先进后出,所以全部入栈后再全部出栈所得的序列顺序必然与入栈序列的顺序相反。

  2.下列叙述中正确的是( )。

  A.循环队列有队头和队尾两个指针,因此,循环队列是非线性结构

  B.在循环队列中,只需要队头指针就能反映队列中元素的动态变化情况

  C.在循环队列中,只需要队尾指针就能反映队列中元素的动态变化情况

  D.循环队列中元素的个数是由队头指针和队尾指针共同决定

  【答案】D

  【解析】循环队列是线性表的一种,所以选项A错误。循环队列的人队和出队需要队尾指针和队头指针共同完成,所以选项B和C错误。

  3.在长度为n的有序线性表中进行二分查找,最坏情况下需要比较的次数是( )。

  A.O(n) B.O(n2) C.O(log2n) D.O(nlog2n)

  【答案】C

  【解析】二分查找法也称为折半查找法。它的基本思想是:将n个元素分成个数大致相同的两组,取a[n/2]与欲查找的x作比较。如果x=a[n/2],则找到x,算法终止;如果xa[n/2],则只要在数组a的右半部继续搜索x。每次余下n/2i)个元素待比较,当最后剩下一个时,即n/2i)=1。故,n=2i,i=log2n。

  4.下列叙述中正确的是( )。

  A.顺序存储结构的存储一定是连续的,链式存储结构的存储空间不一定是连续的

  B.顺序存储结构只针对线性结构,链式存储结构只针对非线性结构

  C.顺序存储结构能存储有序表,链式存储结构不能存储有序表

  D.链式存储结构比顺序存储结构节省存储空间

  【答案】A

  【解析】顺序存储方式是把逻辑上相邻的结点存储在物理上相邻的存储单元里,结点之间的关系由存储单元的邻接关系来体现。其优点是占用最少的存储空间,所以选项D错误。顺序存储结构可以存储如二叉树这样的非线性结构,所以选项B错误。链式存储结构也可以存储线性表,所以选项C错误。

  c++面试

  一 用简洁的语言描述 c++

  在 c 语言的基础上开发的一种面向对象编程的语言; 应用广泛; 支持多种编程范式,面向对象编程,泛型编程,和过程化编程;广泛应用于系统开发,引擎开发;支持类,封装,重载等特性。

  二 c 和 c++ 的区别

  C++ 在 c 的基础上添加类;

  C主要是面向过程,C + + 主要面向对象;

  C主要考虑通过一个过程将输入量经过各种运算后得到一个输出, C++ 主要考虑是如何构造一个对象模型,让这个模型契合与之对应的问题域, 这样就可以通过获取对象的状态信息得到输出。

  三 什么是面向对象

  面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。

  四 封装,继承,多态,虚函数

  封装:封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

  继承:继承主要实现重用代码,节省开发时间。子类可以继承父类的一些东西。

  多态:是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态。

  A. 多态

  定义: “一个接口,多种方法”,程序在运行时才决定调用的函数。

  实现: C++多态性主要是通过虚函数实现的,虚函数允许子类重写override(注意和overload的区别,overload是重载,是允许同名函数的表现,这些函数参数列表/类型不同)。

  目的: 封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

  B.什么是虚函数,什么函数不能声明为虚函数?

  那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。

  构造函数。因为要构造一个对象,必须清楚地知道要构造什么,否则无法构造一个对象。析构函数可以为纯虚函数。

  C.为什么要用纯虚函数?

  在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。为了解决这个问题,方便使用类的多态性,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。

  D. 在什么情况下使用纯虚函数(pure vitrual function)?

  当想在基类中抽象出一个方法,且该基类只做能被继承,而不能被实例化;

  这个方法必须在派生类(derived class)中被实现;

  E. 虚函数与纯虚函数的区别

  虚函数为了重载和多态。 在基类中是有定义的,即便定义为空。 在子类中可以重写。

  纯虚函数在基类中没有定义, 必须在子类中加以实现。

  多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。

  子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数, operator=函数,友元函数等等

  五 设计模式

  六 常见的STL容器有哪些,算法哪些

  STL包括两部分,容器和算法。(重要的还有融合这二者的迭代器)

  1. 容器

  即为存放数据的地方。分为两类。

  序列式容器:vector,list,deque等

  关联式容器: 内部结构基本上是一颗平衡二叉树。所谓关联,指每个元素都有兼职和一个实值。

  举例:vector是动态分配存储空间的容器。

  2. 算法

  排序,复制等等,与各个容器相关联。

  3. 迭代器

  STL的精髓。可以这样描述,它提供了一种方法,使之能够按照顺序访问某个容器所含的各个元素,但是无需暴露该容器的内部结构。它将容器和算法分开,好让这二者独立设计。

  七 开发中常用到的数据结构有哪些。

  数组,链表,树。也会用到栈(先进后出)和队列(先进先出)。

  1.数组和链表的区别。(很简单,但是很常考,记得要回答全面)

  C++语言中可以用数组处理一组数据类型相同的数据,但不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小。而在实际应用中,用户使用数组之 前有时无法准确确定数组的大小,只能将数组定义成足够大小,这样数组中有些空间可能不被使用,从而造成内存空间的浪费。链表是一种常见的数据组织形式,它 采用动态分配内存的形式实现。需要时可以用new分配内存空间,不需要时用delete将已分配的空间释放,不会造成内存空间的浪费。

  从逻辑结构来看:

  数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况,即数组的大小一旦定义就不能改变。当数据增加时,可能超出原先 定义的元素个数;当数据减少时,造成内存浪费;链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删 除数据项时,需要移动其它数据项)。

  从内存存储来看:

  (静态)数组从栈中分配空间(用NEW创建的在堆中), 对于程序员方便快速,但是自由度小;链表从堆中分配空间, 自由度大但是申请管理比较麻烦.

  从访问方式来看:

  数组在内存中是连续存储的,因此,可以利用下标索引进行随机访问;链表是链式存储结构,在访问元素的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组要低。

  2. 二叉树的遍历

  二叉树的遍历,就是按照某条搜索路径访问树中的每一个结点,使得每个结点均被访问一次,而且仅被访问一次。

  常见的遍历次序有:

  先序遍历:先访问根结点,再访问左子树,最后访问右子树

  中序遍历:先访问左子树,再访问根结点,最后访问右子树

  后序遍历:先访问左子树,再访问右子树,最后访问根结点

  时间复杂度 O(n)

  八. const与static的用法

  1. const:

  const修饰类的成员变量,表示该成员变量不能被修改。

  const修饰函数,表示本函数不会修改类内的数据成员。不会调用其他非const成员函数。

  const函数只能调用const函数,非const函数可以调用const函数

  类外定义的const成员函数,在定义和声明出都需要const修饰符。

  2. static:

  2.1 对变量:

  a. 局部变量:

  在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。位于内存中静态存储区; 未初始化的局部动初始化为0. 作用域仍是局部作用域.注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置(从原来的栈中存放改为静态存储区)及其生命周期(局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问),但未改变其作用域。

  b. 全局变量.

  在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。静态存储区,未经初始化的全局静态变量会被程序自动初始化为0,全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。注: static修饰全局变量并未改变其存储位置及生命周期, 而是改变了其作用域,使得当前文件外的源文件无法访问该变量.不能被其他文件访问和修改,其他文件中可以使用相同名字的变量,不会产生冲突.

  2.2 对类:

  a. 成员变量.

  用static修饰类的数据成员实际使其成为类的全局变量,会被类的所有对象共享,包括派生类的对象。因此,static成员必须在类外进行初始化(初始化格式: int base::var=10;),而不能在构造函数内进行初始化,不过也可以用const修饰static数据成员在类内初始化 。

  注意:

  不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行。

  静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。

  静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的指针或引用。

  b. 成员函数

  注意:

  a. 用static修饰成员函数,使这个类只存在这一份函数,所有对象共享该函数,不含this指针。

  b. 静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。base::func(5,3);当static成员函数在类外定义时不-需要加static修饰符。

  c. 在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。因为静态成员函数不含this指针。

  d. 不可以同时用const和static修饰成员函数。

  C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。

  我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。因此不能同时用它们。

  九. 类的static变量在什么时候初始化,函数的static变量在什么时候初始化。

  类的静态成员在类实例化之前就存在了,并分配了内存。函数的static变量在执行此函数时进行实例化。

  十 指针和引用

  指针是一个变量,存放地址的变量,指向内存的一个存储单元,引用仅是个别名。

  引用必须被初始化, 指针不必

  引用使用时无需加*。

  引用没有const修饰,指针有const修饰

  sizeof引用对象得到的是所指对象,变量的大小;sizeof指针得到的是指针本身的大小

  指针可有多级,引用只可一级

  内存分配上,程序为指针变量分配内存,不为引用分配内存。

  1. 引用作为参数的优点:

  (1)传递引用给函数与传递指针的效果是一样的。

  (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!;

  (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

  2. 注意:

  (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)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

  3. 引用与多态的关系?

  引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例

  十一 内存

  1.内存类别

  栈 --由编译器自动分配释放, 局部遍历存放位置

  堆 --由程序员分配和释放.

  全局区(静态区) --全局变量和静态变量的存储是放在一起的, 初始化的全局变量和static静态变量在一块区域.

  程序代码区 --存放二进制代码.

  在函数体中定义的变量通常是在栈上, 用malloc, 等分配内存的函数分配得到的就是在堆上. 在所有函数体外定义的是全局量, 加了static修饰符后不管在哪里都存放在全局区, 在所有函数体外定义的static变量表示在该文件有效, 不能extern 到别的文件用. 在函数体内定义的static表示只在该函数体内有效.

  2. 堆栈溢出的原因:

  数组越界, 没有回收内存, 深层次递归调用

  3. 内存分配方式

  内存分配的三种方式: a 静态存储区,程序编译时便分好, 整个运行期间都存在,比如全局变量,常量; b, 栈上分配; 堆上分配。

  4. 避免内存泄漏

  原因:动态分配的内存没有手动释放完全.

  避免:使用的时候应记得指针的长度; 分配多少内存应记得释放多少, 保证一一对应的关系; 动态分配内存的指针最好不要再次赋值.

C++笔试选择题相关推荐