欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

50道C/C++经典面试题

程序员文章站 2022-03-20 16:53:57
文章转载自:http://www.pythonheidong.com/blog/article/2558/ C/C++经典面试题 1, 变量的声明和定义有什么区别 为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但只能在一个地方定义。加入extern 修饰的是变 ......

文章转载自:

c/c++经典面试题

1,  变量的声明和定义有什么区别

 为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但只能在一个地方定义。加入extern 修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义

说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。

2,  写出 bool int float 指针变量与零值比较的if语句

bool型数据

if(flag)

if(!flag)

 

int型数据:
if(0!=flag)

if(0==flag)

 

指针型数据:
if(null==flag)

if(nujll!=flag)

 

float 型数据:

define norm 0.00001;
if(flag>=-norm && flag<=norm)

 

注意:应特别注意在int,指针型变量和零值比较的时候,把零值放在左边,这样当把==误写成=时,编译器可以报错,否则这样逻辑错误不容易发现,并且可能导致很严重的后果。

 

3,  sizeof和strlen的区别

 sizeof和strlen有一下区别:
sizeof是一个操作符,strlen是库函数

sizeof的参数可以使数据的类型,也可以是变量,而strlen只能是以‘\0’为结尾的字符串作参数。

编译器编译是就计算出了sizeof的结果,而strlen函数必须在运行是才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度

数组做sizeof的参数不退化,传递strlen就退化成为指针了。

注意:有些操作符看起来像是函数,而有些函数名看起来又像操作符,这类容易混淆的名称一定要加以区分,否则遇到数组名这类特殊数据类型做参数时就很容易出错。最容易混淆为函数的操作符就是sizeof。

4,

c语言的关键字static和c++的关键字static有什么区别

在c中static用来修饰局部静态变量和外部静态变量,函数。而c++中除了上述功能外,还用来定义类的成员变量和函数,即静态成员变量和静态成员函数

注意:编程时static的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传递信息,而c++的静态成员则可以在多个对象实例间进行通信,传递信息。

5.c中的malloc和c++中的new有什么区别

malloc和new有一下不同:
new,delete是操作符,可以重载,只能在c++中使用

malloc,free是函数,可以覆盖,c,c++中都可以使用

new可以调用对象的构造函数,对应的delete调用相应的析构函数

malloc仅仅分配内存,free仅仅回收内存,并不执行构造函数和析构函数

new delete返回的是某种数据类型指针,malloc free返回的是void指针

注意:malloc申请的内存空间要用free释放,而new申请的内存空间要用delete释放,不要混淆,因为两者实现的机理不同

 

6,写一个标准的宏min

#define min(a,b)((a)<=(b)?(a):(b))

注意:在调用时一定要注意这个宏定义的副作用,如下调用

(++*p)<(x)?(++*p):(x)

p指针就自加了两次,违背了min的本意。

7,一个指针可以使volatile吗

8,a和&a有什么区别

请写出以下代码的打印结果,主要目的是考察a和&a的区别

#include<stdlo.h>

void main()

{

int a[5]={1,2,3,4,5};

int *ptr=(int *)(&a+1);

printf(“%d,%d”,(a+1),*(ptr-1));

return ;

}

输出结果:2,5

注意:数组名a可以作数组的首地址,而&a是数组的指针。

思考,将原式的int* ptr=(int *)(&a+1);

该为int *ptr=(int *)(a+1)时输出的结果将是什么呢

 

9,简述c,c++程序编译的内存分配情况

c,c++中内存分配方式可以分为三种:
(1)从静态存储区域分配:
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在,速度快,不容出错,因为有系统会善后,例如,全局变量,static变量等

(2)在栈上分配:
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数在执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3)从堆上分配:
即动态内存分配,程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄露,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎片。

一个c,c++程序编译时内存分为5大存储区:堆区,栈区,全局区,文字常量区,程序代码区

10,简述strcpy,sprintf与memecpy的区别

三者主要有以下不同之处

(1)       操作对象不同:strcpy的两个操作对象均为字符串,sprintf的操作对象可以是多种数据类型,目的操作对象是字符串,memcpy的两个对象是两个任意可操作的内存地址,并不限于何种数据类型。

(2)       执行功能不同:strcpy主要实现字符串变量间的拷贝,sprintf主要实现其他数据类型格式到字符串类型的转化,memcpy主要是内存块间的拷贝

(3)       执行效率不同:memcpy最高,sprintf最低

说明:strcpy,sprintf,memcpy都可以实现拷贝的功能,但是针对的对象不同,根据实际需求,来选择合适的函数实现拷贝功能

11,设置地址为ox67a9的整形变量的值为oxaa66

int *ptr;

ptr=(int *)ox67a9;

*ptr=oxaa66;

