各类C++/C程序员面试题

1.static有什么用途?(请至少说明两种)

    (1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;

  (2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

  (3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

  (4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

2.引用与指针有什么区别?

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

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

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

3. 什么是引用?申明和使用引用要注意哪些问题?

答:引用就是某个目标变量的别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。

4. 引用作为函数参数有哪些特点?

1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

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

5.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

      全局变量储存在静态数据库,局部变量在堆栈。

6.堆栈溢出一般是由什么原因导致的?

      没有回收垃圾资源。

具体 :分配的数组过大, 函数递归的层次过深。等。

7.分别写出BOOL,int,float,指针类型的变量的比较语句。

答案:

BOOL :    if ( !a ) or if(a)

int :     if ( a == 0)

float :   const EXP = 0.000001

          if ( a < EXP && a >-EXP)

pointer : if ( a != NULL) or if(a == NULL)    

(.写出float x 与“零值”比较的if语句。)

      if(x>0.000001&&x<-0.000001)

8. 什么时候需要引用

流操作符<<>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数都推荐使用引用。

9. 结构与联合有和区别?

1. 结构和联合都是由多个不同的数据类型成员组成但在任何同一时刻联合中只存放了一个被选中的成员(所有成员共用一块地址空间)而结构的所有成员都存在(不同成员的存放地址不同)。 

 2. 对于联合的不同成员赋值将会对其它成员重写,  原来成员的值就不存在了而对于结构的不同成员赋值是互不影响的。

.不能做switch()的参数类型是:

     switch的参数不能为实型。

10 头文件中的ifndef/define/endif 的作用?

答:防止该头文件被重复引用。

11. include<file.h> 与 #include "file.h"的区别?

答:前者是从系统标准目录的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h

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

首先,作为externC/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。

通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数

extern "C"是连接申明,extern "C"修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: 

void foo( int x, int y );

该函数被C编译器编译后在符号库中的名字为foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制)。

_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void  foo( int  x, int y )void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float

13. New delete malloc free 的联系与区别?

答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的析构函数,而free 不会调用对象的析构函数.

14. cstruct c++ class 的区别

答案:struct 的成员默认是公有的,而类的成员默认是私有的。

Cstruct不能包含成员函数,c++class可以包含成员函数。

15 说说Const的作用?

1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

  (2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;

  (3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

  (4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

  (5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为"左值"

写一个程序, 要求功能:求出用1,2,5这三个数不同个数组合的和为100的组合个数。

如:100个1是一个组合,5个1加19个5是一个组合。。。。 

答案:最容易想到的算法是:

设x是1的个数,y是2的个数,z是5的个数,number是组合数

注意到0<=x<=100,0<=y<=50,0<=z=20,所以可以编程为:

number=0;

for (x=0; x<=100; x++)

for (y=0; y<=50; y++)

for (z=0; z<=20; z++)

if ((x+2*y+5*z)==100)

number++;

cout<<number<<endl;

上面这个程序一共要循环100*50*20次,效率实在是太低了

事实上,这个题目是一道明显的数学问题,而不是单纯的编程问题。

因为x+2y+5z=100

所以x+2y=100-5z,且z<=20 x<=100 y<=50

所以(x+2y)<=100,且(x+5z)是偶数

对z作循环,求x的可能值如下:

z=0, x=100, 98, 96, ... 0

z=1, x=95, 93, ..., 1

z=2, x=90, 88, ..., 0

z=3, x=85, 83, ..., 1

z=4, x=80, 78, ..., 0

......

z=19, x=5, 3, 1

z=20, x=0

某个偶数m以内的偶数个数(包括0)可以表示为m/2+1=(m+2)/2

某个奇数m以内的奇数个数也可以表示为(m+2)/2

所以,求总的组合次数可以编程为:

number=0;

for (int m=0;m<=100;m+=5)

{

number+=(m+2)/2;

}

cout<<number<<endl;

这个程序,只需要循环21次,

那么,那种最容易想到的算法就完全没有用吗?不,这种算法正好可以用来验证新算法

的正确性,在调试阶段,这非常有用。在很多大公司,例如微软,都采用了这种方法:在调

试阶段,对一些重要的需要好的算法来实现的程序,而这种好的算法又比较复杂时,同时用

容易想到的算法来验证这段程序,如果两种算法得出的结果不一致(而最容易想到的算法保

证是正确的),那么说明优化的算法出了问题,需要修改。

 

2、实现一个函数,把一个字符串中的字符从小写转为大写。

#include "stdio.h"

#include "conio.h"

void uppers(char *s,char *us)

{

for(;*s!='\0';s++,us++)

{

if(*s>='a'&&*s<='z')

*us = *s-32;

else

*us = *s;

}

*us = '\0';

}

int main()

{

char *s,*us;

char ss[20];

printf("Please input a string:\n");

scanf("%s",ss);

s = ss;

uppers(s,us);

printf("The result is:\n%s\n",us);

getch();

}

请在小于99999的正整数中找符合下列条件的数,它既是完全平方数,又有两位数字相同,如:144,676。

#include<stdio.h>
#include<math.h>
//函数havesamenum确认num是否满足条件
int havesamenum(int num)
{
 int i=0,j;
 char a[10] = {0};
 
 while(num>0)
 {
  j=num%10;
  a[j]+=1;
  num=num/10;
 }
 while(a[i]<=1&&i<10)
  i++;
 if (i<10) 
  return 1;
 else 
  return 0;
}
void main(void)
{
   int i,j,m;
 
 m=(int)sqrt(99999);
 for(i=1;i<m;i++)
 {
     j=i*i;
     if (1==havesamenum(j)) 

     printf("%6d\t",j);
 }
}

 C++软件工程师面试题

1、 c++是面向对象的编程语言吗?C++中虚函数(virtual) 是什么?有什么好处? 

   (1)C++不是纯面向对象的语言,C++是面向对象和过程的,因为C++支持类和过程。

   (2)虚函数(virtual)具有传递性,即子类中对父类的虚函数的重写,也是一个虚函数  ,不过函数的参数表也要一样。

   (3)可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,而不是基类中定义的成员函数(只要派生类改写了该成员函数)。若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都会调用基类中定义的那个函数。

   

2、 谈谈指针和引用的区别?

    指针用操作符“*”和“->”,引用使用操作符“&”.

    相同点是:指针与引用都是让你间接引用其他对象。

    区别:(1). 指针是一个实体,指向一块内存,它的内容是所指内存的地址;而引用仅是个别名,是某块内存的别名。

          (2). 引用使用时无需解引用(*),指针需要解引用;

          (3). 引用只能在定义时被初始化一次,之后不可变,“从一而终”;指针可变; 

          (4). 引用没有 const类型,指针有 const类型,const 的指针不可变;

          (5). 引用不能为空,指针可以为空;

          (6). “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。

          (7). 指针和引用的自增(++)运算意义不一样;

3.   int m = 100,n = 101; 

     int &k = m;

     k = n;  //此时K,m值分别是多少 ?  

   k和m的值都是101,因为k是对m的引用,k值发生变化,m值也发生着变化。

4、 c++中 const修饰符一般用于那几种情况,具体作用是什么?

   (1).用常量定义 const int n = 100;

       用于常量参数 即 fn(const int & a)

       用于常量函数,即类的该函数不修改其状态。

       用于返回值

   (2).可以定义const常量,具有不可变性; 便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患; 可以保护被修饰的东西,防止意外的修改,增强程序的健壮性;为函数重载提供了一个参考; 可以节省空间,避免不必要的内存分配;提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 

5、 你在程序代码中用assert吗?assert一般用于做什么? 

    (1) 是我常用。

    (2)主要用于DEBUG下断言,即假设一定是这样的,否则就是错误的。例如  asser ( a > 100 );

6、 i++ 相比 ++i 哪个更高效?为什么?

   答:(1)++i 比 i++效率高。

       (2)i++要多调用一次类的构造和析够函数

7、 windows平台下网络编程有哪几种网络编程模型?你最熟悉的是哪种?并对他们作个比较?

   (1)有阻塞,select,基于窗体的事件模型,事件模型,重叠模型,完成端口模型。

   (2)我最熟悉的是事件模型。

   (3)除了阻塞模型外,其他都是非阻塞模型,其中效率最高的是完成端口模型,尤其在windows下服务器最合适了。

     做客户端一般用事件模型了,select,在window和like unix都可以使用。

8、 tcp进行传输时,接收方怎么告诉发送方“我已经处理不过来了,先不要再发数据给我。”

    答:接受方给发送方发一个通知数据包,该通知包让发送方暂停数据的发送,或方慢发送。等接受方处理完毕后,再发一个恢复的通知数据包。

     

9、 设计udp网络协议包设计 包多大合适,为什么?

    答:最好设计成MTU的大小,MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。这样的话传输速度会快。

10、 线程有什么好处和坏处,什么情况下不需要用线程?什么情况下用线程能增加效率?

    答:多线程的使用于有多个任务需要同时的执行,能使同时执行多个任务。在这种情况下是用线程会提高效率。

 在单个任务下不需要用线程,一般情况如果有个很占时间的任务需要去做,这是就要用的线程了,但它也会带来麻烦,即多个线程的同步问题。

 

posted @ 2013-12-26 09:35  ZhangAihua  阅读(458)  评论(0编辑  收藏  举报