2009讯飞软件开发笔试题目
答案请写在答题纸上
第一部分 综合基础试题 共50分
1、用变量a给出下面的定义
a) 一个整型数; int a;
b)一个指向整型数的指针;int *a;
c)一个指向指针的指针,它指向的指针是指向一个整型数;int **a;
d)一个有10个整型的数组;int a[10];
e)一个有10个指针的数组,该指针是指向一个整型数;int *a[10];
f)一个指向有10个整型数数组的指针;int (*a)[10];不知道的可以用int a[10], *p=a;但是考察的应该是前者。
g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数;int (*a)(int );
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数;int (*a[10])(int);
2、请写出以下语句的输出结果:
Int i=43;
Int j=5;
Double f=25.45181;
a) printf(“i=%d,j=%d,f=%3.2f\n”,i,j,f);
b) printf(“i=%x,j=%06d,i/j=%d\n”,i,j,i/j);
答案:
(a)说明:本来应该输出最小3位有效数字,25.5,但是由于限定了2位小数,所以强制有2位小数,有效数字的个数就起不到强制作用了。如果
是%3.1,则输出为25.5
(b)%x显示的是一个无符号的0x 16进制的整数,%06d输出的是6位数,不够6位数,前面补0,i/j两个整数相除,只取商的整数值
3、请完成以下宏定义:
a)用预处理指令#define 声明一个常数,用以表明1年中有多少个秒(忽略闰年问题)
b)写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个
答案:
a)#define seconds 365*24*60*60
b) #define MIN(a,b) ((a)<(b)?(a):(b))
扩展:MAX宏 #define MAX ((a)>(b)(a):(b))
ABS宏 #define ABS (((x)>0)?(x):(-(x)))
4、以下为32位windows下的c++程序,请计算:
a)
char str[]=”hello”;
char *p=str;
请计算:
sizeof(str)=6
sizeof(p)=4
strlen(str)=5
strlen(p)=5
b)
void func(char str[100])
{
void *p=malloc(100);
}
请计算:
sizeof(str)=4
sizeof (p)=4
为了理解特做测试如下:这个例子很有助于理解。
#include<iostream>
using namespace std;
void func(char str_func[100])
{
void *p=malloc(100);
cout<<"sizeof(str_func):"<<sizeof(str_func)<<endl;
cout<<"sizeof(p):"<<sizeof(p)<<endl;
}
int main(void)
{
char str_main[100];
cout<<"sizeof(str_main):"<<sizeof(str_main)<<endl;
func(str_main);
return 1;
}
运行结果:其实,真正的运行机制,我不懂;待参考专业书籍。
c)
int a[3]={1,2,3};
int b=sizeof(a)/sizeof(a[0]);
请计算:
b=3
5、设有定义:int n=0,*p=&n,**q=&p; 则以下选项中,正确的赋值语句是(d)
a)p=1; b)*q=2; c)q=p; d)*p=5;
6、const关键字的用途?(至少说明两种)
答案:
(1)可以定义 const 常量
(2)const 可以修饰函数的参数、返回值,甚至函数的定义体。被const 修饰的东
西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
7、typedef的c语言中频繁用以声明一个已经存在的数据类型的同义词。也可以用以预处理器做类似的事情。例如:
#define dps struct s*
Typedef struct s *tps;
以上两种情况的意图都是要定义dps和tps作为一个指向结构s指针。哪种方法更好一些呢?(如果有的话)为什么?
typedef的方法更好些,因为typedef只是给类型取个别名,用这个别名定义变量和用本来的类型定义变量是一样的;而用#define只是在编译前简
单的宏展开,容易出问题。
8、以下是一组有关内存知识的问题,请仔细看题,回答:
Void GetMemory(char *p)
{
P=(char *)malloc(100);
}
Void Test(void)
{
Char *str=Null;
GetMemory(str);
Strcpy(str,”hello world”);
Printf(str);
}
请问运行Test函数会有什么样的结果?
a)程序不能正常运行,测试如下:
#include <iostream>
#include <cstring>
using namespace std;
void GetMemory(char *p)
{
p=(char *)malloc(100);
}
int main(int argc,char* grgv[])
{
char *str=NULL;
//GetMemory(str); 把这行注释掉程序照样无法运行。
strcpy(str,"hello world");
cout<<str<<endl;
return 1;
}
//程序运行出错(无法运行)
//解释:
char *GetMemory(void)
{
Char p[]=”hello world”);
Return p;
}
Void Test(void)
{
Char *str=NULL;
Str=GetMemory();
Printf(str);
}
请问运行Test函数会有什么结果?
b)乱码,电脑重启后,运行结果会不一样。测试如下:
#include <iostream>
#include <cstring>
using namespace std;
char* GetMemory(void)
{
char p[]="Hello world";
return p;
}
int main(int argc,char* grgv[])
{
char *str=NULL;
str=GetMemory();
cout<<str<<endl;
return 1;
}
//解释:
void GetMemory2(char **p,int num)
{
*p=(char *)malloc(num);
}
Void Test(void)
{
Char *str=NULL;
GetMemory(&str,100);
Strcpy(str,”hello”);
Printf(str);
}
请问运行Test函数会有什么结果?
c)输出hello,测试如下:
#include <iostream>
#include <cstring>
using namespace std;
void GetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
int main(int argc,char* grgv[])
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"Hello");
cout<<str<<endl;
return 1;
}
//解释:
void Test(void)
{
Char *str=(char *)malloc(100);
Strcpy(str,”hello”);
Free(str);
If(str!=NULL)
{
Strcpy(str,”world”);
Printf(str);
}
}
请问运行test函数会有什么样的结果?
(d)输出world,测试如下:
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc,char* grgv[])
{
char *str=(char *)malloc(100);
strcpy(str,"Hello");
free(str);//malloc和free;new和delete配对。
if(str!=NULL)
{
strcpy(str,"world");
cout<<str<<endl;
}
return 1;
}
//解释:
本题考点总结:类似的问题,我已经在数据结构实验课的时候遇到过,当时就不是很理解这个问题,现在刚好可以重拾问题,解决之;我觉
得理解本题的关键是知道函数空间这个点。
具体的见博文一(自己关于malloc的错误):http://blog.csdn.net/dscyw/article/details/8759507
博文二(C++内存管理):http://blog.csdn.net/dscyw/article/details/8757264
博文二就是一个28页文档的拷贝:pdf-http://download.csdn.net/detail/dscyw/5224042
关于C++内存管理的两个文档:doc-http://download.csdn.net/detail/dscyw/5224034
9、请写出以下程序的输出结果:
Class A
{
Public:
A()
{ Printf(“A constructed.\n”);}
Virtual ~A()
{printf(“A deconstructed.\n”);}
Virtual void Fn()
{printf(“A fn called.\n”);}
};
Class B:public A
{
Public:
B()
{printf(“B constructed.\n”);}
Virtual ~B()
{printf(“B deconstructed.\n”);}
Virtual void Fn()
{printf(“B fn called.\n”);}
};
Class C:public B
{
Public:
C()
{printf(“C constructed.\n”);}
Virtual ~C()
{printf(“C deconstructed.\n”);}
Virtual void Fn()
{printf(“C fn called.\n”);}
};
Void main(int argc,char* grgv[])
{
A *pA=new B;
If(pA!=NULL)
pA->fn();
B *pB=static_cast<B*>(pA);
If(pB!=NULL)
pB->fn();
C * pC=static_cast<C*>(pA);
If(pC!=NULL)
pC->fn();
delete pA;
}
测试代码如下:
#include <iostream>
#include <cstring>
using namespace std;
class A
{
public:
A()
{
printf("A constructed.\n");
}
virtual ~A()
{
printf("A deconstructed.\n");
}
virtual void fn()
{
printf("A fn called.\n");
}
};
class B:public A
{
public:
B()
{
printf("B constructed.\n");
}
virtual ~B()
{
printf("B deconstructed.\n");
}
virtual void fn()
{
printf("B fn called.\n");
}
};
class C:public B
{
public:
C()
{
printf("C constructed.\n");
}
virtual ~C()
{
printf("C deconstructed.\n");
}
virtual void fn()
{
printf("C fn called.\n");
}
};
void main(int argc,char* grgv[])
{
A *pA=new B;
if(pA!=NULL)
pA->fn();
B *pB=static_cast<B*>(pA);
if(pB!=NULL)
pB->fn();
C * pC=static_cast<C*>(pA);
if(pC!=NULL)
pC->fn();
delete pA;
}
运行结果如下:
解释:子类必须调用父类的构造函数,不显示调用,系统会自动调用。
C++程序设计--李龙澍(第二版) P178 虚函数
static_cast见博文:http://blog.csdn.net/dscyw/article/details/8757304
10、以下说法错误的是:(B)
A)指针和引用作为函数参数都可以改变实参
B)指针和引用都可以在定义后任意的改变指向
C)引用必须在创建的时候初始化,而指针则不需要
D)不能空引用,但是可以有空指针
11、下列关于多态的描述,错误的是(C)
A)C++语言的多态性分为编译时的多态和运行时的多态性
B)编译时的多态性可以通过函数重载来实现
C)运行时的多态性可以通过模板和虚函数来实现 模板不对
D)实现运行时多态性的机制称动态绑定
12、 运算符的重载形式有两种,重载为成员函数和友元函数
13、main主函数执行完毕后,是否可能会再执行一段代码?请说明理由?
参加http://blog.csdn.net/dscyw/article/details/8752924
14、C++中的空类,默认产生那些类成员函数? 无参构造函数 拷贝构造函数 析构函数 赋值运算符 一对取址运算符
参加http://blog.csdn.net/dscyw/article/details/8752948
第二部分 概念简答
15、简述STL库的功能,并给出遍历一个包含一组整型数的vector的代码。
答案:对stl有所涉及,但是用的不多,也不精,用自己的话:封装了一些常用的数据结构,并提供了操作接口供开发者使用,提高了代码重用率和开发进程。
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
int a[7]={1,2,3,4,5,6,7};
vector<int> ivector(a,a+7);
//vector的赋值并不可以像数组一样方便的用花括号方便的完成赋值,这里借用了数组来初始化这个vector,初始化方
//式vector<elementType> intvec(begin,end);这样可以用起来看上去还是比较习惯的。
vector<int>::iterator iter;
for (iter=ivector.begin();iter!=ivector.end();iter++)
{
cout<<*iter<<'\0';
}
cout<<endl;
ivector[5]=1;//单个vector的赋值,这个方式看上去还是和数组一样的,不过你也可以这么写ivector.at(5)=1;但是就是不习惯
cout<<ivector[5]<<endl<<ivector.size()<<endl;
for (iter=ivector.begin();iter!=ivector.end();iter++)
{
cout<<*iter<<'\0';
}
return 0;
}
16、请写出贝叶斯公式
17、进程和线程的区别和联系?
略。
第三部分 算法设计与设计思考 共30分
18、请不用任何c runtime函数实现以下函数:
Inter trim_str(char *pstr)
函数功能如下:
1) 滤掉字符串头尾的空格、回车、tab
2) 输出字符串通过输入字符串指针返回
3) 如果成功则返回0否则返回非0
见:http://blog.csdn.net/dscyw/article/details/8750390
19、有N个大小不等的自然数(1,2,3,…..N)请将它们从小到大排列。算法要求:时间复杂度为O(n),空间复杂度为O(1)。请简要说明你采用的排序算法并写出c的伪代码。
见:http://blog.csdn.net/dscyw/article/details/8750390
20、用文字和图示(类图)描述你所知道的除单件模式和简单工厂之外的一种设计模式,并用c++实现
暂略,见博文http://blog.csdn.net/dscyw/article/details/8758329
第四部分 知识面考察
21、请在下列三题中任选一题作答
A)什么是内存的垃圾回收集算法,其作用是什么?据你所知,有那些开发语言中提供了垃圾收集机制?
B)现在非常多的用户都在谈SOA,根据Gartner的预测,2008年,企业80%应用都将通过使用SOA来实现,你理解SOA是什么?SOA的关键特点有哪些?SOA带来什么?
C)随着互联网的普及,很多新兴的、传统的软件厂商都在探讨SAAS的前景,甚至很多行业观点认为SAAS是软件行业的未来趋势。你是怎么理解SAAS的,你怎么看待这种趋势?SAAs和更早之前的ASP感念有什么异同?
暂略
附加:goto语句有没有必要存在程序设计语言中
答案:
结构化程序设计是避免使用GOTO语句的一种程序设计;
结构化程序设计是自顶向下的程序设计;
结构化程序设计是一种组织和编制程序的方法,利用它编制的程序易于理解、易于修改;
程序结构化的一个主要功能是使程序正确性的证明容易实现;
结构化程序设计对设计过程中的每一步去验证其正确性,这样便自动导致自我说明和自我捍卫的程序设计风格;
在60年代末和70年代初,关于GOTO语句的用法的争论比较激烈。主张从高级程序语言中去掉GOTO语句的人认为,GOTO语句是对程序结构影响
最大的一种有害的语句,他们的主要理由是:GOTO语句使程序的静态结构和动态结构不一致,从而使程序难以理解,难以查错。去掉GOTO语句后,
可直接从程序结构上反映程序运行的过程。这样,不仅使程序结构清晰,便于理解,便于查错,而且也有利于程序的正确性证明。
持反对意见的人认为,GOTO语句使用起来比较灵活,而且有些情形能提高程序的效率。若完全删去GOTO语句,有些情形反而会使程序过于复
杂,增加一些不必要的计算量。
1974年,D·E·克努斯对于GOTO语句争论作了全面公正的评述,其基本观点是:不加限制地使用GOTO语句,特别是使用往回跳的GOTO语句,会
使程序结构难于理解,在这种情形,应尽量避免使用GOTO语句。但在另外一些情况下,为了提高程序的效率,同时又不致于破坏程序的良好结构,有
控制地使用一些GOTO语句也是必要的。用他的话来说就是:“在有些情形,我主张删掉GOTO语句;在另外一些情形,则主张引进GOTO语句。”从
此,使这场长达10年之久的争论得以平息。
后来,G·加科皮尼和C·波姆从理论上证明了:任何程序都可以用顺序、分支和重复结构表示出来。这个结论表明,从高级程序语言中去掉GOTO语
句并不影响高级程序语言的编程能力,而且编写的程序的结构更加清晰。
结构化程序设计的思想体现在采用了一些比较行之有效的方法,在这些方法中较有代表性的是“逐步求精”方法。所谓“逐步求精”方法,就是在编制
一个程序时,首先考虑程序的整体结构而暂时忽略一些细节问题,然后逐步地一层一层地细化直至用所选用的语言完全描述每一个细节,即得到所期望
的程序为止。换言之,它是按照先全局后局部、先整体后细节、先抽象后具体的过程组织人们的思维活动,使得编写出的程序结构清晰、容易理解、容
易验证、容易修改。“逐步求精”方法与模块化设计方法既有联系又有区别。粗略地讲,逐步求精主要指一个程序的设计过程,而模块化设计主要指比较
大的系统的设计过程。
此外,面对“软件危机”,人们调查研究了软件生产的实际情况,逐步感到采用工程化的方法从事软件系统的研究和维护的必要性,于是与程序设计
方法学密切相关的软件工程在1968年应运而生。软件工程的主要对象是大型软件。软件工程研究的内容主要包括:软件质量保证和质量评价;软件研制
和维护的方法、工具、文档;用户界面的设计以及软件管理等。软件工程的最终目的是摆脱手工生产软件的状况,逐步实现软件研制和维护的自动化。