您的位置:首页 > 编程语言 > C语言/C++

C/C++校招笔试面试经典题目总结二

2015-07-09 16:53 567 查看
接着昨天的总结继续。。。

题目11:#define DOUBLE(x) x+x ,i = 5*DOUBLE(5)。 i 是多少?

解答:

这个题目和题目6是同一个题型,这里并不会出现i=5*(5+5)=50的结果,因为题目只是使用了x+x来替代DOUBLE(x),注意x+x并没有使用括弧,所以结果应该为:i=5*x+x=5*5+5=30。所以在写宏定义的时候一定要谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。

题目12:在不用第三方参数的情况下,交换两个参数的值。

解答:

很有意思的一道题目,有三种方法:
方法一:
a=a+b;
b=a-b;
a=a-b;
方法二:
i^=j;

j^=i;

i^=j;
方法三:
// 用加减实现,而且不会溢出

a = a+b-(b=a)
题目13:下列代码段输出cout<<sizeof(c)<<endl;的结果是?

union a {
int a_int1;
double a_double;
int a_int2;
};
typedef struct
{
a a1;
char y;
} b;
class c
{
double c_double;
b b1;
a a2;
};
解答:

考查对sizeof的理解,和题目8是同一题型。一些基本数据类型的sizeof这里就不在介绍了,下面重点讲下结构体的sizeof:

先看一个例子:

struct S1
{
char c;
int i;
};


问sizeof(s1)等于多少?聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗?你在你机器上试过了吗?也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。
我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:
S1 s1 = { 'a', 0xFFFFFFFF };
定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么?以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:
0012FF78: 61 CC CC CC FF FF FF FF发现了什么?怎么中间夹杂了3个字节的CC?看看MSDN上的说明:
When applied to a structure type or variable,sizeofreturns the actual size, which may include padding bytes insertedforalignment.
原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。
为什么需要字节对齐,计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
让我们交换一下S1中char与int的位置:

struct S2
{
int i;
char c;
};

看看sizeof(S2)的结果为多少,怎么还是8?这是因为有以下规则:
1)数据对齐原则----内存按结构成员的先后顺序排列,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整倍数,如果不够则补齐,以此向后类推;
2)结构体的总大小为结构体最宽基本类型成员大小的整数倍。
看虽然S1和S2结果是一样的,但原因却不一样。S1是因为有第一条规则的存在,即c要和i对齐才在后面填充字节补齐,而S2则是因为第二条规则的限制才在c后面填充字节补齐。所以一定要注意当结构体里面的成员顺序不一样的时候其结果也有可能不一样。例如下面这个例子:

struct s1
{
char a;
double b;
int c;
char d;
};

struct s2
{
char a;
char b;
int c;
double d;
};

cout<<sizeof(s1)<<endl; // 24
cout<<sizeof(s2)<<endl; // 16

同样是两个char类型,一个int类型,一个double类型,但是因为对齐问题,导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明一下:首先,CPU判断结构体的对界,根据上面的规则,s1和s2的对界都取最大的元素类型,也就是double类型的对界8。然后开始摆放每个元素。

对于s1,首先把a放到8的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素d是double类型,要放到8的对界上,离1最接近的地址是8了,所以d被放在了8,此时下一个空闲地址变成了16,下一个元素c的对界是4,16可以满足,所以c放在了16,此时下一个空闲地址变成了20,下一个元素d需要对界1,也正好落在对界上,所以d放在了20,结构体在地址21处结束。由于s1的大小需要是8的倍数,所以21-23的空间被保留,s1的大小变成了24。

对于s2,首先把a放到8的对界,假定是0,此时下一个空闲地址是1,下一个元素的对界也是1,所以b摆放在1,下一个空闲地址变成了2;下一个元素c的对界是4,所以取离2最近的地址4摆放c,下一个空闲地址变成了8,下一个元素d的对界是8,所以d摆放在8,所有元素摆放完毕,结构体在15处结束,占用总空间为16,正好是8的倍数。

所以根据上面两个例子的分析以及两条规则不难得出题目a的大小为:8(联合体sizeof是取最大的数据成员所占的字节数,为double a_double),而b的大小为8+1+7(这里加7主要是因为规则2的存在)=16,所以c的大小为8(注意根据第一条规则这里为什么不为16?如果不知道的可以在下方评论提出来)+16+8=32。所以结果为32。

题目14:输出下面程序段的结果:

#include <iostream.h>
class A
{
public:
virtual void print(void)
{
cout<<"A::print()"<<endl;
}
};
class B:public A
{
public:
virtual void print(void)
{
cout<<"B::print()"<<endl;
};
};
class C:public B
{
public:
virtual void print(void)
{
cout<<"C::print()"<<endl;
}
};
void print(A a)
{
a.print();
}
void main(void)
{
A a, *pa,*pb,*pc;
B b;
C c;

pa=&a;
pb=&b;
pc=&c;

a.print();
b.print();
c.print();

pa->print();
pb->print();
pc->print();

print(a);
print(b);
print(c);
}
解答:

这里涉及到派生类构造函数的调用顺序:

1)调用基类构造函数

2)调用成员构造函数

3)调用派生类本身的构造函数。

而析构函数刚好相反,即顺序为3)2)1)。

所以其输出结果为:

A::print()

B::print()

C::print()

A::print()

B::print()

C::print()

A::print()

A::print()

A::print()
题目15:当一个类A 中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释一下编译器为什么没有让它为零。(Autodesk)

解答:

肯定不是零。举个反例,如果是零的话,声明一个class
A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。

题目16:.h头文件中的ifndef/define/endif 的作用?

解答:

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

题目17:#include<file.h> 与#include"file.h"的区别?

解答:

前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

题目18:写出下列算法的时间复杂度:

(1)冒泡排序;

(2)选择排序;

(3)插入排序;

(4)快速排序;

(5)堆排序;

(6)归并排序;



解答:

这个题目需要引起重视,虽然很多题目不会以这种形式来出题,但是很多选择题和填空题都直接或间接的考查了这些算法的时间复杂度。具体如图所示:







题目19:已知数据表A中每个元素距其最终位置不远,为节省时间,应该采用的排序算法是?

解答:快速排序

题目20:内存分配方式

解答:

内存分配方式有三种:

  (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

  (2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

  (3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
好了,今天就到这吧,明天继续更新!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: