1、 表示已有答案 表示没有处理 表示答案不确定 C++笔试题 1.多态类中的虚函数表是Compile-Time,还是Run-Time时建立的? 答案:虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组.而对象的隐藏成员--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键. 3.main主函数执行完毕后,是否可能会再执行一段代码?(朗讯的一道笔试题) 答案:可以,可以用_onexit 注册一个函数,它会在main 之后执行; 如果你需要加入一段在main退出后执行的代码,可以使用atexit()函数,注册
2、一个函数。
语法:
#include
3、 atexit( fn3 ); atexit( fn4 ); printf( "This is executed first.\n" ); } void fn1() { printf( "next.\n" ); } void fn2() { printf( "executed " ); } void fn3() { printf( "is " );
4、 } void fn4() { printf( "This " ); } 结果: This is executed first. This is executed next. 4.一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态? 在子类的空间里,有没有父类的这个函数,或者父类的私有变量? (华为笔试题) 答案:只要基类在定义成员函数时已经声明了virtue关键字,在派生类实现的时候覆盖该函数时,virtue关键字可加可不
5、加,不影响多态的实现。子类的空间里有父类的所有变量(static除外)。 5.给一个字符串、例如 “ababc”要求返回“ab”. 因为“ab”连续重复出现且最长。 用C/C++语言写一函数完成该算法,给出复杂度 6.对序列1、1、2、3、5、8、13。。。。 是Fab..数列 2、3、5、13...是Fab..质数数列,因为他们与自己前面的Fab...数列都互质 给出k,返回第k小的Fab..质数 7.101个硬币100真、1假,真假区别在于重量。请用无砝码天平称两次给出真币重还是假币 重的结论。 8.完成字符串拷贝可以使用 sprintf、strc
6、py 及 memcpy 函数,请问这些函数有什么区别 ,你喜欢使用哪个,为什么? 答案:这些函数的区别在于 实现功能 以及 操作对象 不同。 1.strcpy 函数操作的对象是 字符串,完成 从 源字符串 到 目的字符串 的 拷贝 功能。 2.snprintf 函数操作的对象不限于字符串:虽然目的对象是字符串,但是源对象可以是字符串、也可以是任意基本类型的数据。这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。如果源对象是字符串,并且指定 %s 格式符,也可实现字符串拷贝功能。 3.memcpy 函数顾名思义就是 内存拷贝,实现 将一个 内存块 的内容复制到另一个 内存
7、块 这一功能。内存块由其首地址以及长度确定。程序中出现的实体对象,不论是什么类型,其最终表现就是在内存中占据一席之地(一个内存区间或块)。因此,memcpy 的操作对象不局限于某一类数据类型,或者说可 适用于任意数据类型,只要能给出对象的起始地址和内存长度信息、并且对象具有可操作性即可。鉴于 memcpy 函数等长拷贝的特点以及数据类型代表的物理意义,memcpy 函数通常限于同种类型数据或对象之间的拷贝,其中当然也包括字符串拷贝以及基本数据类型的拷贝。 对于字符串拷贝来说,用上述三个函数都可以实现,但是其实现的效率和使用的方便程度不同: · strcpy 无疑是最合适的选择:效率高且
8、调用方便。 · snprintf 要额外指定格式符并且进行格式转化,麻烦且效率不高。 · memcpy 虽然高效,但是需要额外提供拷贝的内存长度这一参数,易错且使用不便;并且如果长度指定过大的话(最优长度是源字符串长度 + 1),还会带来性能的下降。其实 strcpy 函数一般是在内部调用 memcpy 函数或者用汇编直接实现的,以达到高效的目的。因此,使用 memcpy 和 strcpy 拷贝字符串在性能上应该没有什么大的差别。 对于非字符串类型的数据的复制来说,strcpy 和 snprintf 一般就无能为力了,可是对 memcpy 却没有什么影响。但是,对于基本数据类型来说,尽管
9、可以用 memcpy 进行拷贝,由于有赋值运算符可以方便且高效地进行同种或兼容类型的数据之间的拷贝,所以这种情况下 memcpy 几乎不被使用。memcpy 的长处是用来实现(通常是内部实现居多)对结构或者数组的拷贝,其目的是或者高效,或者使用方便,甚或两者兼有。
9.变量的声明和定义有什么区别?
10.请写出下面代码在 32 位平台上的运行结果,并说明 sizeof 的性质:
#include
10、)malloc(20 * sizeof(char)); printf("%d\n", sizeof(a)); printf("%d\n", sizeof(b)); printf("%d\n", sizeof(a[3])); printf("%d\n", sizeof(b+3)); printf("%d\n", sizeof(*(b+4))); return 0 ; } 12.请完成以下题目。注意,请勿直接调用 ANSI C 函数库中的函数实现。 a)请编写一个 C 函数,该函数给
11、出一个字节中被置 1 的位的个数,并请给出该题的至少一个不同解法。 第一种unsigned int TestAsOne0(char log) { int i; unsigned int num=0, val; for(i=0; i<8; i++) { val = log >> i; //移位 val &= 0x01;
12、 //与1相与 if(val) num++; } return num; } 第二种unsigned int TestAsOne1(char log) { int i; unsigned int num=0, val; for(i=0; i<8; i++) {
13、 val = (~log) >> i; //反码? val &= 0x00; //与0相与 if(!val) num++; } return num; } b)请编写一个 C 函数,该函数将给定的一个字符串转换成整数。 int Invert(char *str) { int n
14、um=0; while(*str!='\0') { int digital=*str-48; num=num*10+digital; str=str+1; } return num; } c)请编写一个 C 函数,该函数将给定的一个整数转换成字符串。 void IntToCharChange(int num, char* pval) { char strval[100]; int i, j; int val0 = 0;
15、 int val1 = 0; val0 = num; for(i=0; i<100; i++) { val1 = val0 % 10; //取余 val0 = val0 / 10; //取整 strval[i] = val1 + 48; //数字—字符 if(va
16、l0 < 10) { i++; strval[i] = val0 + 48; break; } } for(j=0; j<=i; j++) //倒置 { pval[j] = strval[i-j]; } pval[j] = '\0';
17、 } d)请编写一个 C 函数,该函数将一个字符串逆序。 void AntitoneValue(char* father, char* child) { int i; char source[100]; int j = 0; while(father[j]) //放入source,[j]为长度 { source[j] = father[j]; j++; if(j > 99) {
18、
return;
}
}
source[j] = '\0';
for(i=0; i 19、{
int i;
for(i=0; i 20、
}
while( i< Stringlen )
{
if(*(p+i)==*(p+j)&&j< Stringlen)
{
len++; //统计子串长度
i++;
j++;
}
else
{
if(len>maxlen) //统计最大子串长度
{
maxlen=len+1;
len=0;
}
else {
21、len=0;
}
i++;
j++;
}
}
return maxlen;
}
给出演示上述函数功能的一个简单程序,并请编写对应的 Makefile 文件
13.我们需要编写一个图形相关的应用程序,需要处理大量图形(Shape)信息,图形有矩形(Rectangle),正方形(Square),圆形 (Circle)等种类,应用需要计算这些图形的面积,并且可能需要在某个设备上进行显示(使用在标准输出上打印信息的方式做为示意)。
a) 22、请用面向对象的方法对以上应用进行设计,编写可能需要的类
b)请给出实现以上应用功能的示例性代码,从某处获取图形信息,
并且进行计算和绘制
c)如果你的Square继承自Rectangle,请给出理由,如果不是,
请给出理由,并且请比较两种方式的优劣
d)请问你所编写的类,在如下代码中会有何表现,请解释
void test_rectangle_area(Rectangle& r)
{
r.set_width(10);
r.set_height(15);
assert 23、r.area() == 150);
}
14.假设现有一个单向的链表,但是只知道只有一个指向该节点的指针p,并且假设这个节
点不是尾节点,试编程实现删除此节点
参考:将下一个节点的内容复制到本节点上,然后删除下一个节点;
15.写一个程序,把一个100以内的自然数分解因数。(自然数分解因数就是将一个自然数
分解为几个素数的乘积,提示,由于该数不是很大,所以可以将质数保存在数组中,以加快计
算速度)
16.编写一个Identify的分配、释放的函数,为1-10000之间的自然数。
17.分别实现itoa和atoi.
18.Consider the follo 24、wing code:
#include 25、结果
b) Name several ways in which the security problem that causes this program not to output what the programmer intended can be prevented WITHOUT changing the code.
参考:第一个问题:
32位情况:
x86下,栈方向向上生长.在main的栈中,先分配i空间(4byte),然后分配4个字节的buf(地址在i的上面,比i小).strcpy越界,用0把buf开始的第4(0开始)个字节覆盖掉了.而x86 26、是LSB排列顺序,所以真好覆盖了i的内个数字1.所以显示出数字0.
16位情况同样分析即可.
第2问?
19.int w=1,x=2,y=3,z=4;
m=(w 27、
for(i=0;i<4;i++)
fwrite(&a[i],sizeof(int),1,fp);//这里也帮忙看一下
fclose(fp);
fp=fopen("data.dat","rb");
fseek(fp,-2L*sizeof(int),SEEK_END);//还有这里
fread(&b,sizeof(int),1,fp);//这里还有也看一下
fclose(fp);
printf("b=%d\n",b);
}
21.有双向循环链表结点:(华为面试题)
typedef struct node
{ 28、
int date;
struct node *front,*next;
}_Node;
有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两上链表中date值相同的结点删除
参考算法:
1.取出A的一个元素d
2.收集B中有相同元素d的结点到垃圾箱,并从B里删除
3.收集A中有相同元素d的结点到垃圾箱,并从A里删除
4.删除垃圾箱中的所有元素
5.A链的指针指向下一个
6.重复1~5,直到A链循环到头了
注意的是第3步,在2步执行后垃圾箱不为空时才执行 29、
上述算法还可以做一点点优化:
1.加入两个变量cA, cB,分别记录当前A中和B中的元素个数
每次从较长者中取出一个元素来,先从较小者中找起
若没有,则不必在较长者中浪费时间了
#include 30、t boy=0;
NODE *pa=ahead,*pb=bhead,*paa,*paaa,*paaaa,*pbb;
while(pa->next!=ahead)
{
int boys=pa->date; //取pa中一个值
paaaa=pa;
paa=pa;
pb=bhead;
whi 31、le(pb->next!=bhead)
{
if(boys==pb->date) //如果pa,pb中有值相同
{
cout< 32、 if(pb==bhead)
{
boy=1;
pb->front->next=pb->next;
pb->next->front=pb->front;
33、 bhead=bhead->next;
pbb=pb;
pb=pb->next;
delete pbb;
}
else
34、 {
boy=1;
pb->front->next=pb->next;
pb->next->front=pb->front;
pbb=pb;
35、 pb=pb->next;
delete pbb;
}
}
else
pb=pb->next;
} 36、
while(paa->next!=ahead && boy==1)
{
if(paa->date==boys)
{
cout<<"delete A:"< 37、pa)
{
pa=pa->next;
ahead=pa;
paa->front->next=paa->next;
paa->next->front=paa 38、>front;
paaa=paa;
paa=paa->next;
delete paaa;
}
else
39、 {
paa->front->next=paa->next;
paa->next->front=paa->front;
paaa=paa;
paa=paa->next;
40、 delete paaa;
}
}
else
{
paa=paa->next;
}
41、 }
boy=0;
if(paaaa==pa)
pa=pa->next;
}
cout< 42、 NODE;
pHeadA=A;
pHeadB=B;
for(int i=1;i<21;++i) //生成链表A,并赋初值!
{
A->date=i;
A->next=new NODE;
A->next->front=A;
A=A->next;
} 43、
A=A->front;
delete A->next;
A->next=pHeadA;
pHeadA->front=A;
for(int i=1;i<33;i+=2) //生成链表B,并赋初值!
{
B->date=i;
B->next=new NODE;
44、 B->next->front=B;
B=B->next;
}
B=B->front;
delete B->next;
B->next=pHeadB;
pHeadB->front=B;
redel(pHeadA,pHeadB); //调用函数删除相同结点!
}
22.
char * GetStr()
45、
{
char *tmp;
tmp = "123"
return tmp;
}
void main()
{
printf("%s", GetStr());
}
会输出123吗?123创建在堆上还是栈上呢?123的空间是什么时候释放的?
参考:"123" 是常量字符串,存储在全局变量区,和静态变量一起。即不在堆,也不在栈 在程序结束时自动释放
23.1)字符指针、浮点数指针、以及函数指针这三种类型的变量哪个占用的内存最大?为什么?
答案:指针变量也占用内存单元,而且所有指针变量占用内存单元的数量都是相同的。就是说,不管是指向何种对象的指针变量,它们占 46、用内存的字节数都是一样的,并且要足够把程序中所能用到的最大地址表示出来(通常是一个机器字长)。
2)类ClassB从ClassA派生,那么ClassA *a = new ClassB(…); 试问该表达是否合法?为什
么?
答案:派生类的指针指向基类的对象是错误的,不能通过编译的; 基类的指针可以指向派生类的对象,调用派生类的函数
鸡是动物,没错。( 动物的指针 指向 鸡的实例)
鸡可以执行所有动物都具有的方法,例如 “死亡”
反过来,动物一定是鸡吗?(鸡的指针 指向 动物或者动物的某个派生类的实例)
动物都能执行鸡的某个方法吗?比如说 “下蛋”?
3)如果ClassA 47、中定义并实现虚函数int func(void),ClassB中也实现该函数,那么上述变量
a->func()将调用哪个类里面的函数?如果int func(void)不是虚函数,情况又如何?为什
么?
答案:第一问调用的是B的。第二问调用A的。
虚函数的一个典型应用,虚函数只能借助于指针或者引用来达到多态的效果
如果没有定义成虚函数:------
class A{
public:
void print(){ cout<<”This is A”< 48、is B”< 49、<<”This is B”< 50、
如下所述的if else和switch语句哪个的效率高?为什么?
5)在同一个进程中,一个模块是否可以通过指针操作破坏其它模块的内存,为什么?(华为)
6)应用程序在运行时的内存包括代码区和数据区,其中数据区又包括哪些部分?
参考:对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。
24.Assignment 2: Pictu






