C++面试题及解释

来源:互联网 发布:java多线程并发测试 编辑:程序博客网 时间:2024/05/16 02:00

1.C与C++的异同,优劣。

rong:http://blog.csdn.net/rongwenbin/article/details/20143385


2.C,C++,VC,BC,TC的区别。

rong:不同之处是不同版本(或厂商)的编译器,当然不同版本或厂商的编译器就可能带不同的库文件或工具或宏。


3.C++中try…catch关键字的用法与优点。

http://blog.csdn.net/rongwenbin/article/details/20534607


4.枚举的用法,以及它与宏的区别。

枚举常量与宏的区别主要有几点:
(1)枚举常量是实体中的一种,但宏不是实体;
(2)枚举常量属于常量,但宏不是常量;
(3)枚举常量具有类型,但宏没有类型,枚举变量具有与普通变量相同的诸如作用域、值等性质,但宏没有,宏不是语言的一部分,它是一种预处理替换符。枚举类型主要用于限制性输入,例如,某个函数的某参数只接受某种类型中的有限个数值,除此之外的其它数值都不接受,这时候枚举能很好地解决这个问题。能用枚举尽量用枚举,否则在调试的时候你是看不到当时的值的。
(4)用宏去定义一个变量如果你定义了一个相同的变量那么要看谁在前面,如果宏在前面变量会产生编译错误,而且这个错误很难查找,如果那个宏隐藏的很深的话。如果你定义的变量在前那么更可怕了,直接没有错误,但是宏定义被自定义的变量悄悄替换了。用枚举定义的话不管你定义的顺序前后关系怎样都会产生重复定义的错误。从上面的举例来看枚举比宏好用的多。宏还有一个特性是没有作用域,这里的作用域是指宏定义以后的代码都可以使用这个宏。宏可以被重复定义这个可能导致宏的值被修改。所以建议不要用宏去定义整形的变量,用枚举或者const。又会有用const还是枚举呢,世界一向如此纠结,枚举只能表示整形,const可以修饰任何类型。整形的情况下如果你要定义几种有关系的数值那么用枚举,否则用const。


5.const的用法,以及声明const变量与宏的区别;
const的用法有四种:

(1) const常量,如const int max = 100;

(2) const 修饰类的数据成员;

(3) const修饰指针的情况;

(4) 在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。

区别:

(1)const常量有数据类型, 而宏常量没有数据类型;

(2)编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有类型安全检查,而且字符替换可能会带来料想不到的边界效应;

(3) 有些集成化工具可以对const常量进行调试, 但不能对宏量进行调试。


6.C++中引用与指针的区别;
答:

(1) 引用实际上是所引用的对象或变量的别名,而指针是包含所指向对象或变量的地址的变量。
(2) 引用在定义时必须初始化,而指针在定义时不初始化。
(3) 不可以有NULL的引用,而可以有指向NULL的指针。
(4) 引用在初始化后不可以改变引用关系,而指针可以随时指向其他对象(非const指针)。


7.C++中virtual与inline的含义分别是什么?
答:

在基类成员函数的声明前加上virtual关键字,意味着将该成员函数声明为虚函数。
inline与函数的定义体放在一起,使该函数称为内联。inline是一种用于实现的关键字,而不是用于声明的关键字。
虚函数的特点;如果希望派生类能够重新定义基类的方法,则在基类中将该方法定义为虚方法,这样可以启用动态联编。
内联函数的特点;使用内联函数的目的是为了提高函数的运行效率。内联函数体的代码不能过长,因为内联函数省去调用函数的时间是以代码膨胀为代价的内联函数不能包含循环语句,因为执行循环语句要比调用函数的开销大。
一个函数能否即是虚函数又是内联函数?可以,建议不使用?


8.以下关键字的含义与用法:
extern,extern “C”,static,explicit,register,#undef,#ifndef

百度文库《c++中explicit关键字的含义和用法》
c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显式而什么又是隐式的呢?

C语言register关键字—最快的关键字http://blog.csdn.net/rongwenbin/article/details/20553589


9.什么是函数重载与覆盖?
为什么C不支持函数重载?
为什么C++能支持函数重载?


10.VC中,编译工具条内的Debug与Release选项是什么含义?

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。Debug带有大量的调试代码,运行时需要相应的运行库,发布模式程序紧凑不含有调试代码和信息,直接可以运行(如果不需要运行库)

11.编写my_memcpy函数,实现与库函数memcpy类似的功能,不能使用任何库函数;
 void* mymemcpy(void* pvTo, const char* pvFrom, size_t size)
 { assert((dest != NULL) && (src != NULL));
   byte* psTo = (byte*)pvTo;
   byte* psFrom = (byte*)pvFrom;
   while (size– > 0)
   {*psTo++ = *psFrom++;}
   return pvTo;
 }


12.编写my_strcpy函数,实现与库函数strcpy类似的功能,不能使用任何库函数;
答:char* my_strcpy(char* strdest, const char* strsrc)
 { assert((strdest != NULL) && (strsrc != NULL))
   char* address = strdest;
   while((*strdest++ = *strsrc++) != NULL)
   return address;
 }