说明:这道题就是强制类型转换的典型例子,无论在什么平台地址长度和整型数据的长度是一样的,即一个整型数据可以强制转换成地址指针类型,只要有意义即可。

12,面向对象的三大特征:
面向对象的三大特征是封装性,继承性,多态性。//有待完善

13.c++的空类有哪些成员函数

(1)缺省的构造函数

(2)缺省的拷贝构造函数

(3)缺省的析构函数

(4)缺省的赋值运算符

(5)缺省取址运算符

(6)缺省取址运算符const

注意:有些书上只是简单的介绍了前四个函数,没有提及后面两个函数,但后两个函数也是空类的默认函数。另外西药注意的是,只有当实际使用这些函数的时候,编译器才会定义他们。

14,谈谈你对拷贝构造函数和赋值运算符的认识

拷贝构造函数和复制运算符重载有以下两个不同之处:
(1)拷贝构造函数生成新的类对象,而赋值运算不能

(2)由于拷贝 构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同,而赋值运算符则需要这个操作,另外赋值运算符中如果原来的对象中内存非配要先把内存释放掉

注意:当类中 有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。

17:简述类成员函数的重写,重载和隐藏的区别

(1)       重写和重载主要有以下几点不同:
范围区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中

参数的区别:被重写的函数和重写的函数的参数列表一定相同,而被重载函数和重载函数的参数列表一定不同

virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函数可以被virtual修饰,也可以没有。

(2)隐藏和重写,重载有以下几点不同:

与重载的范围不同,和重写一样,隐藏函数和被隐藏函数不在同一个类中

参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同,也可以不同,但是函数名肯定要相同。当参数不相同是,无论基类中的参数是否被virtual修饰,基类的函数都是被隐藏,而不是被重写。

说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不同,达到的目的也是完全不同的,覆盖是动态绑定的多态,而重载是静态绑定的多态

18简述多态实现的原理

编译器发现一个类中有虚函数,便会立即为此类生成虚函数表vtable,虚函数表的各表项为指向对应虚函数的指针,编译器还会在此类中隐含插入一个指针vptr(对vc编译器来说,它插在类中的第一个位置上)指向虚函数表,调用此类的构造函数时,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable联系起来,另外在调用类的构造函数时,指向基类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。

注意:一定要区分虚函数,纯虚函数,虚拟继承的关系和区别。牢记虚函数实现原理,因为多态c++面试的重要考点之一,而虚函数是实现多态的基础。

 

19,链表和数组有什么区别

数组和链表有以下几点不同:
(1)存储形式:数组是一块连续的空间,声明时就要确定长度,链表是一块不连续的动态空间,长度可变,每个结点要保存相邻结点的指针。

(2)       数据查找:数组的线性查找速度快,查找操作直接使用偏移地址,链表需要按顺序检索结点,效率低

(3)       数据插入和删除:链表可以快速插入和删除结点,而数组则可能需要大量数据移动。

(4)       越界问题:链表不存在越界问题,数组有越界问题

说明:在选择数组或链表数据结构时,一定要根据实际需要进行选择,数组便于查询,链表便于插入和删除,数组节省空间但长度固定,链表虽然变长但是占了更多的存储空间

20,怎么吧一个单链表反序

 

21,简述队列和栈的异同

队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是先进先出,栈是后进先出

注意:区别栈区和堆区,堆区的存取是顺序随意,而栈区是后进先出,栈由编译器自动分配,存放函数的参数值,局部变量的值等,其操作方式类似数据结构中的栈,堆一般由程序员分配释放,若程序员不释放,程序结束时可能由os回收,分配方式类似于链表

它与本题的的堆和栈是两回事,堆栈只是一种数据结构,而堆区和栈区是程序中的不同内存存储区域

 

22-28各种排序算法

 

29谈谈你对编程规范的理解或认识

编程规范可总结为:程序的可行性,可读性,可移植性,以及可测试性

说明:这是编程规范的总纲目,面试者不一定要去背诵上面给出的那几个例子,应该去理解这几个例子说明的问题,想一想,自己如何解决可行性,可读性,可移植性,以及可测试性这几个问题,结合上几个例子和自己平时的编程习惯来回答这个问题

30 short i=0;i=i+1l; 这两句有错吗

代码一是错的,代码二十正确的

说明:在数据安全的情况下,大类型的数据向小类型的数据转换一定要显示的强制类型转换

 

31,&& 和& ,||和|有什么区别

(1)&和|对操作数进行求值运算,&&和||是判断逻辑关系

(2)&&和|| 在判断左操作数就能确定结果的情况下就不再对右操作数求值。

注意:在编程的时候有些时候将&& 或||替换成&和 |没有出错,但是其逻辑是错误的,可能导致不可预测的后果。

 

32c++的引用和c语言的指针有什么区别

指针和引用主要有一下区别:
(1)引用必须被初始化,但是不分配存储空间,指针在声明时初始化,在初始化的时候需要分配存储空间。

