c/c++面试题汇总(3)

1.一个类有基类、内部有一个其他类的成员对象,构造函数的执行顺序是怎样的。

答:先执行基类的(如果基类当中有虚基类,要先执行虚基类的,其他基类则按照声明派生类时的顺序依次执行),再执行成员对象的,最后执行自己的。

2.常见的设计模式

答:后期整理。(以后加进来)。

3.C#和C++除了语法上的差别以外,有什么不同的地方?(Autodesk,Microsoft)
答:(1) c#有垃圾自动回收机制,程序员不用担心对象的回收。(2)c#严禁使用指针,只能处理对象。如果希望使用指针,则仅可在unsafe 程序块中能使用指针。(3)c#只能单继承。(4)必须通过类名访问静态成员。不能像C++中那样,通过对象访问静态成员。(5)在子类中覆盖父类的虚函 数时必须用关键字override,覆盖父类的方法要用关键字new

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

答:无论是在构造函数初始化列表中初始化成员,还是在构造函数体中对它们赋值,最终结果都是相同的。不同之处在于,使用构

函数初始化列表初始化数据成员,没有定义初始化列表的构造函数在构造函数体中对数据成员赋值。对于const和reference类型

员变量,它们只能够被初始化而不能做赋值操作,因此只能用初始化列表。还有一种情况就是,类的构造函数需要调用其基类的

函数的时候如果在子类的构造函数中需要初始化父类的private成员,直接对其赋值是不行的,只有调用父类的构造函数

才能完成对它的初始化。但在函数体内调用父类的构造函数也是不合法的,只有采用初始化列表调用子类构造函数的方式)。

5. C++是不是类型安全的?
答案:不是。两个不同类型的指针之间可以强制转换。C#是类型安全的。

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

7. 什么是虚拟存储器?virtual memory 怎样映射到physical memory?页面替换算法有哪些?

答案:后期学习整理。

8.Struct 和class 的区别 
答案:struct 中成员变量和成员函数默认访问权限是public,class 是private

9.当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。
答案:1。我举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。

10.描述一下C++的多态 
答案:C++的多态表现在两个部分,一个是静态连编下的函数重载,运算符重载;动态连编下的虚函数、纯虚函数(抽象类)。

11.有四个同样的容器,里面装满了粒数相同的药丸,正常药丸的质量为m,变质药丸的质量为m+1,现在已知这四个容器中,有一个装的全是变质药丸,用电子秤只称一次,找出哪个容器装的是变质药丸 
答案:把四个容器依次编号为1、2、3、4,然后从中分别取出1、2、3、4 粒药丸,称这10 粒药丸的质量,如果质量为10m+1,则说明第一个容器装的是变质药丸,如果为10m+2 则说明第二个装的变质药丸,依次类推。

12.比较一下C++中static_cast 和 dynamic_cast 的区别。 

答案:dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上,它被用于安全地沿着类的继承关系向下进行类型转换。如你想在没有继承关系的类型中进行转换,你可能想到static_cast

13.类成员函数的重载、覆盖和隐藏区别
答案:
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

14.A,B 不使用任何if、switch、或者其他判断语句,找出最大值

答案:((A + B) + abs (A - B)))/ 2

15.如何打印出当前源文件的文件名以及源文件的当前行号?
答案:cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。

16.main 主函数执行完毕后,是否可能会再执行一段代码,给出说明?
答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行int fn1(void), fn2(void), fn3(void), fn4 (void);
void main( void )
{
String str("zhanglin");
_onexit( fn1 );
_onexit( fn2 );
_onexit( fn3 );
_onexit( fn4 );
printf( "This is executed first.\n" );
}
int fn1()
{
printf( "next.\n" );
return 0;
}

.........

17.如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif

18.变量的声明和定义的区别

答案:为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但是只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。注:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。

19.sizeof和strlen的区别 
 sizeof是一个操作符,strlen是库函数。 
 sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。编译器在编译时就计算出了sizeof的结果。而strlen函数必须在运行时才能计算出来。并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。  数组做sizeof的参数不退化,传递给strlen就退化为指针了。

20.一个指针可以是volatile吗

答案:可以,因为指针和普通变量一样,有时也有变化程序的不可控性。常见例:子中断服务子程序修改一个指向一个buffer的指针时,必须用volatile来修饰这个指针。

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量

1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:
1
2
3
4
int square( volatile int *ptr )
{
    return *ptr * *ptr;
}
答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。
3). 这段代码是个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
1
2
3
4
5
6
7
int square( volatile int *ptr )
{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}
由于*ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!正确的代码如下:
1
2
3
4
5
6
long square( volatile int *ptr )
{
    int a;
    a = *ptr;
    return a * a;
}

21,写出下列代码的输出
#include "stdafx.h"
#include <stdio.h>
#include "string.h"


int _tmain(int argc, _TCHAR* argv[])
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a + 1);
printf("%d,%d",*(a + 1),*(ptr - 1));
return 0;
}
输出为2,5原因是a是数组的首地址,a+1数组的下一个元素。&a是数组的指针。加1为数组尾部地址加1。
22 ,简述C、C++程序编译的内存分配情况 
C、C++中内存分配方式可以分为三种: 
(1)从静态存储区域(全局区)分配: 
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static变量等。 
(2)在栈上分配: 
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 
(3)从堆上分配: 
即动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。 
一个C、C++程序编译时内存分为5大存储区:堆区、栈区、全局区、文字常量区、程序代码区。
(4)文字常量区:

常量字符串就是放在这里的。 程序结束后由系统释放。

常量,顾名思义,不可进行写操作,关于这一点的注意事项,请看下面这段错误代码;

char *p = "atbcdef";

*(p+1) = 'b';

程序运行时将报非法写入错误。

  1. char* p = “Hello World1”;  存在静态存储区上
  2. char a[] = “Hello World2”;  存在栈上
  3. p[2] = ‘A’;  
  4. a[2] = ‘A’;  -------------错误语句
  5. char* p1 = “Hello World1;” 
程序运行时报错,

(5)程序代码区存放函数体的二进制代码。

23.简述strcpy、sprintf与memcpy的区别 
三者主要有以下不同之处: 
(1)操作对象不同,strcpy的两个操作对象均为字符串,sprintf的操作源对象可以是多种数据类型,目的操作对象是字符串,memcpy 的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。 (2)执行效率不同,memcpy最高,strcpy次之,sprintf的效率最低。 (3)实现功能不同,strcpy主要实现字符串变量间的拷贝,sprintf主要实现其他数据类型格式到字符串的转化,memcpy主要是内存块间的拷贝。 
说明:strcpy、sprintf与memcpy都可以实现拷贝的功能,但是针对的对象不同,根据实际需求,来选择合适的函数实现拷贝功能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值