C/C++常见面试题整理

前段时间有不少同学在后台问是否有C/C++相关面试题,本人近半年基本上都是在C/C++开发,我也在不断学习和总结着,C/C++有一些非常有意思的点,不同于Java及C#。尤其是C++11,C++14,C++17越来越丰富了C++语言。C++修炼要比Java及C#要长。一步一步来吧。总结的答案不一定都对,一定自己去使用VS实践一把,才能领会。

1、C++里面如何声明const void f(void)函数为C程序中的库函数?

  • 【参考答案】: 在该函数前添加extern “C”声明。由于编译后的名字不同,C++程序不能直接调用C 函数。

2、c++中类和c语言中struct的区别(至少两点)

  • 【参考答案】:

  • (1) c++中的类默认的成员是私有的,struct默认的是共有的。

  • (2) c++中的类可以定义成员函数,struct只能定义成员变量。

3、变量的声明和定义有什么区别?

  • 【参考答案】: 声明变量不分配空间,定义变量要分配空间。声明主要是告诉编译器,后面的引用都按声明的格式。定义其实包含了声明的意思,同时要分配内存空间。

4、memset ,memcpy 的区别

  • 【参考答案】: memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为’\0′。 memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;

5、程序什么时候应该使用线程,什么时候单线程效率高。

  • 【参考答案】:

  • 1 耗时的操作使用线程,提高应用程序响应

  • 2 并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。

  • 3 多CPU系统中,使用线程提高CPU利用率

  • 4 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。 其他情况都使用单线程。

6、介绍一下模板和容器。如何实现?(也许会让你当场举例实现)

  • 【参考答案】: 模板可以说比较古老了,但是当前的泛型编程实质上就是模板编程。 它体现了一种通用和泛化的思想。 STL有7种主要容器:vector,list,deque,map,multimap,set,multiset.

7、以下为WindowsNT下的32位C++程序,请计算sizeof的值

 
   
  1. charstr[]=“Hello”;

  2. char*p=str;

  3. intn=10;

  4. //请计算

  5. sizeof(str)=?

  6. sizeof(p)=?

  7. sizeof(n)=?

  8. voidFunc(charstr[100])

  9. {

  10. //请计算

  11. sizeof(str)=?

  12. }

  13. void*p=malloc(100);

  14. //请计算

  15. sizeof(p)=?

  16. 【参考答案】:

  17. sizeof (str ) = 6

  18. sizeof ( p ) = 4

  19. sizeof ( n ) =4

  20. void Func ( char str[100])

  21. {

  22. sizeof( str ) = 4

  23. }

  24. void *p = malloc( 100 );

  25. sizeof ( p ) =4

8、C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?inta=5,b=7,c;c=a+++b;

  • 【参考答案】: 这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成: c = a++ + b; 因此, 这段代码持行后a = 6, b = 7, c = 12。 如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题

9、#include与#include“file.h”的区别?

  • 【参考答案】: 前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

10、如何在C中初始化一个字符数组。

  • 【参考答案】: 这个问题看似很简单,但是我们要将最简单的问题用最严谨的态度来对待。关键的地方:初始化、字符型、数组。最简单的方法是char array[];。这个问题看似解决了,但是在初始化上好像还欠缺点什么,个人认为:char array[5]={’1′,’2′,’3′,’4′,’5′};或者char array[5]={“12345″};或者char array[2][10]={“China”,”Beijing”};也许更符合“初始化”的意思。

11、在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?

  • 【参考答案】: extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。

12、内存的分配方式的分配方式有几种?

  • 【参考答案】:

  • 1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。

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

  • 3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

13、在C++程序中调用被C编译器编译后的函数,为什么要加extern"C"?

  • 【参考答案】: C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);该函数被C编译器编译后在库中的名字为foo,而C++编译器则会产生像foointint之类的名字。C++提供了C连接交换指定符号extern"C"来解决名字匹配问题。

14、如何让局部变量具有全局生命期。

  • 【参考答案】: 具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

15、解释堆和栈的区别。

  • 【参考答案】: 具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

16、在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”声明?

  • 【参考答案】: 函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。

17、strtok函数在使用上要注意什么问题。

  • 【参考答案】: 这个问题我不知道能不能回答全面,因为实在是用的很少。这个函数的作用是分割字符串,但是要分割的字符串不能是常量,这是要注意的。比如先定义一个字符串:char array[]=”part1,part2″;,strtok的原形是char *strtok(char *string, char *delim);,我们将”,”作为分隔符,先用pt=strtok(array,”,”);,得到的结果print出来就是”part1″,那后面的呢,要写成pt=strtok(NULL,”,”);,注意,要用NULL,如果被分割的字符串会被分成N段,那从第二次开始就一直要用NULL。总结起来,需要注意的是:被分割的字符串和分隔符都要使用变量;除第一次使用指向字符串的指针外,之后的都要使用NULL;注意使用这个函数的时候千万别把指针跟丢了,不然就全乱了。

18、用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

  • 【参考答案】:#define SECONDSPERYEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情:

  • 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

  • 2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。

  • 3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。

  • 4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。

19、说一说C与C++的内存分配方式?

  • 【参考答案】:

  • 1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,如全局变量,static变量。

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

  • 3)从堆上分配(动态内存分配)程序在运行的时候用malloc或new申请任意多少的内存,程序员负责在何时用free或delete释放内存。动态内存的生存期自己决定,使用非常灵活。

20、头文件中的 ifndef/define/endif 干什么用?预处理

  • 【参考答案】: 防止头文件被重复引用

21、new、delete、malloc、free关系

  • 【参考答案】: delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

22、虚函数的作用是什么?

  • 【参考答案】:

  • 多态:调用同一个函数名,可以根据需要但实现不同的功能。

  • 主要是运行时多态。

  • 若要访问派生类中相同名字的函数,必须将基类中同名函数定义为虚函数,这样,将不同的派生类对象的地址赋值给基类指针变量后,就可以动态的调用不同类中的函数。

  • 在派生类中重新定义基类中的虚函数时,可以不用关键字virtual来修饰这个成员函数。

  • 在程序执行过程中,依据指针具体指向哪个对象,或依据引用哪个类对象,才能确定激活哪个版本,实现动态聚束。

23、虚析构的作用是什么?

  • 【参考答案】: 防止内存泄露,正确析构指向派生类实例的基类指针。 等同于做如下事情: Base* pA = new Derived(); delete pA;

24、什么是预编译,何时需要预编译:  

  • 【参考答案】:

  • (1) 总是使用不经常改动的大型代码体 

  • (2) 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头  

25、char * const p    char const * p    const char *p  上述三个有什么区别? 

  • 【参考答案】: 

  • char * const p; //常量指针,p的值不可以修改 

  • char const * p;//指向常量的指针,指向的常量值不可以改 

  • const char *p; //和char const *p 

26、C++ 标准库智能指针uniqueptr,sharedptr,weak_ptr介绍

  • 【参考答案】:

  • uniqueptr 只允许基础指针的一个所有者。 除非你确信需要 sharedptr,否则请将该指针用作 POCO 的默认选项。 可以移到新所有者,但不会复制或共享。 替换已弃用的auto_ptr。 

  • sharedptr 采用引用计数的智能指针。 如果你想要将一个原始指针分配给多个所有者(例如,从容器返回了指针副本又想保留原始指针时),请使用该指针。 直至所有sharedptr 所有者超出了范围或放弃所有权,才会删除原始指针。

  • weakptr 结合 sharedptr 使用的特例智能指针。 weakptr 提供对一个或多个 sharedptr 实例拥有的对象的访问,但不参与引用计数。 如果你想要观察某个对象但不需要其保持活动状态,请使用该实例。

27、介绍下右值引用和移动语义及完美转发,在那些场景中用到 此题留给大家一个思考

0?wx_fmt=jpeg

你可能感兴趣的:(C/C++常见面试题整理)