13.编写gbk_strlen函数,计算含有汉字的字符串的长度,汉字作为一个字符处理;
已知:汉字编码为双字节,其中首字节<0,尾字节在0~63以外。(如果一个字节是-128~127)


  1. #include <iostream>  
  2. using namespace std;  
  3. /* 
  4. 13.编写gbk_strlen 函数,计算含有汉字的字符串的长度,汉字作为一个字符处理; 
  5. 已知:汉字编码为双字节,其中首字节<0,尾字节在0~63 以外;(如果一个字节是-128~127) 
  6. */  
  7.   
  8. int gdk_strlen(const char *addr){  
  9.     const char *p=addr; //p用于后面的遍历  
  10.     while (*p)  //当遇到\0时结束  
  11.     {  
  12.         if ((*p<0)&&(*(p+1)<0||*(p+1)>63)) //如果是汉字,作为一个字符处理。
  13.         {  
  14.         addr++;   
  15.         p+=2;  
  16.         }  
  17.         else//否则向前移动一步  
  18.             p++;  
  19.         }  
  20.     }  
  21.     return p-addr; //首地址和末地址之差为含有汉字的字符串长度  
  22. }  
  23.   
  24. void main(){  
  25.     char s[10]="ab含d汗";  
  26.     int a=gdk_strlen(s);  
  27.     cout<<a<<endl;  
  28.     system("pause");  



14.函数assert的用法?
答:断言assert是仅在debug版本起作用的宏,用于检查“不应该“发生的情况。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。

对于断言 ASSERT 的理解:http://blog.csdn.net/rongwenbin/article/details/20561111


15.为什么在头文件的最前面都会看到这样的代码:
#ifndef _STDIO_H_
#define _STDIO_H_

头文件中的#ifndef一般格式是这样的#ifndef <标识> ,#define <标识>;<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h。

#ifndef _STDIO_H_
#define _STDIO_H_


16.为什么数组名作为参数,会改变数组的内容,而其它类型如int却不会改变变量的值?

答:当数组名作为参数时,传递的实际上是地址。而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调函数内部对形参的改变并不影响实参的值。


==========================================================

1.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。


2.写一个函数,将其中的\t都转换成4个空格。


3.Windows程序的入口是哪里?写出Windows消息机制的流程。

WinMain
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
 {
 if (bRet == -1)
 {
 // handle the error and possibly exit
 }
 else
 {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
 }
 }


4.如何定义和实现一个类的成员函数回调函数


5.C++里面是不是所有的动作都是main()引起的?如果不是,请举例。

不是,对于C++程序而言,静态变量、全局变量、全局对象的分配早在main( )函数之前已经完成。所以并不是所有的动作都是由main( )引起的,只是编译器是由main( )开始执行的,main( )只不过是一个约定的函数入口,在main( )函数中的显示代码执行之前,会调用一个由编译器生成的_main( )函数,而_main( )函数会进行所有全局对象的构造及初始化工作。
以如下程序示例代码为例:

class A{};

A a;

int main( )

{



}

程序在执行时,因为会首先初始化全局变量,当这个变量是一个对象时,则会首先调用该对象的构造函数,所以上例中,a的构造函数先执行,然后再执行main( )函数。C++中并非所有的动作都是main( )引起的。
怎样在main( )函数退出之后再执行一段代码?答案依然是全局对象,当程序退出时, 全局变量必须销毁,自然会调用全局对象的析构函数,所以剩下的就同构造函数一样了。
转载自新书《程序员面试笔试宝典》官网。


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

在该函数前添加extern “C”声明。


7.下列哪两个是等同的
  int b;
  A const int* a = &b;
  B const* int a = &b;
  C const int* const a = &b;
  D int const* const a = &b;


关键问题点:const 属于修饰符 ,关键是看const 修饰的位置在那里
(1)、const int *a
这里const 修饰的是int,而int定义的是一个整值。
因此*a 所指向的对象 值 不能通过 *a 来修改,但是 可以重新给 a 来赋值,使其指向不同的对象。
eg:
       const int *a = 0;
       const int b = 1;
       int c = 1;
       a = &b  //ok!  额外:注意不能通过a 来修改 b值
       a = &c  //ok!   额外:虽然c本身不是一个常量
      *a = 2  //erro! 为题就在这里,不能修改通过 *a 所指向的对象值,最后赋值得对象是c,因此不能通过*a 来修改c值。

(2)、int  *const a       
这里const修饰的是 a ,a代表的是一个指针地址。
因此不能赋给a其他的地址值,但可以修改a指向的值。
这有点和cont int *a相反的意味,例子就不说了。

(3)、至于int const *a 和 const int *a 的意义是相同的 他们两个的作用等价。

补充:
(4)、const int * const a
这个代表a所指向的对象的值以及它的地址本身都不能被改变。

关于const的点滴补充:
(1)、const 对象的地址只能赋值给指向const 对象的指针。
(2)、指向const 对象的指针可以 被赋 以 一个非const 对象的地址 。
(3)、指向const 得指针常被用作函数的形式参数,保证被传递给函数的实际对象在函数得实际对象在函数中不会被修改。
(4)、常量在定义后就不能被修改,所以它必须被初始化。未初始化的常量定义将导致编译错误(上面都是在说明const得问题,所以没有赋值,实际语句中要赋值的)。


8.内联函数在编译时是否做参数类型检查?
  void g(base & b){
   b.play;
  }
  void main(){
   son s;
   g(s);
   return;
  }


0 0
原创粉丝点击