c,c++常见面试题 下载本文

重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和

function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定)。 重写:当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。

14.有哪几种情况只能用intialization list 而不能用assignment?

当类中含有const、reference 成员变量;基类的构造函数都需要初始化表。

15. C++是不是类型安全的?

不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。

16.main函数执行之前,还会执行什么代码? 全局对象的构造函数会在main函数之前执行。

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

1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。

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

18.分别写出bool,int,float,指针类型的变量a 与“零”的比较语句。 1 bool : if(!a) or if(a) 2 int : if(a == 0)

3 float : const EXPRESSION EXP = 0.000001 4 if (a < EXP && a >-EXP)

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

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

const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

1)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

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

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

数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。 (1)修改内容上的差别 1 char a[] = \; 2 a[0] = 'X';

3 char *p = \; // 注意p 指向常量字符串

4 p[0] = 'X'; // 编译器不能发现该错误,运行时错误

(2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。

1 char a[] = \; 2 char *p = a; 3

4 //计算数组和指针的内存容量

5 cout<< sizeof(a) << endl; // 12 字节 6 cout<< sizeof(p) << endl; // 4 字节 7

8 //数组作为函数参数传递 9 void Func(char a[100]) 10 {

11 cout<< sizeof(a) << endl; // 4 字节而不是100 字节 12 }

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

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

2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。

22.基类的析构函数不是虚函数,会带来什么问题? 派生类的析构函数用不上,会造成资源的泄漏。 23.全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的? 生命周期不同: 全局变量随主程序创建和创建,随主程序销毁而销毁;局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在; 使用方式不同: 通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用;分配在栈区。 内存分配位置不同: 全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面 。 24.写出完整版的strcpy函数: 如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案: 2分 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 void strcpy( char *strDest, char *strSrc ) { while( (*strDest++ = * strSrc++) != '\\0' ); } void strcpy( char *strDest, const char *strSrc ) //将源字符串加const,表明其为输入参数,加2分 { while( (*strDest++ = * strSrc++) != '\\0' ); } void strcpy(char *strDest, const char *strSrc) { //对源地址和目的地址加非0断言,加3分 assert( (strDest != NULL) && (strSrc != NULL) ); while( (*strDest++ = * strSrc++) != '\\0' ); } //为了实现链式操作,将目的地址返回,加3分! char * strcpy( char *strDest, const char *strSrc ) { assert( (strDest != NULL) && (strSrc != NULL) ); 4分 7分 10分 5 6 7 8 char *address = strDest; while( (*strDest++ = * strSrc++) != '\\0' ); return address; } 25.为什么标准头文件都有类似以下的结构? 1 2 3 4 5 6 7 8 9 10 1 2 3 #ifndef __INCvxWorksh #define __INCvxWorksh #ifdef __cplusplus extern \ { #endif /*...*/ #ifdef __cplusplus } #endif #endif /* __INCvxWorksh */ #ifndef __INCvxWorksh #define __INCvxWorksh #endif 头文件中的编译宏 的作用是防止被重复引用。 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在symbol库中的名字与C语言的不同。例如,假设某个函数的原型为: 1 void foo(int x, int y); 该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。 为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern \来解决名字匹配问题,函数声明前加上extern \后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。 26.编写类String的构造函数、析构函数和赋值函数,已知类String的原型为: 1 2 3 4 5 6 7 class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &other); // 拷贝构造函数 ~ String(void); // 析构函数 String & operator =(const String &other); // 赋值函数 8 9 10 private:

char *m_data; // 用于保存字符串 };

1 //普通构造函数

2 String::String(const char *str) 3 {

4 if(str==NULL) 5 {

6 m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\\0'的空

7 *m_data = '\\0'; //加分点:对m_data加NULL 判断 8 } 9 else 10 {

11 int length = strlen(str);

12 m_data = new char[length+1]; // 若能加 NULL 判断则更好 13 strcpy(m_data, str); 14 } 15 }

16 // String的析构函数 17 String::~String(void) 18 {

19 delete [] m_data; 20 }

21 //拷贝构造函数

22 String::String(const String &other) // 得分点:输入参数为const型 23 {

24 int length = strlen(other.m_data);

25 m_data = new char[length+1]; //加分点:对m_data加NULL 判断 26 strcpy(m_data, other.m_data); 27 }

28 //赋值函数

29 String & String::operator =(const String &other) // 得分点:输入参数为const型 30 {

31 if(this == &other) //得分点:检查自赋值 32 return *this;

33 delete [] m_data; //得分点:释放原有的内存资源 34 int length = strlen( other.m_data );

35 m_data = new char[length+1]; //加分点:对m_data加NULL 判断 36 strcpy( m_data, other.m_data );

37 return *this; //得分点:返回本对象的引用 38 }