(2)引用初始化以后不能被改变,指针可以改变所指向的对象

(3)不存在指向空值的引用,但存在指向空值的指针

注意:引用作为函数的参数时,会引发一定的问题,因为让引用做参数,目的就是想改变这个引用所指向地址的内容,而函数调用时传入的是实参,看不出函数的参数是正常变量还是引用,因此可能会引发错误,所以使用时一定要小心。

 

33,适当的数据结构为更好的算法设计提供了有利的条件

 

35typedef和define有什么区别

(1)       用法不同:typedef用来定义一种数据类型的别名,增强程序的可读性,define主要用来定义常量,以及书写复杂使用频繁的宏

(2)       执行时间不同,typedef是编译过程的一部分,有类型检查得功能,define是宏定义,是预编译的步部分,起发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查

(3)       作用域不同:typedef有作用域限定,define不受作用域约束,只要define声明后的引用都是正确的。

(4)       对指针的操作不同,typedef和define定义的指针时有很大的区别

(5)       注意:typedef定义是语句,因为句尾要加分号,而define不是语句,千万不能在句尾加分号。

36关键字const是什么

const用来定义一个只读的变量或对象。主要优点:便于类型检查,同宏定义一样可以方便的进行参数的修改和调整,节省空间,避免不必要的内存分配、可为函数重载提供参数。

说明:const修饰函数参数,是一种编程规范的要求,便于阅读,一看即知这个参数不能被改变,实现时不易出错

 

37static有什么作用

static在c中主要用于定义全局静态变量,定义局部静态变量,定义静态函数,在c++中新增了两个作用,定义静态数据成员,定义静态函数成员

注意:因为static定义的变量分配在静态区,所以其定义的变量的默认值为0,普通的变量的默认值为随机数,在定义指针变量时要特别注意。

 

extern有什么作用

extern标识的变量或函数声明起定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找定义

 

39流操作符重载为什么返回引用

在程序中,流操作符>>和<<经常连续使用,因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用,其他的数据类型都无法做到这一点。

注意:出来在复制操作符和流操作符之外的其他的一些操作符中,如+-*/却千万不能返回引用,因为这死者操作符的对象都是右值,因此他们必须构造一个对象作为返回值。

40,简述指针常量与常量指针区别

指针常量是指定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变,常量指针是指定义了一个指针,这个指针指向一个只读的对象,不能通过常量指针来改变这个对象的值。

指针常量强调的是指针的不可改变性,而常量指针强调的是指针对其所指对象的不可改变性

注意:无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数中的不可改变性。

 

41数组和指针的区别,即字符数组和字符串指针的区别

 

42如何避免“野指针”

野指针产生原因及解决办法如下:
(1)指针变量声明时没有被初始化,解决办法:指针声明时初始化,可以是具体的地址值,也可以是让他指向null

(2)指针p被free或者delete之后,没有置为null。解决办法:指针指向的内存空间被释放后指针应该指向null

(3)指针操作超越了变量的作用范围,解决办法:在变量的作用域结束前释放掉变量的地址空间,并让指针指向null

注意:野指针的解决方法也是编程规范的基本原则,平时使用指针时一定要避免产生野指针,在使用指针前一定要检验指针的合法性

 

43常引用有什么作用

常引用的引入主要是为了避免使用变量的引用时,在不知道的情况下改变变量的值,常引用主要用于定义一个普通变量的只读属性的别名,作为函数的传入参数,避免实参在调用函数中被意外的改变。

说明:很多情况下,需要用常引用做形参,被引用对象等效于常对象,不能在函数中改变实参的值,这样的好处是有较高的易读性和较小的出错率。

49,构造函数能否为虚函数

构造函数不能是虚函数,而且不能在构造函数中调用虚函数,因为那样实际执行的是父类的对应的函数,因为自己还没有构造好,析构函数可以是虚函数,而且在一个复杂类结构中,这往往是必须的。析构函数也可以是纯虚函数,但纯虚函数必须有定义体,因为析构函数的调用是在子类中隐含的。说明:虚函数的动态绑定特性是 实现重载的关键技术,动态绑定根据实际的调用情况查询相应类的虚函数表,调用相应的虚函数。

 

50谈谈你对面向对象的认识

面向对象可以理解成对待每一个问题,都是首先要确定这个问题由几个部分组成,而每一个部分其实就是一个对象,然后再分别设计这些对象,最后得到整个程序,传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象的角度来考虑问题的。这样做能够是得程序更加简洁清晰。

说明:编程中接触最多的面向对象编程技术仅仅是面向对象技术中的一个组成部分,发挥面向对象技术的优势是一个综合的技术问题,不仅仅需要面向对象的分析,设计和编程技术,而且需要借助必要的建模和开发工具。

 

文章转载自: