C++面试题

C++面试题

这是本人面试之前整理的C++面试题,感觉还可以,知识点挺全的,如果大家需要我会即时发布。

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

malloc freeC++/C语言的标准库函数,new/deleteC++的运算符。它们都可用于在堆区上申请动态内存和释放内存。

malloc函数需要指定分配的字节数并且不能初始化对象,new会自动调用对象的构造函数,delete会调用对象的析构函数,而free不会调用对象的析构函数。

1)      malloc free

函数原型:void* malloc(size_t size);

         调用方法:

         (数椐类型*malloc(size)

如: char* p;

p = (char*)malloc(100*sizeof(char));// 分配 100 个字节的内存空间

函数原型:void free(void *ptr);

         调用方法:

         free(void* ptr);

如: int *ip;

ip = (int*)malloc(100*sizeof(int));

free(ip);

 

2)      new delete

使用方法:

         type *p = new type;

         其中type是一个数椐类型,p是指向该类型的指针。

如: type *p = new type[size];

int *ip = new int[100];// 数组分配形式

int *iq = new int(100);// 单个变量分配并赋值。

使用方法:

delete p;// 单个变量

p = NULL;

delete []q;// 数组或结构的等多

q = NULL;    个变量。

 

2. #define DOUBLE(x) x+x i = 5*DOUBLE(5) i 是多少?

宏就是对字符串进行替换。

因此:i = 5*DOUBLE(5) 相当于 i = 5*x+x => i = 5*5+5

#include <iostream>

using namespace std;

#define DOUBLE(x) x+x

//#define DOUBLE(x) x+x

int main()

{

   double i = 0;

   cout << “i = ” << 5*DOUBLE(5) << endl;// 结果是 30

   return 0;

}

 

3. 有哪几种情况只能用intialization list 而不能用assignment?  ( 注意:把引用和对象成员的代码也加上吧)

答:1.当类中含有constreference 成员变量,对象成员;基类的构造函数都需要初始化。

2. 当基类有带参构造,子类就应当声明一个将参数传递给基类构造函数的途径。

3. 当基类派生子类对象时,就要对基类数据成员等初始化。

示例代码:

#include<iostream>

using namespace std;

 

class A

{

private:

   const int a; // const 成员

   const int b; // const 成员

public:

   A(int i,int j):a(i),b(j) // 必须在这里初始化

   {

 

   }

   void print()

   {

      cout << "a=" << a << ",b=" << b << endl;

   }

};

int main()

{

   A a(1,2);

   a.print();

 

   return 0;

}

 

#include<iostream>

using namespace std;

 

class A

{

private:

   int x1;

public:

   A(int i) // 只有一个带参的构造函数

   {

      x1 = i;

   }

   void printA()

   {

      cout << "x1=" << x1 << endl;

   }

};

class B:public A

{

private:

   int x2;

public:

   B(int i):A(i + 10) // 必须在这里初始化

   {

      x2 = i;

   }

   void printB()

   {

      printA();

      cout << "x2=" << x2 << endl;

   }

};

 

int main()

{

   B b(2);

   b.printB();

 

return 0;

}

4. 简述数组与指针的区别?

答: 数组与指针的区别?

1 、修改内容上的差别

char a[] = "abcd";

a[0] = 'e';

char *p = "abcd";//p 指向的是常量字符串

p[0] = 'e';// 编绎时不报错,运行时崩溃

2.sizeof() 值不同

cout << sizeof(a) << endl;// 5 计算的是数组的所占字节数

cout << sizeof(p) << endl;// 4 计算指针变量所占字节数

特殊情况:如果数组做函数的参数时行传递时 sizeof() 的值为 4

void show(char str[100])

{

 cout << sizeof(str) << endl;// 4 数组自动退化为同类型的指针

}

3 、指针的本质是一个与地址相关的复合类型,它的值是数据存放的位置(地址);数组的本质则是一系列的变量。

int a[10] = {0};

int *p = a;

cout << &a << endl;// 数组 a 的地址

cout << p << endl;//p 的值为数组 a 的地址

4 、数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。

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

int *p = a;

cout << p++ << endl;//p 指向发生变化

cout << a++ << endl;// 报错

问题:指针与数组
听说char a[]char *a是一致的,是不是这样呢?
指针和数组存在着一些本质的区别。当然,在某种情况下,比如数组作为函数的参数进行   传递时,由于该数组自动退化为同类型的指针,所以在函数内部,作为函数参数传递进来的指针与数组确实具有一定的一致性,但这只是一种比较特殊的情况而已,在本质上,两者是有区别的。请看以下的例子:
char a[] = "Hello!";
char *p = "Hello!";
上述两个变量的内存布局分别如下:
  数组a需要在内存中占用7个字节的空间,这段内存区通过名字a来标志。指针p则需要4个字节的空间来存放地址,这4个字节用名字p来标志,目前这个p指向某地连续的7个字节,即字符串“Hello!”
另外,例如:对于a[2]p[2],二者都返回字符‘i’,但是编译器产生的执行代码却不一样。对于a[2],执行代码是从a的位置开始,向后移 动2两个字节,然后取出其中的字符。对于p[2],执行代码是从p的位置取出一个地址,在其上加2,然后取出对应内存中的字符。

示例代码:

#include<iostream>

using namespace std;

 

int main()

{

   int a[] = {1,2,3,4,5,6,7,8,9};

   for(int i=0; i<9; i++)

   {

      cout << "a[" << i << "]:" << a[i] << " ";

      cout << "&a[" << i << "]:" << &a[i] << " ";

      cout << "a+" << i << ":" << (a + i) << " ";

      cout << "*(a+" << i << "):" << *(a + i) << " ";

      cout << endl;

   }

   cout << endl;

   int *p = &a[0];

   for(i=0; i<9; i++)

   {

      cout << "p[" << i << "]:" << p[i] << " ";

      cout << "&p[" << i << "]:" << &p[i] << " ";

      cout << "p+" << i << ":" << (p + i) << " ";

      cout << "*(p+" << i << "):" << *(p + i) << " ";

      cout << endl;

   }

   return 0;

}

5.  描述内存分配方式以及它们的区别?

1 栈区分配。 局部变量、const对象。函数执行结束时这些存储单元自动被释放。

(函数的形参:函数调用时才被分配内存单元,调用结束后内存单元被释放。)

2 数据区分配。全局变量,静态变量。常量。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。

全局变量,静态变量 生命周期:到程序结束。。

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

#include <stdlib.h>

void* malloc(size_t size);

int* p;

p = (int*)malloc( 10*sizeof(int) );

if(!p)

{

cout << “memeroy failed “ << endl;

}

free(p);// 申请失败

p = (int*)realloc(p, 20*sizeof(int))// 重新分配

//////////////////////////////////

int* p = new int(5);

if(!P)// 申请失败

 {

      cout << “memeroy failed “ << endl;

};

delete p;

p = NULL;

6. 分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

bool :       if ( !a ) or if(a)

int :        if ( a == 0)

float :        const float EXP = 0.000001

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

//float 精度问题, float 类型的 零值 不一定是 “ 0” 所以必须不能直接比较

指针 :      if ( a != NULL) or if(a == NULL)

7. 请说出const#define 相比,有何优点?

1const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而#define 只作简单的字符串替换,无类型安全检查。

2const 在编译时分配存储空间,而#define在预编译时编译,不分配存储空间。

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

 

8. 分析一下这段程序的输出

#include <iostream>

#include <string>

using namespace std;

class B

{

public:

   B()

   {

      cout<<"default constructor"<<endl;

   }

   ~B()

   {

      cout<<"destructed"<<endl;

   }

   B(int i):data(i)

   {

      cout<<"constructed by parameter " << data <<endl;

   }

private:

   int data;

};

B Play(B b)

{

   return b ;

}

//(1)

/// *                           

int main(int argc, char* argv[])     

{                                   

   B t1 = Play(5);

   B t2 = Play(t1);

   return 0;

}

//* /

/*

//(2)                                  

int main(int argc, char* argv[])    

{                                    

   B t1 = Play(5);

   B t2 = Play(10);

   return 0;

}

*/

结果:

 (1)

     constructed by parameter 5

     destructed

     destructed

     destructed

     destructed

(2)

     constructed by parameter 5

     destructed

     constructed by parameter 10

     destructed

     destructed

     destructed

说明:

如果类的成员函数中有拷贝构造函数,则将调用的拷贝构造的原理和过程说明一下,并解释由于编译环境的不同,编译的结果也有所不同(如此题中在Linuxg++中报编译错误,而在VC6.0中不报编译错误,但显示调用的拷贝构造的过程(解释为编译器的升级导致));如果没有,则无需说明拷贝构造的过程,

9. 类成员函数的重载(overload)、覆盖(override)和隐藏(override)区别?

作用域:

     重载(1)相同的范围(在同一个类中);

覆盖(重写) 1)不同的范围(分别位于派生类与基类);

隐藏 (1)不同的范围(分别位于派生类与基类);

表现形式:

重载

2)函数名字相同;

3)参数不同;

4virtual 关键字可有可无。

覆盖(重写)

2)函数名字相同;

3)参数相同;

4)基类函数必须有virtual 关键字。

隐藏

2)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

3)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

注:如果要调用基类被隐藏的函数,则加成员名限定。

举例:

#include <stdio.h>

#include <iostream>

using namespace std;

class A

{

public:

   A()

   {}

   virtual ~A()

   {}

   // 重写

   virtual void Gun(int a, int b)

   {

      cout << "A~Gun(int a, int b)" << endl;

  

   Void Kun()// 隐藏 1

   {

      cout << "A~Kun(int a)" << endl;

   }

   //virtual Kun();

   Void Run(int a)// 隐藏 2

   {

      cout << "A~Run(int a)" << endl;

   }

};

class B:public A

{

public:

   B()

   {}

   ~B()

   {}

 

   // 重载

   void Fun()

   {

      cout << "B~Fun()" << endl;

   }

   void Fun(int a)

   {

      cout << "B~Fun(int a)" << endl;

   }

   // 重写

   Void Gun(int a, int b)

   {

      cout << "B~Gun(int a, int b)" << endl;

   }

   // 隐藏 1 (参数不同即可隐藏)

   Void Kun(int a)

   {

      cout << "B~Kun(int a)" << endl;

   }

   // 隐藏 2 (函数同名,参数相同,没有 virtual

   Void Run(int a)

   {

      cout << "B~Run(int a)" << endl;

   }

}

int main(int argc, char* argv[])

{

   A a;

   B b;

  

   // 重写

   a.Gun(1, 2);

   b.Gun(1, 2);

   // 重载

   b.Fun(4);

   b.Fun();

   // 隐藏 1

   //b.Kun();// 隐藏了

   b.Kun(3);

   // 隐藏 2

   a.Run(4);

   b.Run(5);

   return 0;

}

10. const 符号常量;

(1)const char *p

(2)char const *p

(3)char * const p

说明上面三种描述的区别;

如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向的内容不可修改;

如果const位于星号的右侧,const就是修饰指针本身,即指针本身是不可修改。

(1) const char *p

一个指向char类型的const对象指针,我们可以修改p的值,使其指向不同的char,但是不能改变它指向非char对象,如:

(2) char const *p

这两个好象是一样的,此时*p可以修改,而p不能修改。

举例:

const char *p;

char c1='a';

char c2='b';

p=&c1;//ok

p=&c2;//ok

*p=c1;//error// 不能通过 p 的指向来修改 p 所指向的变量的值。

(3)char * const p

一个指向char类型的指针,此指针p的值不可修改,但p所指向的变量的值可修改。

(4)const char * const p

这种是地址及指向对象都不能修改。

添加下面解释:注意面试解释时尽量使用英文,显示更加专业。

1). char * const cp; ( * 读成 pointer to )

cp is a const pointer to char cp值不可改变,但*cp,也就是cp所指对象能够改变。

2). const char * p;

p is a pointer to const char ,亦即指向常量的指针,所以p所指的对象不可改变。

11. 下面是C语言中两种if语句判断方式。请问哪种写法更好?为什么?

 int n;

 if (n == 10) // 第一种判断方式

 if (10 == n) // 第二种判断方式

第二种代码风格更好。

第一种方式:如果==误写为 = if语句永远为真。

第二种方式:如果==误写为 = 10=n,把一个变量赋给一个常量,系统直接报错。

同理: if(NULL == point) if(point ==NULL )

如果误写成:if(point =NULL )

可能会无法delete相应的内存区域导致内存泄漏!

12. 在不用第三方参数的情况下,交换两个参数的值

方法一:

Swap(x,y)

{

x=x+y;

y=x-y;

x=x-y;

}

方法二:

Swap(x,y)

{

x=x-y;

y=x+y;

x=y-x;

}

方法三:

Swap(x,y)

{

x=y-x;

y=y-x;

x=y+x;

}

方法四:

i^=j;

j^=i;

i^=j;

方法五:

a = a+b-(b=a)

 

 

 

你可能感兴趣的:(C++面试题)