讯飞软件开发笔试题目答案版c++教学教材.docx
《讯飞软件开发笔试题目答案版c++教学教材.docx》由会员分享,可在线阅读,更多相关《讯飞软件开发笔试题目答案版c++教学教材.docx(21页珍藏版)》请在冰点文库上搜索。
讯飞软件开发笔试题目答案版c++教学教材
2009讯飞软件开发笔试题目(C++)A卷
答案请写在答题纸上
+
第一部分综合基础试题共50分
1、(4分)用变量a给出下面的定义
a)一个整型数;
b)一个指向整型数的指针;
c)一个指向指针的指针,它指向的指针是指向一个整型数;
d)一个有10个整型的数组;
e)一个有10个指针的数组,该指针是指向一个整型数;
f)一个指向有10个整型数数组的指针;
g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
答案:
a)inta
b)int*a;
c)int**a;
d)inta[10];
e)int*a[10];
f)int(*a)[10]
g)int(*a)(int)
h)int(*a[10])(int)
2、(4分)请写出以下语句的输出结果:
Inti=43;
Intj=5;
Doublef=25.45181;
a)printf(“i=%d,j=%d,f=%3.2f”,i,j,f);
b)printf(“i=%x,j=%06d,i/j=%d”,i,j,i/j);
答案:
A)i=43,j=5,f=25.45
(说明:
本来应该输出最小3位有效数字,25.5,但是由于限定了2位小数,所以强制有2位小数,有效数字的个数就起不到强制作用了。
如果是%3.1,则输出为25.5)
B)i=2B,j=000005,i/j=8
(%x显示的是一个无符号的0x16进制的整数,%06d输出的是6位数,不够6位数,前面补0,i/j两个整数相除,只取商的整数值)
3、(2分)请完成以下宏定义:
a)用预处理指令#define声明一个常数,用以表明1年中有多少个秒(忽略闰年问题)
b)写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个
答案:
a)#defineSECONDS(365*24*60*60)UL
b)#defineMIN(a,b)((A)<(B)?
(A):
(B))
扩展:
MAX宏#defineMAX((A)>(B)?
(A):
(B))
ABS宏#defineABS(((X)>0)?
(X):
(-(X)))
4、(6分)以下为32为windows下的c++程序,请计算:
a)
charstr[]=”hello”;
char*p=str;
请计算:
sizeof(str)=6
sizeof(p)=4
strlen(p)=5
答案:
6,字符串数组以\0(空格为结尾,所以str数组空间大小为5+1)
4,计算的是指针的长度。
5,strlen函数区的字符指针str的长度,不包括空字符。
b)
voidfunc(charstr[100])
{
Void*p=malloc(100);
}
请计算:
sizeof(str)=100,:
表示在内存中预分配的内存大小。
sizeof(p)=4
c)
inta[3]={1,2,3};
intb=sizeof(a)/sizeof(a[0]);sizeof(a)求的是数组的大小。
请计算:
b=3,对的。
5、(2分)设有定义:
intn=0,*p=&n,**q=&p;则以下选项中,正确的赋值语句是(d)
a)p=1;b)*q=2;c)q=p;d)*p=5;
(c)改成q=&p;才对。
6、(2分)const关键字的用途?
(至少说明两种)
答案:
(1)可以定义const常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。
被const修饰的东
西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
(3)const可以用来修饰指针变量,控制指针变量的存取规则。
7、(2分)typedef的c语言中频繁用以声明一个已经存在的数据类型的同义词。
也可以用以预处理器做类似的事情。
例如:
#definedpsstructs*
Typedefstructs*tps;
以上两种情况的意图都是要定义dps和tps作为一个指向结构s指针。
哪种方法更好一些呢?
(如果有的话)为什么?
考虑安全性还是用typedef好,宏定义在编译时是不检查的,只是简单替换,而typedef编译时要检查的
typedef,而且typedef,define并非等价,如#definestring1char*
typedefchar*string2;第二种才能达到预想效果,string1a,b;
得到的b是char
define是做替换的,typedef则是重新定义一种数据类型的。
可以向int型一样使用的。
#defineFIND(struct,e)(size_t)&(((struct*)0)->e)
typedef是语句(以';'结尾)
Typedef。
它在自己的作用域内给一个已经存在的类型一个别名
8、(8分)以下是一组有关内存知识的问题,请仔细看题,回答:
VoidGetMemory(char*p)
{
P=(char*)malloc(100);
}
VoidTest(void)
{
Char*str=Null;
GetMemory(str);
Strcpy(str,”helloworld”);
Printf(str);
}
请问运行Test函数会有什么样的结果?
a)__________程序崩溃,运行时错误___________________________
char*GetMemory(void)
{
Charp[]=”helloworld”);
Returnp;
}
VoidTest(void)
{
Char*str=NULL;
Str=GetMemory();
Printf(str);
}
请问运行Test函数会有什么结果?
b)_______________helloworld________________________________
voidGetMemory2(char**p,intnum)
{
*p=(char*)malloc(num);
}
VoidTest(void)
{
Char*str=NULL;
GetMemory(&str,100);
Strcpy(str,”hello”);
Printf(str);
}
请问运行Test函数会有什么结果?
c)_______hello__________________________________________
voidTest(void)
{
Char*str=(char*)malloc(100);
Strcpy(str,”hello”);
Free(str);
If(str!
=NULL)
{
Strcpy(str,”world”);
Printf(str);
}
}、
请问运行test函数会有什么样的结果?
d)_______程序崩溃:
因为释放str指针后,没有将指针置为null,所以指针变为野指针了。
再执行cpy时会因为找不到指针的指向而导致程序崩溃,请编程时,注意这一点。
__________________________________________
9、(6分)请写出以下程序的输出结果:
ClassA
{
Public:
A()
{Printf(“Aconstructed.\n”);}
Virtual~A()
{printf(“Adeconstructed.\n”);}
VirtualvoidFn()
{printf(“Afncalled.\n”);}
};
ClassB:
publicA
{
Public:
B()
{printf(“Bconstructed.\n”);}
Virtual~B()
{printf(“Bdeconstructed.\n”);}
VirtualvoidFn()
{printf(“Bfncalled.\n”);}
};
ClassC:
publicB
{
Public:
C()
{printf(“Cconstructed.\n”);}
Virtual~C()
{printf(“Cdeconstructed.\n”);}
VirtualvoidFn()
{printf(“Cfncalled.\n”);}
};
Voidmain(intargc,char*grgv[])
{
A*pA=newB;
If(pA!
=NULL)
pA->fn();
B*pB=static_cast(pA);
If(pB!
=NULL)
pB->fn();
C*pC=static_cast(pA);
If(pC!
=NULL)
pC->fn();
deletepA;
}
Answer:
Aconstructed
Bconstructed
Bfncalled
Bfncalled
Bfncalled
Bdeconstructed
Adeconstructed
10.(2分)以下说法错误的是:
()
A)指针和引用作为函数参数都可以改变实参
B)指针和引用都可以在定义后任意的改变指向,引用是不可以改变的。
C)引用必须在创建的时候初始化,而指针则不需要
D)不能空引用,但是可以有空指针
11、(2分)下列关于多态的描述,错误的是()
A)C++语言的多态性分为编译时的多态和运行时的多态性
B)编译时的多态性可以通过函数重载来实现
C)运行时的多态性可以通过模板(不是模板是引用)和虚函数来实现
D)实现运行时多态性的机制称动态绑定
编译时的多态性:
就是在程序编译的时候,也就是生成解决方案的时候就决定要实现什么操作。
而运行时的多态性:
就是指直到系统运行时,才根据实际情况决定实现何种操作。
静态链接库是.lib格式的文件,一般在工程的设置界面加入工程中,程序编译时会把lib文件的代码加入你的程序中因此会增加代码大小,你的程序一运行lib代码强制被装入你程序的运行空间,不能手动移除lib代码。
动态链接库是程序运行时动态装入内存的模块,格式*.dll,在程序运行时可以随意加载和移除,节省内存空间。
也就是说静态链接库不适合程序的运行,它是要么不做,要么全做的库。
在大型的软件项目中一般要实现很多功能,如果把所有单独的功能写成一个个lib文件的话,程序运行的时候要占用很大的内存空间,导致运行缓慢;但是如果将功能写成dll文件,就可以在用到该功能的时候调用功能对应的dll文件,不用这个功能时将dll文件移除内存,这样可以节省内存空间
这种情况称为运行时链接!
如果我们再把动态库的名字加上去呢?
[cpp] viewplaincopyprint?
1. >>gcc main.c -ldl ./libA.so ./libB.so @crazybaby
2. >>./a.out @crazybaby
3.libA common!
4.libA common!
[cpp] viewplaincopyprint?
1. >>gcc main.c -ldl ./libB.so ./libA.so @crazybaby
2. >>./a.out @crazybaby
3.libB common!
4.libB common!
同样可以得出结论,动态链接库如果不加库连选项,函数调用是正确的加库路径,会以库的路径顺序为主!
左边覆盖右边.而且当只链接其中一个时也生效如
如果是两个静态库中有相同的函数,会造成同名冲突。
但是动态库不会造成同名冲突。
也就是说动态库不会造成同名冲突。
只有静态链接库才会造成同名冲突。
12、(2分)运算符的重载形式有两种,重载为_重载为类的内部成员函数____________和_重载为类的友元函数______________________
13、(2分)main主函数执行完毕后,是否可能会再执行一段代码?
请说明理由?
可以使用注册函数让程序在推出main之后,程序终止之前执行自定义的一些代码!
全局对象的构造函数会在main函数之前执行
利用atexit()函数可以在程序终止前完成一些“清理”工作——如果将指向一组函数的指针传递给atexit()函数,那么在程序退出main()函数后(此时程序还未终止)就能自动调用这组函数。
在使用atexit()函数时你要注意这样两点:
main之前:
预编译 全局变量的初始化等
main之后:
全局变量的释放
main函数执行之前,主要就是初始化系统相关资源
mainCRTStartup中被调用的
在main之前会调用一系列初始化函数来初始化这个进程
而在main之后会调用exit(int)来进行进程的清理工作。
可以用_onexit注册一个函数
,可以用_onexit注册一个函数,它会在main之后执行intfn1(void),fn2(void),fn3(void),fn4(void);
可能会执行一些注册过的Hook
注意,atexit()以栈的方式注册函数,后注册的函数会先执行。
_onexit和atexit()一样是以占的方式注册函数的,后注册的函数会被先执行。
voidmain(void)
14、(2分)C++中的空类,默认产生那些类成员函数?
默认构造函数,析构函数,拷贝构造函数,赋值函数,取址函数(一对,一个const的,一个非const的),
第二部分概念简答(共10分)
15、(4分)简述STL库的功能,并给出遍历一个包含一组整型数的vector的代码。
1.标准模板库(STL)使得C++编程语言在有了同Java一样强大的类库的同时,保有了更大的可扩展性。
该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。
2.为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
3.从逻辑层次来看,在STL中体现了泛型化程序设计的思想(genericprogramming)
#include
#include
#include
usingnamespacestd;
intmain()
{
vectordata;
data.push_back
(1);
data.push_back
(2);
data.push_back(3);
data.push_back(4);
data.push_back(5);
data.push_back(6);
data.push_back(7);
vector:
:
iteratorit;
for(it=data.begin();it!
=data.end();it++)
{
cout<<*it<<"";
}
cout<system("pause");
return0;
}
16、(5分)请写出贝叶斯公式
贝叶斯定理公式:
P(A|B)=P(B|A)*P(A)/P(B)
17、(5分)进程和线程的区别和联系?
进程是程序的一次执行,线程可以理解为进程中执行的一段程序片段,在一个多任务的环境中下面的概念可以帮助我们理解两者之间的差别。
1.进程间是独立的,这表现在内存空间,上下文环境上;线程运行在进程空间内,线程之间并不是独立的,是并发执行的。
一般来讲(不适用特殊技术),进程无法突破边界来存取其他进程的资源;而线程由于处于进程空间内,所以同一进程产生的线程共享同一内存空间。
2.同一进程中的两段代码不能同时进行,除非引入线程。
3.线程是属于进程的,当进程退出时,该进程所产生的线程都会被强制退出并清除。
线程是CPU调度的基本单位,进程是系统资源调度的基本单位。
第三部分算法设计与设计思考共30分
18、(10分)请不用任何cruntime函数实现以下函数:
Intertrim_str(char*pstr)
函数功能如下:
1)滤掉字符串头尾的空格、回车、tab
2)输出字符串通过输入字符串指针返回
3)如果成功则返回0否则返回非0
inttrim(char*str1)
{
if(str1=NULL)
{
return1;
}
/*charstr1[15]="12334";*/
char*begin,*end;
begin=str1;
end=str1;
while(*end!
='\0')
{
end++;
if(*end==''||*end=='\t'||*end=='\n')
break;
}
*end='\0';
while(*begin!
='\0')
{
if(*begin==''||*begin=='\t'||*begin=='\n')
{
begin++;
}
}
cout<return0;
}
19、(10分)有N个大小不等的自然数(1,2,3,…..N)请将它们从小到大排列。
算法要求:
时间复杂度为O(n),空间复杂度为O
(1)。
请简要说明你采用的排序算法并写出c的伪代码。
如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O
(1);
1.#include
2.using namespace std;
3.int sort(int data[],int n);
4.int main()
5.{
6. int data[] = {8,7,9,4,6,5,3,2,1};
7. for(int i = 0 ;i < sizeof(data)/sizeof(int);i++)
8. cout<9. cout<10. sort(data,sizeof(data)/sizeof(int));
11. system("pause");
12. return 1;
13.}
14.int sort(int data[],int n)
15.{
16. //保证空间复杂度为O
(1)
17. int tmp = 0;
18. for(int i = 0;i < n;i++)
19. {
20. //移动,直到第data[i]为i+1的时,while结束循环。
向后继续判断
21. while(data[i] !
= i+1)
22. {
23. //每次循环保证了data[i-1]的正确。
总共有n个所以时间复杂度为O(N)
24. tmp = data[data[i]-1];
25. data[data[i]-1] = data[i];
26. data[i] = tmp;
27. }
由于while中移动的次序很少。
所以近似为O(n)
28. }
29. for(int i = 0;i < n;i++)
30. cout<31. cout<32. return 1;
33.}
20、(10分)用文字和图示(类图)描述你所知道的除单件模式和简单工厂之外的一种设计模式,并用c++实现
Adapter模式,就是适配器模式
代码如下:
classtarget
{
public:
virtualvoidrequst()
{
cout<<"generalinterface."<}
};
classadaptee
{
public:
voidspecialrequst()
{
cout<<"specialinterface"<特¬?
殊ºa的Ì?
情¨¦况?
转Áa化¡¥为a公?
共2的Ì?
接¨®口¨²,ê?
使º1得Ì?
大䨮家¨°都?
可¨¦以°?
使º1用®?
。
¡ê
}
};
classadapter:
publictarget
{
public:
adapter()
{
ade=newadaptee;
}
~adapter()
{
deleteade;
}
virtualvoidrequst()
{
ade->specialrequst();
target:
:
requst();
}
private:
adaptee*ade;
};
intmain()
{
adapter*p=newadapter();
p->requst();
return0;
}
第四部分知识面考察共10分
21、(10分)请在下列三题中任选一题作答
A)什么是内存的垃圾回收集算法,其作用是什么?
据你所知,有那些开发语言中提供了垃圾收集机制?
因此我们需要一种自动内存管理的策略,这就是自动垃圾回收机制。
既然是自动垃圾回收,那么平台肯定得采取一种方式发现垃圾,然后清除。
这就是垃圾收集算法所关注的问题。
垃圾收集算法的任务就是将活动的对象和已经死掉的对象分别出来,然后将死掉的对象的内存回收,而且为了更好的利用内存,有的算法还会对内存碎片进行压缩。
下面会对常用的垃圾收集算法进行介绍:
引用计数(ReferenceCounting)
引用计数,顾名思义,就是每个对象上有个计数器,当添加了一个对它的引用时它的计数器就会加1,当不再使用这个引用时它的计数器就会递减1。
当计数器为0的时候则认为该对象是垃圾,可以被回收了,如果该对象被回收则该对象所引用的所有对象的计数器会跟着递减。
这样有可能会有很多对象的引用都减为0
跟踪(trace)跟踪有以下几种方式。
标记清扫(Mark-Sweep)
使用跟1.标记(MarkPhase)2.清扫(Sw