C/C++笔试题(很多)

时间:2021-12-03 14:54:44

微软亚洲技术中心的面试题!!!

.进程和线程的差别。

线程是指进程内的一个执行单元,也是进程内的可调度实体.

与进程的区别:

(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

(3)拥有资源:进程是拥有资源的独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. 

(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。

2.测试方法

人工测试:个人复查、抽查和会审

机器测试:黑盒测试和白盒测试

.Heap与stack的差别

Heap是堆,stack是栈。

Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。

Stack空间有限,Heap是很大的*存储区

C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。

程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行

.Windows下的内存是如何管理的?

.介绍.Net和.Net的安全性。

.客户端如何访问.Net组件实现Web Service?

.C/C++编译器中虚表是如何完成的?

.谈谈COM的线程模型。然后讨论进程内/外组件的差别。

.谈谈IA32下的分页机制

小页(4K)两级分页模式,大页(4M)一级

.给两个变量,如何找出一个带环单链表中是什么地方出现环的?

一个递增一,一个递增二,他们指向同一个接点时就是环出现的地方   ??

.在IA32中一共有多少种办法从用户态跳到内核态?

通过调用门,从ring3到ring0,中断从ring3到ring0,进入vm86等等

.如果只想让程序有一个实例运行,不能运行两个。像winamp一样,只能开一个窗口,怎样实现?

用内存映射或全局原子(互斥变量)、查找窗口句柄.. 

FindWindow,互斥,写标志到文件或注册表,共享内存。. 

.如何截取键盘的响应,让所有的‘a’变成‘b’?

键盘钩子SetWindowsHookEx

.Apartment在COM中有什么用?为什么要引入?

.存储过程是什么?有什么用?有什么优点?

存储过程(Stored Procedure)是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库。中用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

存储过程用于实现频繁使用的查询、业务规则、被其他过程使用的公共例行程序

存储过程在创建时即在服务器上进行编译,所以执行起来比单个 SQL 语句快

.Template有什么特点?什么时候用?

.谈谈Windows DNA结构的特点和优点。

17.网络编程中设计并发服务器,使用多进程与多线程 ,请问有什么区别?

,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。

,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。

区别:两者都可以提高程序的并发度,提高程序运行效率和响应时间。线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

MSRA Interview Written Exam(December 2003,Time:2.5 Hours)

写出下列算法的时间复杂度。

(1)冒泡排序; 

(2)选择排序; 

(3)插入排序; 

(4)快速排序; 

(5)堆排序; 

(6)归并排序;

写出下列程序在X86上的运行结果。

struct mybitfields 



unsigned short a : 4; 

unsigned short b : 5; 

unsigned short c : 7; 

}test

void main(void)  



int i; 

test.a=2; 

test.b=3; 

test.c=0;

i=*((short *)&test); 

printf("%d/n",i); 

}

写出下列程序的运行结果。

unsigned int i=3; 

cout<<i * -1;

写出下列程序所有可能的运行结果。

int a; 

int b; 

int c;

void F1() 



b=a*2; 

a=b; 

}

void F2() 



c=a+1; 

a=c; 

}

main() 



a=5; 

//Start F1,F2 in parallel 

F1(); F2(); 

printf("a=%d/n",a); 

}

考察了一个CharPrev()函数的作用。

对 16 Bits colors的处理,要求:

(1)Byte转换为RGB时,保留高5、6bits; 

(2)RGB转换为Byte时,第2、3位置零。

一个链表的操作,注意代码的健壮和安全性。要求:

(1)增加一个元素; 

(2)获得头元素; 

(3)弹出头元素(获得值并删除)。

一个给定的数值由左边开始升位到右边第N位,如 0010<<1 == 0100 或者 

0001 0011<<4 == 0011 0000 请用C或者C++或者其他X86上能运行的程序实现。

附加题(只有在完成以上题目后,才获准回答)

。In C++, what does "explicit" mean? what does "protected" mean?

c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,在某些情况下,我们要求类的使用者必须显示调用类的构造函数时就需要使用explicit,反之默认类型转换可能会造成无法预期的问题。

protected控制的是一个函数对一个类的成员(包括成员变量及成员方法)的访问权限。protected成员只有该类的成员函数及其派生类的成员函数可以访问

1.  在C++中有没有纯虚构造函数?

构造函数不能是虚的。只能有虚的析构函数

2.  在c++的一个类中声明一个static成员变量有没有用?

在C++类的成员变量被声明为static(称为静态成员变量),意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,也就是说不管创建多少对象,static修饰的变量只占有一块内存。其修改值为该类的其它所有实例所见;而类的静态成员函数也只能访问静态成员(变量或函数)。

static是加了访问控制的全局变量,不被继承。

。在C++的一个类中声明一个静态成员函数有没有用? (同上?)

。如何实现一个非阻塞的socket?

。setsockopt, ioctl都可以对socket的属性进行设置,他们有什么不同? (linux)

。解释一下进程和线程的区别? (重复,参见微软亚洲技术中心笔试)

。解释一下多播(组播)和广播的含义?

组播:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。

广播:主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要).

。多播采用的协议是什么?

。在c++中纯虚析构函数的作用是什么?请举例说明。

。编程,请实现一个c语言中类似atoi的函数功能(输入可能包含非数字和空格)

百度笔试题

一、选择题:15分 共10题 

1.    在排序方法中,关键码比较次数与记录地初始排列无关的是    . 

A. Shell排序      B. 归并排序       C. 直接插入排序     D. 选择排序

2.    以下多线程对int型变量x的操作,哪几个需要进行同步: 

A. x=y;         B. x++;         C. ++x;            D. x=1;

3.    代码 

void func() { 

        static int val; 

        … } 中,变量val的内存地址位于: 

A. 已初始化数据段    B.未初始化数据段      C.堆              D.栈

4.    同一进程下的线程可以共享以下 

A. stack            B. data section   C. register set        D. thread ID

5.    TCP和IP分别对应了 OSI中的哪几层? 

A.  Application layer 

B.  Data link layer 

C.  Presentation layer 

D.  Physical layer 

E.  Transport layer 

F.  Session layer 

G.  Network layer

6.    short a[100],sizeof(a)返回? 

A 2     B 4       C 100       D 200        E 400

7.    以下哪种不是基于组件的开发技术_____。 

A XPCOM        B XP           C COM                D CORBA

8.    以下代码打印的结果是(假设运行在i386系列计算机上): 

    struct st_t 

    { 

        int    status; 

        short* pdata; 

        char   errstr[32]; 

    };

st_t  st[16]; 

    char* p = (char*)(st[2].errstr + 32); 

    printf("%d", (p - (char*)(st)));

A 32          B 114       C 120         D 1112

9.    STL中的哪种结构是连续形式的存储 

A  map      B  set         C  list      D  vector

10.    一个栈的入栈序列是A,B,C,D,E,则栈的不可能的输出序列是( ) 

A、EDCBA;   B、DECBA;    C、DCEAB;    D、ABCDE

参考答案:D /ABC/ A/ BC /EG /D /B/ C/ D/ C

二、简答题:20分,共2题

1.    (5分)重复多次fclose一个打开过一次的FILE *fp指针会有什么结果,并请解释。 

考察点:导致文件描述符结构中指针指向的内存被重复释放,进而导致一些不可预期的异常。

2.    (15分)下面一段代码,想在调用f2(1)时打印err1,调用f2(2)时打印err4,但是代码中有一些问题,请做尽可能少的修改使之正确。 

     

1    static int f1(const char *errstr, unsigned int flag) { 

2        int copy, index, len; 

3        const static char **__err = {“err1”, “err2”, “err3”, “err4”}; 

4     

5        if(flag & 0x10000) 

6            copy = 1; 

7        index = (flag & 0x300000) >> 20; 

8      

9        if(copy) { 

10            len = flag & 0xF; 

11            errstr = malloc(len); 

12            if(errstr = NULL) 

13                return -1; 

14            strncpy(errstr, __err[index], sizeof(errstr)); 

15        } else 

16            errstr =  __err + index;     

17    } 

18 

19    void f2(int c) { 

20        char *err; 

22        swtch(c) { 

23        case 1: 

24            if(f1(err, 0x110004) != -1) 

25                printf(err); 

26        case 2: 

27            if(f2(err, 0x30000D) != -1) 

28                printf(err); 

29        } 

30 }

三、编程题:30分 共1题    注意:要求提供完整代码,如果可以编译运行酌情加分。

1.    求符合指定规则的数。 

给定函数d(n) = n + n的各位之和,n为正整数,如 d(78) = 78+7+8=93。 这样这个函数可以看成一个生成器,如93可以看成由78生成。  

定义数A:数A找不到一个数B可以由d(B)=A,即A不能由其他数生成。现在要写程序,找出1至10000里的所有符合数A定义的数。 

输出: 





四、设计题:35分 共1题 

注意:请尽可能详细描述你的数据结构、系统架构、设计思路等。建议多写一些伪代码或者流程说明。

1.    假设一个mp3搜索引擎收录了2^24首歌曲,并记录了可收听这些歌曲的2^30条URL,但每首歌的URL不超过2^10个。系统会定期检查这些URL,如果一个URL不可用则不出现在搜索结果中。现在歌曲名和URL分别通过整型的SONG_ID和URL_ID唯一确定。对该系统有如下需求: 

1)    通过SONG_ID搜索一首歌的URL_ID,给出URL_ID计数和列表 

2)    给定一个SONG_ID,为其添加一个新的URL_ID 

3)    添加一个新的SONG_ID 

4)    给定一个URL_ID,将其置为不可用

限制条件:内存占用不超过1G,单个文件大小不超过2G,一个目录下的文件数不超过128个。

为获得最佳性能,请说明设计的数据结构、搜索算法,以及资源消耗。如果系统数据量扩大,该如何多机分布处理?

汉略曾考的测试题目

Q:When speaking of software products, how do you define the term“quality”.

问:当说到软件产品的时候,你如何定义术语“质量”

Meeting customer requirements

Q:What is the role of software debelopers and quality assuranle engineers in ensuring the quality of the product? How are other functional areas important to developing a quality product?

问:在确定产品的质量方面,什么是软件开发工程师和质量保证工程师要做的?其他的功能对如何发展产品质量有什么重要?

 软件测试是贯穿整个软件开发生命周期、对软件产品(包括阶段性产品)进行验证和确认的活动过程,其目的是尽快尽早地发现在软件产品中所存在的各种问题——与用户需求、预先定义的不一致性。Quality assuranle engineers: use a set of activities designed to ensure the development process
to meet the requirements.

Q:What is cyclomatic complexity?

问:(这是一个复杂度模型吧)

一种代码复杂度的衡量标准,中文名称叫做圈复杂度。圈复杂度“用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,根据经验,程序的可能错误和高的圈复杂度有着很大关系”。

Q:What are black-box texing and white-box texting?

问:什么是黑盒测试和白盒测试?

黑盒测试Black-box
Testing
,又称为功能测试数据驱动测试)是把测试对象看作一个黑盒子。利用黑盒测试法进行动态测试时,需要测试软件产品的功能,不需测试软件产品的内部结构和处理过程。采用黑盒技术设计测试用例的方法有:等价划分、边界值分析、错误推测、因果图和综合策略。黑盒测试注重于测试软件的功能性需求,也即黑盒测试使软件工程师派生出执行程序所有功能需求的输入条件。黑盒测试并不是白盒测试的替代品,而是用于辅助白盒测试发现其他类型的错误。

白盒测试(White-box
Testing
,又称逻辑驱动测试,结构测试)是把测试对象看作一个打开的盒子。利用白盒测试法进行动态测试时,需要测试软件产品的内部结构和处理过程,不需测试软件产品的功能。白盒测试又称为结构测试和逻辑驱动测试。白盒测试法的覆盖标准有逻辑覆盖、循环覆盖和基本路径测试。其中逻辑覆盖包括语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖。

Black box testing: a testing without knowledge of the internal working of the item being tested.



white box testing: use specific knowledge of programming code to examine outputs.

Q:The following function divides a by b and out put to c,returns -1 as error.

  Int divide (int a,int b,int c)

  List you test cases in a black-box testing.

问:对 Int divide (int a,int b,int c)函数写出黑盒测试用例

先等价,后边界值

a       b         c         预期         结果   

  g       g   

  5       0     

  6       2     

  0       1   

  -10   10   

  -10     -10   

  10.0   10.0  

Q:Int a ctivity(int nage,bool bmale)

  {if (nage<60)

    return zoo;

    else if(bmale)

    return golf;

    else return movie;

  } 

用cyclomatic   complexity,共有多少条路径   

   3

Q:The following function tests whether the three numbers can be the lengths of the three sides of a triangle.

Bool triangle(float a,float b,float c)

List you test cases in a black-box testing.

问:也是让写黑盒测试用例,是一个三个数是否是三角形的三条边的测试

先等价,后边界值

a       b         c         预期         结果   

  g       j         0   

  -1     2           2   

  10     2         3   

  2       3         4   

  2       2         5   

  6       6         6

IQ,EQ题

然后是英文的数据结构,c/c++,数据库,3D建模,软件工程,软件测试

题目几乎都是英文的

后面还要填表格,一张中文的,一张英文的

一般有三个步骤

首先会笔试。笔试题分为EQ题和专业题,EQ题没什么好说的,大家*发挥就行,不过其中有一些逻辑推理题要注意。专业题目全英文,考的内容很多,数据结构,C/C++语法,COM,3D建模,软件测试基础知识,如黑盒,白盒测试等,题不难,每方面有三到五题左右。

笔试成绩达到一定分数过后才能进入第二轮人事部面试。这部分面试一般是五人一组在一房间里,面试人员会问很多问题,然后每个人做答,问题很随机,当时好像问了“最尊敬的人是谁,最难忘的事是什么,有何职业规划,如何处理与同事之间的关系矛盾等等”。

这轮过后就到技术部面试,会问一些基础知识,如数据结构常用的有哪些,如何用C/C++写出其中的一种,面象对像有哪些特性,XML是什么等等,可能他会用英语问你这些问题,各位练下听力口语哈(当时俺被问的很郁闷)

COM:

(COM),是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术。在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制;可以在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下;COM与语言,平台无关的特性使所有的程序员均可充分发挥自己的才智与专长编写组件模块;等等。COM是开发软件组件的一种方法。组件实际上是一些小的二进制可执行程序,它们可以给应用程序,操作系统以及其他组件提供服务。

开发自定义的COM组件就如同开发动态的,面向对象的API。多个COM对象可以连接起来形成应用程序或组件系统。并且组件可以在运行时刻,在不被重新链接或编译应用程序的情况下被卸下或替换掉。Microsoft的许多技术,如ActiveX, DirectX以及OLE等都是基于COM而建立起来的。并且Microsoft的开发人员也大量使用COM组件来定制他们的应用程序及操作系统。

COM所含的概念并不止是在Microsoft Windows操作系统下才有效。COM并不是一个大的API,它实际上象结构化编程及面向对象编程方法那样,也是一种编程方法。在任何一种操作系统中,开发人员均可以遵循“COM方法”。 有的组件必须满足两个条件:第一,组件必须动态链接;第二,它们必须隐藏(或封装)其内部实现细节。动态链接对于组件而言是一个至关重要的要求,而消息隐藏则是动态链接的一个必要条件。对于COM来讲,接口是一个包含一个函数指针数组的内存结构。每一个数组元素包含的是一个由组件所实现的函数地址。

1.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分)

int a = 4;

(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);

a = ?

答:C错误,左侧不是一个有效变量,不能赋值,可改为(++a) += a;

改后答案依次为9,10,10,11

2.某32位系统下, C++程序,请计算sizeof 的值(5分).

char str[] = “www.ibegroup.com”

char *p = str ;

int n = 10;

请计算

sizeof (str ) = ?(1)

sizeof ( p ) = ?(2)

sizeof ( n ) = ?(3)

void Foo ( char str[100]){

请计算

sizeof( str ) = ?(4)

}

void *p = malloc( 100 );

请计算

sizeof ( p ) = ?(5)

答:(1)17 (2)4 (3) 4 (4)4 (5)4

3. 回答下面的问题. (4分)

(1).头文件中的 ifndef/define/endif 干什么用?预处理

答:防止头文件被重复引用

(2). #include 和 #include “filename.h” 有什么区别?

答:前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。

(3).在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?

答:函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。

(4). switch()中不允许的数据类型是?

答:实型

4. 回答下面的问题(6分)

(1).Void GetMemory(char **p, int num){

*p = (char *)malloc(num);

}

void Test(void){

char *str = NULL;

GetMemory(&str, 100);

strcpy(str, "hello");

printf(str);

}

请问运行Test 函数会有什么样的结果?

答:输出“hello”

(2). void Test(void){

char *str = (char *) malloc(100);

strcpy(str, “hello”);

free(str);

if(str != NULL){

strcpy(str, “world”);

printf(str);

}

}

请问运行Test 函数会有什么样的结果?

答:输出“world”

(3). char *GetMemory(void){

char p[] = "hello world";

return p;

}

void Test(void){

char *str = NULL;

str = GetMemory();

printf(str);

}

请问运行Test 函数会有什么样的结果?

答:无效的指针,输出不确定

5. 编写strcat函数(6分)

已知strcat函数的原型是char *strcat (char *strDest, const char *strSrc);

其中strDest 是目的字符串,strSrc 是源字符串。

(1)不调用C++/C 的字符串库函数,请编写函数 strcat

答:

VC源码:

char * __cdecl strcat (char * dst, const char * src)

{

char * cp = dst;

while( *cp )

cp++; /* find end of dst */

while( *cp++ = *src++ ) ; /* Copy src to end of dst */

return( dst ); /* return dst */

}

(2)strcat能把strSrc 的内容连接到strDest,为什么还要char * 类型的返回值?

答:方便赋值给其他变量

6.MFC中CString是类型安全类么?

答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换

7.C++中为什么用模板类。

答:(1)可用来创建动态增长和减小的数据结构

(2)它是类型无关的,因此具有很高的可复用性。

(3)它在编译时而不是运行时检查数据类型,保证了类型安全

(4)它是平台无关的,可移植性

(5)可用于基本数据类型

8.CSingleLock是干什么的。

答:同步多个线程对一个数据类的同时访问

9.NEWTEXTMETRIC 是什么。

答:物理字体结构,用来设置字体的高宽大小

10.程序什么时候应该使用线程,什么时候单线程效率高。

答:1.耗时的操作使用线程,提高应用程序响应

.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。

.多CPU系统中,使用线程提高CPU利用率

.改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

其他情况都使用单线程。

11.Windows是内核级线程么。

答:见下一题

12.Linux有内核级线程么。

答:线程通常被定义为一个进程中代码的不同执行路线。从实现方式上划分,线程有两种类型:“用户级线程”和“内核级线程”。 用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统中也可实现,但线程的调度需要用户程序完成,这有些类似 Windows 3.x 的协作式多任务。另外一种则需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部需求进行创建和撤销,这两种模型各有其好处和缺点。用户线程不需要额外的内核开支,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占用了更多的系统开支。 Windows
NT和OS/2支持内核线程。Linux 支持内核级的多线程

13.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中?

答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理

堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上

14.使用线程是如何防止出现大的波峰。

答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队等候。

函数模板与类模板有什么区别?

答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。

一般数据库若出现日志满了,会出现什么情况,是否还能使用?

答:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记录日志。也就是说基本上处于不能使用的状态。

17 SQL Server是否支持行级锁,有什么好处?

答:支持,设立*机制主要是为了对并发操作进行控制,对干扰进行*,保证数据的一致性和准确性,行级*确保在用户取得被更新的行到该行进行更新这段时间内不被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的并发性。

如果数据库满了会出现什么情况,是否还能使用?

答:见16

19 关于内存对齐的问题以及sizeof()的输出

答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

20 int i=10, j=10, k=3; k*=i+j; k最后的值是?

答:60,此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低

21.对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现?

答:将操作多个表的操作放入到事务中进行处理

22.TCP/IP 建立连接的过程?(3-way shake)

答:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

23.ICMP是什么协议,处于哪一层?

答:Internet控制报文协议,处于网络层(IP层)

24.触发器怎么工作的?

答:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数据的处理必须符合由这些SQL 语句所定义的规则。

25.winsock建立连接的主要实现步骤?

答:服务器端:socket()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接。

客户端:socket()建立套接字,连接(connect)服务器,连接上后使用send()和recv(),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。

服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesocket()关闭套接字。

26.动态连接库的两种方式?

答:调用一个DLL中的函数有两种方法:

.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向系统提供了载入DLL时所需的信息及DLL函数定位。

.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或LoadLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了

27.IP组播有那些好处?

答:Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播技术的核心就是针对如何节约网络资源的前提下保证服务质量。

托管代码

使用基于公共语言运行库的语言编译器开发的代码称为托管代码;托管代码具有许多优点,例如:跨语言集成、跨语言异常处理、增强的安全性、版本控制和部署支持、简化的组件交互模型、调试和分析服务等。

重载

每个类型成员都有一个唯一的签名。方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。只要签名不同,就可以在一种类型内定义具有相同名称的多种方法。当定义两种或多种具有相同名称的方法时,就称作重载。

道C语言面试题例子

预处理器(Preprocessor)

1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 

我在这想看到几件事情: 

1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 

2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。 

3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。 

4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。

2. 写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。

#define MIN(A,B) ((A) <= (B)?(A) : (B)) 

这个测试是为下面的目的而设的: 

1). 标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。 

2). 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。 

3). 懂得在宏中小心地把参数用括号括起来 

4). 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事? 

least = MIN(*p++, b);

3. 预处理器标识#error的目的是什么?

如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。#error 停止编译并显示错误信息



死循环(Infinite loops)

4. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?

这个问题用几个解决方案。我首选的方案是: 

while(1) 





一些程序员更喜欢如下方案: 

for(;;) 





这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下一个坏印象。 

第三个方案是用 goto 

Loop: 

... 

goto Loop; 

应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。

数据声明(Data declarations) 

5. 用变量a给出下面的定义 

a) 一个整型数(An integer) 

b) 一个指向整型数的指针(A pointer to an integer) 

c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) 

d) 一个有10个整型数的数组(An array of 10 integers) 

e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) 

f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) 

g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) 

h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )

答案是: 

a) int a; // An integer 

b) int *a; // A pointer to an integer 

c) int **a; // A pointer to a pointer to an integer 

d) int a[10]; // An array of 10 integers 

e) int *a[10]; // An array of 10 pointers to integers 

f) int (*a)[10]; // A pointer to an array of 10 integers 

g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer 

h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。 但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道 所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?

Static

6. 关键字static的作用是什么?

这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用: 

1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 

2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 

3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。 

大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。

Const 

7.关键字const是什么含意? 

我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是什么意思?

const int a;   //a是一个常整型数

int const a;   //a是一个常整型数

const int *a; //一个指向常整型数的指针,整型数是不可修改的,但指针可以

int * const a; //一个指向整型数的常指针,指针指向的整型数是可以修改的,指针不可修改

int const * a const;// 一个指向常整型数的常指针,整型数不可修改,指针也是不可修改的

(主要看const靠近*还是int,不可修改的就是它)

前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由: 

1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。) 

2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。 

3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

Volatile

8. 关键字volatile有什么含意 并给出三个不同的例子。

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 

1). 并行设备的硬件寄存器(如:状态寄存器) 

2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 

3). 多线程应用中被几个任务共享的变量 

回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 

假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 

1). 一个参数既可以是const还可以是volatile吗?解释为什么。 

2). 一个指针可以是volatile 吗?解释为什么。 

3). 下面的函数有什么错误: 

int square(volatile int *ptr) 



return *ptr * *ptr; 



下面是答案: 

1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 

2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 

3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: 

int square(volatile int *ptr) 



int a,b; 

a = *ptr; 

b = *ptr; 

return a * b; 



由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下: 

long square(volatile int *ptr) 



int a; 

a = *ptr; 

return a * a; 

}

位操作(Bit manipulation)

9. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。

对这个问题有三种基本的反应 

1). 不知道如何下手。该被面者从没做过任何嵌入式系统的工作。 

2). 用bit fields。Bit fields是被扔到C语言死角的东西,它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用的。我最近不幸看到Infineon为其较复杂的通信芯片写的驱动程序,它用到了bit fields因此完全对我无用,因为我的编译器用其它的方式来实现bit fields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。 

3). 用 #defines 和 bit masks 操作。这是一个有极高可移植性的方法,是应该被用到的方法。最佳的解决方案如下: 

#define BIT3 (0x1<<3) 

static int a; 

void set_bit3(void) 



a |= BIT3; 



void clear_bit3(void) 



a &= ~BIT3; 



一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=~操作。

访问固定的内存位置(Accessing fixed memory locations) 

10. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。

这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下: 

int *ptr; 

ptr = (int *)0x67a9; 

*ptr = 0xaa55;

一个较晦涩的方法是: 

*(int * const)(0x67a9) = 0xaa55;

即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。



中断(Interrupts) 

11. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。



__interrupt double compute_area (double radius) 



double area = PI * radius * radius; 

printf(" Area = %f", area); 

return area; 

}

这个函数有太多的错误了,以至让人不知从何说起了: 

1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。 

2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。 

3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。 

4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。



代码例子(Code examples)

12 . 下面的代码输出是什么,为什么?

void foo(void) 



unsigned int a = 6; 

int b = -20; 

(a+b > 6) puts("> 6") : puts("<= 6"); 

}

这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。 因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。



13. 评价下面的代码片断:

unsigned int zero = 0; 

unsigned int compzero = 0xFFFF; 

/*1's complement of zero */

对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:

unsigned int compzero = ~0;

这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。 

到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错,那么我就扔出下面的追加问题,这些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是答案。不管如何,你就当是这个娱乐吧…

动态内存分配(Dynamic memory allocation)

14. 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?

这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是 P.J. Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:下面的代码片段的输出是什么,为什么?

char *ptr; 

if ((ptr = (char *)malloc(0)) == NULL) 

puts("Got a null pointer"); 

else 

puts("Got a valid pointer"); 

这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是“Got a valid pointer”。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。



Typedef 

15. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子: 

#define dPS struct s * 

typedef struct s * tPS; 

以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么? 

这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子: 

dPS p1,p2; 

tPS p3,p4;

第一个扩展为 

struct s * p1, p2;

上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。



晦涩的语法

16. C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么? 

int a = 5, b = 7, c; 

c = a+++b;

这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成: 

c = a++ + b; 

因此, 这段代码持行后a = 6, b = 7, c = 12。 

如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题

群硕笔试:

基本概念,涉及到C++、Java、软件测试、EJB、ASP和ASP.NET的知识。

今天群硕笔试,考了好多内容,其中Java占很大部分!

本试卷中最有难度的编程题:给定一个数组,这个数组中既有正数又有负数,找出这个数组中的子数组,此子数组的和最大!

#include<stdio.h>

void main()

{

int a[15]={2,3,-4,5,6,-5,-1,14,9,-10,1,-71,75,4,-9};

int b[15]; //计算和

int num=a[14];

int c[15]; //最大尾数标志数组



int n=14;

int i,j=0;



for(i=14;i>=0;i--) //从后计算和放入b中



c[i]=n;b[i]=num;

if(num<0){n=i-1;num=0;}

num=num+a[i-1];

}



printf("/n");

for(i=0;i<15;i++)

printf("%d, ",b[i]);

printf("/n");



//找到最大字符子串

num=b[0];n=c[0];

for(i=0;i<15;i++)

if(b[i]>num){num=b[i];j=i;n=c[i];}

for(i=j;i<=n;i++)

printf("%d, ",a[i]);

printf("sum=%d",num);

}

最不知道怎么答的题:在TCP/IP中最经常使用的编程方法?

最简单的题:final, finally, finalize的区别(因为经常考)

final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。

finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。

finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

最容易疏忽的题:main(){C c;}在前面已经定义了C的类,这个地方容易迷糊的就是,没有new,照样执行构造函数,没有free,照样执行析构函数。

最迷糊的题:一个无向图是否能够存到树中?为什么?

最然我感到有差距的题:EJB中一定包括()interface,()interface,()class

不用任何变量交换a,b两个变量

用递归求最大公约数

举一个多态的例子

二叉平衡树(特性,内插入和 外 插入)

UNIX进程包括那三个部分:...(简单)

new动态分配失败会抛出什么异常,C++中提供了那两个标准函数来设定异常处理HANLDER(有点难度)

EJB包含那几种?区别(压根没听过)

asp和asp.net的区别(假期做项目的时候碰到过,嘿嘿)

JAVA中的interface 和 abstract class区别(照着c里面的感念随便写了点)

logic thinking:检测电冰箱(我用软件工程的思想随便写写)

1.内连接与外连接的区别。

3.内联的定义,什么情况下选择内联。

4.什么是多态,用一段代码说明。

5.不经过第三者变量来交换两个整型数。

6.EJB都有那些Beans.

7.什么是平衡二叉树。

8.当new出错后怎么处理。

9.asp与asp.net的最大区别。

10.如何证明一个电冰箱是否是好的

1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现     

  一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空     

  间,能否设计一个算法实现?

template   <typename   T,   int   index>   

  struct   SumArr   

  {   

  static   int   GetValue(T*   arr)   

  {   

  return   arr[index]   +   SumArr<T,   index-1>::GetValue(arr);   

  }   

  };   

    

  template   <typename   T>   

  struct   SumArr<T,   0>   

  {   

  static   int   GetValue(T*   arr)   

  {   

  return   arr[0];   

  }   

  };   

    

  int   main()   

  {   

  int   arry[11]   =   {1,2,3,4,5,6,7,8,9,10,2};   

  printf("%d",   SumArr<int,   10>::GetValue(arry)   -   11   *   5);   

  }

基础题:

1_1  什么叫做多态性? 在C++中是如何实现多态的?

解:多态是指同样的消息被不同类型的对象接收时导致完全不同的行为,是对类的特定成员函数的再抽象。C++支持的多态有多种类型,重载(包括函数重载和运算符重载)和虚函数是其中主要的方式。

1_2  什么叫做抽象类? 抽象类有何作用? 抽象类的派生类是否一定要给出纯虚函数的实现?

解:带有纯虚函数的类是抽象类。抽象类的主要作用是通过它为一个类族建立一个公共的接口,使它们能够更有效地发挥多态特性。抽象类声明了一组派生类共同操作接口的通用语义,而接口的完整实现,即纯虚函数的函数体,要由派生类自己给出。但抽象类的派生类并非一定要给出纯虚函数的实现,如果派生类没有给出纯虚函数的实现,

这个派生类仍然是一个抽象类。

autodesk笔试

晚上参加了autodesk笔试,留下了一丝的残念,mfc好久没有用几乎忘光了,com学院没有开这门课,还得靠自学T_T晚上听了报告,发现autodesk公司真的很不错.在cadc部门能接触到autocad最核心的代码,这是在另外很多外企所碰不到的.autolove部分那张脸上充满笑容忘着远方的小女孩的照片很让人感动,很钦佩autodesk公司所做的公益活动.得复习一下专业知识了,以后还将有很多的招聘会.

附笔试题目:

.What is virtual function ?what is vtable used for?

虚函数主要用于实现多态用,基类的某个函数前加个Virtual 用来告诉编译系统,遇到这个处理过程时,要等到执行时再确定到底调用哪个类的处理过程;

每一个虚函数都会有一个入口地址,虚函数表保存所有虚函数的入口地址

2.What's the difference between "struct" and "class" in c++?

  struct成员默认类型为public,class成员默认类型为private。即为数据的封装。

如果没有多态和虚拟继承,在C++中,struct和class的存取效率完全相同!简单的说就是,存取class的data member和非virtual function效率和struct完全相同!不管该data member是定义在基类还是派生类的。如果不是为了和C兼容,C++中就不会有struct关键字。

3.What do we need to make destructor vitual?why?

CObject的析构函数设为virtual型,则所有CObject类的派生类的析构函数都将自动变为virtual型,这保证了在任何情况下,不会出现由于析构函数未被调用而导致的内存泄露

4.What to declare member function as const?

void fun1(int a) const;const的作用是指在该函数内部不会改变此类的成员变量(除非该成员变量定义时加上violate关键字),否则修改了该成员变量就会报错.

5.What is the Message reflection in MFC?



6.How many ways to get the handle of a model dialog?what are they?



7.How to change the default window procedure after the window shows up?



8.What is the difference between STA and MTA in COM?



9.What is marshaling in COM?



10.What is dual interface in COM?



11.What is the difference between aggregated and contained object in COM?



12.Write an insert function for a sorted singly linked list please take into considerations of various conditions including error conditions?



13.智力题目. 甲乙丙丁是血缘关系,其中一个与其他三个性别不同,其中有甲的母亲,乙的哥哥,丙的父亲,丁的女儿。知道其中年龄最大的和最小的性别不同,问谁和其他人性别不同。

1. dynamic binding

2. default private

3. for safe deleting base classes

4. sometype foo const;

5. use some macro, create a message table

6-12. i'll keep it blank...

13. 丁最大,男的

Autodesk笔试题目

C/C++ Programming

1,列出两个情况是必须使用成员初始化列表,而不在构造函数里面赋值

,#define DOUBLE(x) x+x

i = 5 * DOUBLE(10)

这个时候i是什么结果?

正确的DOUBLE应该怎样写?

,static_cast和dynamic_cast有什么区别?

,namespace解决了什么问题?

,auto_ptr是什么东西,有什么用?



Algorithm and GP

1, 写出三个你熟悉的排序法,以时间复杂度的大小排序

, 写出一个使用递归来反转一个单向链表的函数

, 写一个程序测试系统是Big_Endian的还是Little_Endian的(以前万老师发帖讨论过了)



C++ Programming

1, C++有管理多种内存,分别写出他们是什么,他们的特性和性能如何?

, 写出一个基于char*的string类,包括构造析构函数和赋值运算符,取字串长度等基本操作



Graphic(两题都不会,全忘了)

……



IQ

1, 称面粉(经典题)

, 在平面上有一系列间距为2的无限长的平行线,在上面扔单位长度的线段,和平行线相交的概率是多少?

, A君和B君见到B君的三个熟人X,Y,Z

A君问B君:“他们的多大”

B君说:“他们的年龄之和是我们的年龄之和,他们的年龄的乘积是2450”

A说:“我还是不知道”

B说:“他们都比我们的朋友C要小”

A说:“那我知道了”

问C的年龄是多少?

MFC(不太会做,记不清楚了)

, 怎么为窗口自定义消息

窗口自定义消息。。需用宏定义。。声明消息为WM_USER以后的消息号。。然后用USER_COMMAND做消息映射。。。最后。。自己搞个callback。。。

, SendMessage和PostMessage的区别

sendmessage是消息发送给指定的callback函数后立即执行。。当前的调用挂起。。postmessage只是把消息发送到消息队列。。然后返回。。。所以在消息循环中。。用的是postmessage而不是sendmessage。。

, CRuntimeClass是由什么用的?他是怎样得到的?

, 怎样通过一个句柄得到CWnd的指针

fromhandle函数可以得到指定cwnd的m_hwnd。。

笔试博朗   - [笔试 职业]

 

早上起的早了一点,刚好看到版上置顶的帖子第一个是博朗,反正也没有别的事,抄了一份简历过去。

笔试分为两个部分,综合素质测试以及软件知识相关。软件考试如同考高程,一共20个题目。大概有操作系统的状态转换

三态:运行态,就绪态,等待态

硬件中断

有限自动向量机

有限自动机(Finite Automata):有限自动机=有限控制器+字符输入带

如果有限状态机每次转换后的状态是唯一的则称之为确定有限状态机(DFA);如果转换后的后继状态不是唯一的则称之为不确定有限自动机(NFA);

数据库

链表操作(出入新元素,很简单)

数据结构中的树,

加密问题

PING的协议(ICMP?)

Ping命令是在互连网络中进行故障检测的工具,通俗地说就是它向指定的机器发送一个消息,然后通知是否成功地传送了该消息. ping利用了ICMP中的请求回显和应答回显的功能. ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机。ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。

ICMP协议通过IP协议发送的,IP协议是一种无连接的,不可靠的数据包协议。在Unix/Linux,序列号从0开始计数,依次递增。而Windows ping程序的ICMP序列号是没有规律。

UML知识(全军覆没,没接触过这玩意)

用对象模型、动态模型、功能模型和用例模型,共同完成对整个系统的建模. UML的定义包括UML语义和UML表示法两个部分.从应用的角度看,当采用面向对象技术设计系统时,首先是描述需求;其次根据需求建立系统的静态模型,以构造系统的结构;第三步是描述系统的行为。其中在第一步与第二步中所建立的模型都是静态的,包括用例图、类图(包含包)、对象图、组件图和配置图等五个图形,是标准建模语言UML的静态建模机制。其中第三步中所建立的模型或者可以执行,或者表示执行时的时序状态或交互关系。它包括状态图、活动图、顺序图和合作图等四个图形,是标准建模语言UML的动态建模机制。因此,标准建模语言UML的主要内容也可以归纳为静态建模机制和动态建模机制两大类。

UML的组成

UML模型还可作为测试阶段的依据。系统通常需要经过单元测试集成测试系统测试验收测试。不同的测试小组使用不同的UML图作为测试依据:单元测试使用类图和类规格说明;集成测试使用部件图和合作图;系统测试使用用例图来验证系统的行为;验收测试由用户进行,以验证系统测试的结果是否满足在分析阶段确定的需求。

UML的静态建模 机制包括用例图(Use case diagram)、类图(Class
diagram
)、对象图(Object diagram )、包(Package)、构件图(Component
diagram
)和配置图(Deployment diagram)。

在UML中,一个用例模型由若干个用例图描述,用例图主要 元素是用例和执行者。用例(use case) 从本质上讲,一个用例是用户与计算机之间的一次典型交互作用。在UML中,用例表示为一个椭圆。执行者(Actor) 执行者是指用户在系统中所扮演的角色。其图形化的表示是一个小人。

在UML中,类 和对象模型分别由类图和对象图表示. UML规定类的属性的语法为: 可见性 属性名 : 类型 = 缺省值 {约束特性} 图1"客户"类中,"客户名"属性描述为"- 客户名 : 字符串 = 缺省客户名"。

常用的可见性有Public、Private和Protected三种,在U ML中分别表示为"+"、"-"和"#"。

关联类通过一根虚线与关联连接。

聚集和组成 聚集(Aggregation)是一种特殊形式的关联。聚集表示类之间的关系是 整体与部分的关系。一辆轿车包含四个车轮、一个方向盘、一个发动机和一个底盘,这是 聚集的一个例子。在需求分析中,"包含"、"组成"、"分为……部分"等经常设计成聚集关 系。聚集可以进一步划分成共享聚集(Shared Aggregation)和组成。

已知后序,中序,求前序

堆的结构。

答的惨不忍睹啊,数了数,大概就10个能对的,其他是一点吃不准。

考完软件,立刻考逻辑,就是一大堆的数据,40个题目,40min要做完。可怜我还没有计算器,做的我累死了。到最后还有10几个没勾,我也懒得乱勾了。交卷。

有几点点要bs一下这个公司,

Java中除了使用new,还有其他的实例化方法吗?(我说了ClassLoader和Class.forNa

me,他就继续问了些,然后我感觉没底)

2.java.util包中你最常用那些类?(我说Collection)Collection分那两类?List和Set

有什么区别?自定义对象如何保证在Set中的唯一性?(我回答equals&hashCode)

3.谈谈JDBC中的DataSource

4.JSP中如何包含其他页面?(我回答jsp:include标签和include指令)然后他问我两个之

间差别?

5.servlet中有哪些接口和方法?GET和POST请求有哪些区别?

6.分布式事务处理和RMI?(这些我不是很熟,只是接触过,所以就老实回答我不知道)

7.Applet和普通Application的区别?Applet如何获取哪些安全权限?(我回答了两种方

式和应用情况)然后他就问Java的安全机制有哪些?

8.谈谈PKI和数字证书(我的项目有PKI)

9.JDOM?DOM有哪些优缺点?SAX?

10.JAVA多线程如何实现?如何获得共享对象的副本?(我回答clone和并发控制,他觉得

不是很满意,可能我回答得不到点)

11.J2EE有哪些设计模式?会话外观是什么?

12.UML里你常用哪些图?用例图是什么?如何描述用例里面的流程?(我回答了用例描述

和活动图)

14.数据库和J2EE服务器用过哪些?说了些软件,然后我主动说里面的机理不熟。

这个东西有些参考价值,和同学讨论一下发现还是有些错误,



1.已知strcpy 函数的原型是:

char *strcpy(char *strDest, const char *strSrc);

其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy

答案:

char *strcpy(char *strDest, const char *strSrc)

{

if ( strDest == NULL || strSrc == NULL)

return NULL ;

if ( strDest == strSrc)

return strDest ;

char *tempptr = strDest ;

while( (*strDest++ = *strSrc++) != ‘’);

return tempptr ;

}



2.已知类String 的原型为:

class String

{

public:

String(const char *str = NULL); // 普通构造函数

String(const String &other); // 拷贝构造函数

~ String(void); // 析构函数

String & operate =(const String &other); // 赋值函数

private:

char *m_data; // 用于保存字符串

};

请编写String 的上述4 个函数。

答案:

String::String(const char *str)

{

if ( str == NULL ) //strlen在参数为NULL时会抛异常才会有这步判断

{

m_data = new char[1] ;

m_data[0] = '' ;

}

else

{

m_data = new char[strlen(str) + 1];

strcpy(m_data,str);

}

}

String::String(const String &other)

{

m_data = new char[strlen(other.m_data) + 1];

strcpy(m_data,other.m_data);

}

String & String::operator =(const String &other)

{

if ( this == &other)

return *this ;

delete []m_data;

m_data = new char[strlen(other.m_data) + 1];

strcpy(m_data,other.m_data);

return *this ;

}

String::~ String(void)

{

delete []m_data ;

}



3.简答

3.1 头文件中的ifndef/define/endif 干什么用?

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

3.2#include <filename.h> 和#include “filename.h” 有什么区别?

答:对于#include <filename.h> ,编译器从标准库路径开始搜索filename.h

对于#include “filename.h”,编译器从用户的工作路径开始搜索filename.h

3.3 在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

答:C++语言支持函数重载,C 语言不支持函数重载。函数被C++编译后在库中的名字与C 语言的不同。假设某个函数的原型为: void foo(int x, int y);

该函数被C 编译器编译后在库中的名字为_foo , 而C++ 编译器则会产生像_foo_int_int 之类的名字。

C++提供了C 连接交换指定符号extern“C”来解决名字匹配问题。

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

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

3.5 请描述一个你熟悉的设计模式(Autodesk)

3.6 在UML 中,聚合(aggregation)和组合(composition)有什么区别 Autodesk)

答案:聚合关系更强,类似于pages 和book 的关系;组合关系要弱,类似于books和bookshelf 的关系。

3.7C#和C++除了语法上的差别以外,有什么不同的地方?(Autodesk,Microsoft)

答案:(C#我只是了解,不是很精通)

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

3.8ADO.net 和ADO 的区别?

答案:实际上除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。但是ADO 使用OLE DB 接口并基于微软的COM 技术,而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。

3.9 New delete 与malloc free 的区别 ( Autodesk)

答案:用malloc 函数不能初始化对象,new 会调用对象的构造函数。Delete 会调用对象的destructor,而free 不会调用对象的destructor.

3.10 #define DOUBLE(x) x+x (Autodesk)

i = 5*DOUBLE(10); i 是多少?正确的声明是什么?

答案:i 为60。正确的声明是#define DOUBLE(x) (x+x)

3.11 有哪几种情况只能用intialization list 而不能用assignment? (Autodesk)

答案:当类中含有const、reference 成员变量;基类的构造函数都需要参数;类中含有其他类的成员对象,而该类的构造函数都需要参数。

3.11 C++是不是类型安全的? (Autodesk)

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

3.12 main 函数执行以前,还会执行什么代码? (Autodesk)

答案:全局对象的构造函数会在main 函数之前执行。

3.13 描述内存分配方式以及它们的区别。 (Autodesk , Microsoft)

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

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

(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

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

见操作系统 p238 页。掌握的页面替换算法NRU,FIFO,第二次机会页面替换算法,LRU

3.15 有四个同样的容器,里面装满了粒数相同的药丸,正常药丸的质量为m,变质药丸的质量为m+1,现在已知这四个容器中,有一个装的全是变质药丸,用电子秤只称一次,找出哪个容器装的是变质药丸 (Microsoft)

答案:把四个容器依次编号为1、2、3、4,然后从中分别取出1、2、3、4 粒药丸,称这10 粒药丸的质量,如果质量为10m+1,则说明第一个容器装的是变质药丸,如果为10m+2 则说明第二个装的变质药丸,依次类推。

3.16 比较一下C++中static_cast 和 dynamic_cast 的区别。 (Autodesk)

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

3.17 Struct 和class 的区别 (Autodesk)

答案:struct 中成员变量和成员函数默认访问权限是public,class 是private

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

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

3.19 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)

答案:通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址*10H+通用寄存器内地址,就得到了真正要访问的地址。

3.20 描述一下C++的多态 (microsoft)

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



4.写出BOOL,int,float,指针类型的变量a 与零的比较语句。

答案:

BOOL : if ( !a )

int : if ( a == 0)

float : const EXPRESSION EXP = 0.000001

if ( a < EXP && a >-EXP)

pointer : if ( a != NULL)



5.请说出const 与#define 相比优点

答案:

(1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

(2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。



.简述数组与指针的区别

数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。

(1)修改内容上的差别

char a[] = “hello”;

a[0] = ‘X’;

char *p = “world”; // 注意p 指向常量字符串

p[0] = ‘X’; // 编译器不能发现该错误,运行时错误

(2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。

char a[] = "hello world";

char *p = a;

cout<< sizeof(a) << endl; // 12 字节

cout<< sizeof(p) << endl; // 4 字节

计算数组和指针的内存容量

void Func(char a[100])

{

cout<< sizeof(a) << endl; // 4 字节而不是100 字节

}



7.类成员函数的重载、覆盖和隐藏区别

答案:

成员函数被重载的特征:

(1)相同的范围(在同一个类中);

(2)函数名字相同;

(3)参数不同;

(4)virtual 关键字可有可无。

覆盖是指派生类函数覆盖基类函数,特征是:

(1)不同的范围(分别位于派生类与基类);

(2)函数名字相同;

(3)参数相同;

(4)基类函数必须有virtual 关键字。

“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)



.There are two int variables: a and b, don’t use “if”, “? :”, “switch”

or other judgement statements, find out the biggest one of the two

numbers.

答案:( ( a + b ) + abs( a – b ) ) / 2



9.如何打印出当前源文件的文件名以及源文件的当前行号?

答案:

cout << __FILE__ ;

cout<<__LINE__ ;

__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。



.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;

}

int fn2()

{

printf( "executed " );

return 0;

}

int fn3()

{

printf( "is " );

return 0;

}

int fn4()

{

printf( "This " );

return 0;

}

The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit
cannot take parameters.



11.如何判断一段程序是由C 编译程序还是由C++编译程序编译的?

答案:

#ifdef __cplusplus

cout<<"c++";

#else

cout<<"c";

#endif



12.文件中有一组整数,要求排序后输出到另一个文件中

答案:

void Order(vector<int> &data) //起泡排序

{

int count = data.size() ;

int tag = false ;

for ( int i = 0 ; i < count ; i++)

{

for ( int j = 0 ; j < count - i - 1 ; j++)

{

if ( data[j] > data[j+1])

{

tag = true ;

int temp = data[j] ;

data[j] = data[j+1] ;

data[j+1] = temp ;

}

}

if ( !tag )

break ;

}

}

void main( void )

{

vector<int>data;

ifstream in("c://data.txt");

if ( !in)

{

cout<<"file error!";

exit(1);

}

int temp;

while (!in.eof())

{

in>>temp;

data.push_back(temp);

}

in.close();

Order(data);

ofstream out("c://result.txt");

if ( !out)

{

cout<<"file error!";

exit(1);

}

for ( i = 0 ; i < data.size() ; i++)

out<<data[i]<<" ";

out.close();

}



13.排序方法比较 (intel)

排序方法 平均时间 最坏时间 辅助存储

直接插入排序

起泡排序

快速排序

简单选择排序

堆排序

归并排序

基数排序



.一个链表的结点结构

struct Node

{

int data ;

Node *next ;

};

typedef struct Node Node ;

(1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)

Node * ReverseList(Node *head) //链表逆序

{

if ( head == NULL || head->next == NULL )

return head;

Node *p1 = head ;

Node *p2 = p1->next ;

Node *p3 = p2->next ;

p1->next = NULL ;

while ( p3 != NULL )

{

p2->next = p1 ;

p1 = p2 ;

p2 = p3 ;

p3 = p3->next ;

}

p2->next = p1 ;

head = p2 ;

return head ;

}

(2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。

Node * Merge(Node *head1 , Node *head2)

{

if ( head1 == NULL)

return head2 ;

if ( head2 == NULL)

return head1 ;

Node *head = NULL ;

Node *p1 = NULL;

Node *p2 = NULL;

if ( head1->data < head2->data )

{

head = head1 ;

p1 = head1->next;

p2 = head2 ;

}

else

{

head = head2 ;

p2 = head2->next ;

p1 = head1 ;

}

Node *pcurrent = head ;

while ( p1 != NULL && p2 != NULL)

{

if ( p1->data <= p2->data )

{

pcurrent->next = p1 ;

pcurrent = p1 ;

p1 = p1->next ;

}

else

{

pcurrent->next = p2 ;

pcurrent = p2 ;

p2 = p2->next ;

}

}

if ( p1 != NULL )

pcurrent->next = p1 ;

if ( p2 != NULL )

pcurrent->next = p2 ;

return head ;

}

(2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 ( Autodesk)

答案:

Node * MergeRecursive(Node *head1 , Node *head2)

{

if ( head1 == NULL )

return head2 ;

if ( head2 == NULL)

return head1 ;

Node *head = NULL ;

if ( head1->data < head2->data )

{

head = head1 ;

head->next = MergeRecursive(head1->next,head2);

}

else

{

head = head2 ;

head->next = MergeRecursive(head1,head2->next);

}

return head ;

}



15.分析一下这段程序的输出 (Autodesk)

class B

{

public:

B()

{

cout<<"default constructor"<<endl;

}

~B()

{

cout<<"destructed"<<endl;

}

B(int i):data(i)

{

cout<<"constructed by parameter" << data <<endl;

}

private:

int data;

};

B Play( B b)

{

return b ;

}

int main(int argc, char* argv[])

{

B temp = Play(5);

return 0;

}

请自己执行一下看看。



16.写一个函数找出一个整数数组中,第二大的数 (microsoft)

答案:

const int MINNUMBER = -32767 ;

int find_sec_max( int data[] , int count) //类似于1 4 4 4这样的序列将认为1是第二大数

{

int maxnumber = data[0] ;

int sec_max = MINNUMBER ;

for ( int i = 1 ; i < count ; i++)

{

if ( data[i] > maxnumber )

{

sec_max = maxnumber ;

maxnumber = data[i] ;

}

else

{

if ( data[i] > sec_max )

sec_max = data[i] ;

}

}

return sec_max ;

}



17 写一个在一个字符串中寻找一个子串第一个位置的函数

这个题目的一般算法比较简单我就不给出了,如果要求高效率的话请参见数据结构中的KMP 算法,不过在笔试时间有限情况下,写出那个算法还是挺难的。





英文题目

1. Introduce yourself in English

2. What is your great advantage you think of yourself?

3. What is your drawback you think of yourself?

Maybe I will feel very tense if I make a speech in front of a lot of people.

4. How do you feel shanghai?

C语言面试题大汇总

2.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。

循环链表,用取余操作做

3.不能做switch()的参数类型是:

switch的参数不能为实型。

4. static有什么用途?(请至少说明两种)

1.限制变量的作用域

2.设置变量的存储域

7. 引用与指针有什么区别?

1) 引用必须被初始化,指针不必。

2) 引用初始化以后不能被改变,指针可以改变所指的对象。

2) 不存在指向空值的引用,但是存在指向空值的指针。

8. 描述实时系统的基本特性

在特定时间内完成特定的任务,实时性与可靠性

9. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

全局变量储存在静态数据库,局部变量在堆栈

10. 什么是平衡二叉树?

左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1

11. 堆栈溢出一般是由什么原因导致的?

没有回收垃圾资源

12. 什么函数不能声明为虚函数?

constructor

13. 冒泡排序算法的时间复杂度是什么?

O(n^2)

14. 写出float x 与“零值”比较的if语句。

if(x>0.000001&&x<-0.000001)

16. Internet采用哪种网络协议?该协议的主要层次结构?

tcp/ip 应用层/传输层/网络层/数据链路层/物理层

17. Internet物理地址和IP地址转换采用什么协议?

ARP (Address Resolution Protocol)(地址解析协议)

18.IP地址的编码分为哪俩部分?

IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。

思科

 

1. 用宏定义写出swap(x,y)

#define swap(x, y)

x = x + y;

y = x - y;

x = x - y;

2.数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:int do_dup(int a[],int N)

答案:方法1:如果数就是1-N-1,那么求出a[N]的和,然后减去1-N-1就行了。(确定数字1-N)

S = N * (N-1) / 2;

int i;

int s = 0;

for(i=0;i<N;++i)

{

s += a[i];

}

int res = s - S;

方法2.a[]中的某元素a[i]看做是pi[]数组的下标,元素a[i]存储到对应数组下标pi[a[i]]的地址中

#include<stdio.h> 

#define N 10 

void main() 

{  

 int a[N]={1,2,3,4,5,6,7,7,8,9}; 

 int pi[N]={0}; 

 int key=0; 

 for(int i=0;i<N;i++) 

 {  if(pi[a[i]]==0) 

   pi[a[i]]=a[i]; 

   else  

    { key=a[i]; 

      break; 

     } 

   } 

 printf("多余的数字是%d/n",key); 

}

3 一语句实现x是否为2的若干次幂的判断

位运算

int i = 512;  cout << boolalpha << ((i & (i - 1)) ? false : true) << endl;

4.unsigned int intvert(unsigned int x,int p,int n)实现对x的进行转换,p为起始转化位,n为需要转换的长度,假设起始点在右边.如x=0b0001 0001,p=4,n=3转换后x=0b0110 0001

unsigned int intvert(unsigned int x,int p,int n){

unsigned int _t = 0;

unsigned int _a = 1;

for(int i = 0; i < n; ++i){

_t |= _a;

_a = _a << 1;

}

_t = _t << p;

x ^= _t;

return x;

}

慧通:

什么是预编译

何时需要预编译:

1、总是使用不经常改动的大型代码体。 

2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。

char * const p;

char const * p

const char *p

上述三个有什么区别?

char * const p; //常量指针,p的值不可以修改

char const * p;//指向常量的指针,指向的常量值不可以改

const char *p; //同char const *p



char str1[] = "abc";

char str2[] = "abc";

const char str3[] = "abc";

const char str4[] = "abc";

const char *str5 = "abc";

const char *str6 = "abc";

char *str7 = "abc";

char *str8 = "abc";

cout << ( str1 == str2 ) << endl;

cout << ( str3 == str4 ) << endl;

cout << ( str5 == str6 ) << endl;

cout << ( str7 == str8 ) << endl;

结果是:0 0 1 1解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;而str5,str6,str7,str8是指针,它们指向相同的常量区域。



一个32位的机器,该机器的指针是多少位

指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。



main()

{ int a[5]={1,2,3,4,5};

  int *ptr=(int *)(&a+1);

  printf("%d,%d",*(a+1),*(ptr-1));

}

输出:2,5

*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5;&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)int *ptr=(int *)(&a+1); 则ptr实际是&(a[5]),也就是a+5

原因如下:

&a是数组指针,其类型为 int (*)[5];而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同a是长度为5的int数组指针,所以要加 5*sizeof(int)所以ptr实际是a[5]

但是prt与(&a+1)类型是不一样的(这点很重要),所以prt-1只会减去sizeof(int*);

a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].



1.请问以下代码有什么问题:

int main()

{  char a;

   char *str=&a;

   strcpy(str,"hello");

   printf(str);

   return 0;

}

没有为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。



char* s="AAA";

printf("%s",s);

s[0]='B';

printf("%s",s);

有什么错?

"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。

cosnt char* s="AAA";然后又因为是常量,所以对是s[0]的赋值操作是不合法的。

、写一个“标准”宏,这个宏输入两个参数并返回较小的一个。

#define Min(X, Y) ((X)>(Y)?(Y):(X))       注意结尾没有;

、嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。

  while(1){}或者for(;;)

、关键字static的作用是什么?

  定义静态变量

、关键字const有什么含意?

表示常量不可以修改的变量。

、关键字volatile有什么含意?并举出三个不同的例子?

提示编译器对象的值可能在编译器未监测到的情况下改变。

int (*s[10])(int) 表示的是什么

int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。



1.有以下表达式:

int a=248; b=4;int const c=21;const int *d=&a;

int *const e=&b;int const *f const =&a;

请问下列表达式哪些会被编译器禁止?为什么?

*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;

*c 这是个什么东东,禁止

*d 说了是const, 禁止

e = &a 说了是const 禁止

const *f const =&a; 禁止

2.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;

有两种解法, 一种用算术算法, 一种用^(异或)

a = a + b;

b = a - b;

a = a - b; 

or

a = a^b;// 只能对int,char..

b = a^b;

a = a^b;

or

a ^= b ^= a;

3.c和c++中的struct有什么不同?

c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private

4.#include <stdio.h>

#include <stdlib.h>

void getmemory(char *p)

{

p=(char *) malloc(100);

strcpy(p,"hello world");

}

int main( )

{

char *str=NULL;

getmemory(str);

printf("%s/n",str);

free(str);

return 0;

}

程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险

5.char szstr[10];

strcpy(szstr,"0123456789");

产生什么结果?为什么?

长度不一样,会造成非法的OS

6.列举几种进程的同步机制,并比较其优缺点。

原子操作 

信号量机制

自旋锁

管程,会合,分布式系统



7.进程之间通信的途径

共享存储系统

消息传递系统

管道:以文件系统为基础

11.进程死锁的原因

资源竞争及进程推进顺序非法

12.死锁的4个必要条件

互斥、请求保持、不可剥夺、环路

13.死锁的处理

鸵鸟策略、预防策略、避免策略、检测与解除死锁

15. 操作系统中进程调度策略有哪几种?

FCFS(先来先服务),优先级,时间片轮转,多级反馈

8.类的静态成员和非静态成员有何区别?

类的静态成员每个类只有一个,非静态成员每个对象一个

9.纯虚函数如何定义?使用时应注意什么?

virtual void f()=0;

是接口,子类必须要实现

10.数组和链表的区别

数组:数据顺序存储,固定大小

连表:数据可以随机存储,大小可动态改变

12.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?

应用层

表示层

会话层

运输层

网络层

物理链路层

物理层

tcp /udp属于运输层

TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。

与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。

tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好

udp: 不提供稳定的服务,包头小,开销小 





:(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针

.(void *)ptr 和 (*(void**))ptr值是相同的

:int main()

{

int x=3;

printf("%d",x);

return 1;



}

问函数既然不会被其它函数调用,为什么要返回1?

mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息





,要对绝对地址0x100000赋值,我们可以用

(unsigned int*)0x100000 = 1234;

那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?

*((void (*)( ))0x100000 ) ( );

首先要将0x100000强制转换成函数指针,即:

(void (*)())0x100000

然后再调用它:

*((void (*)())0x100000)();

用typedef可以看得更直观些:

typedef void(*)() voidFuncPtr;

*((voidFuncPtr)0x100000)();

2,已知一个数组table,用一个宏定义,求出数据的元素个数

#define NTBL

#define NTBL (sizeof(table)/sizeof(table[0]))



面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?

进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。



每个线程有自己的堆栈。

DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?



以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃





unsigned short A = 10;

printf("~A = %u/n", ~A);



char c=128; 

printf("c=%d/n",c);



输出多少?并分析过程

第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285

第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。

这两道题都是在考察二进制向int或uint转换时的最高位处理。



分析下面的程序:

void GetMemory(char **p,int num)

{

*p=(char *)malloc(num);





int main()

{

char *str=NULL;



GetMemory(&str,100);



strcpy(str,"hello");



free(str);



if(str!=NULL)

{

strcpy(str,"world");





printf("/n str is %s",str);

getchar();



问输出结果是什么?希望大家能说说原因,先谢谢了

输出str is world。

free 只是释放的str指向的内存空间,它本身的值还是存在的.

所以free之后,有一个好的习惯就是将str=NULL.

此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,

尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。

这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。

当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。



char a[10],strlen(a)为什么等于15?运行的结果



#include "stdio.h"

#include "string.h"



void main()

{



char aa[10];

printf("%d",strlen(aa));

}



sizeof()和初不初始化,没有关系;

strlen()和初始化有关。





char (*str)[20];/*str是一个数组指针,即指向数组的指针.*/

char *str[20];/*str是一个指针数组,其元素为指针型数据.*/



long a=0x801010;

a+5=?

0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725罗

1)给定结构struct A 

{

char t:4;

char k:4;

unsigned short i:8;

unsigned long m;

};问sizeof(A) = ?

给定结构struct A 

{

char t:4; 4位

char k:4; 4位

unsigned short i:8; 8位 

unsigned long m; // 偏移2字节保证4字节对齐

}; // 共8字节

2)下面的函数实现在一个数上加一个数,有什么错误?请改正。

int add_n ( int n )

{

static int i = 100;

i += n;

return i;

}

当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static上?





// 帮忙分析一下

#include<iostream.h>

#include <string.h>

#include <malloc.h>

#include <stdio.h>

#include <stdlib.h>

#include <memory.h>

typedef struct AA

{

int b1:5;

int b2:2;

}AA;

void main()

{

AA aa;

char cc[100];

strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");

memcpy(&aa,cc,sizeof(AA));

cout << aa.b1 <<endl;

cout << aa.b2 <<endl;

}

答案是 -16和1

首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.

经过strcpy和memcpy后,aa的4个字节所存放的值是:

0,1,2,3的ASC码,即00110000,00110001,00110010,00110011

所以,最后一步:显示的是这4个字节的前5位,和之后的2位

分别为:10000,和01

因为int是有正负之分  所以:答案是-16和1



求函数返回值,输入x=9999; 

int func ( x )



int countx = 0; 

while ( x ) 



countx ++; 

x = x&(x-1); 



return countx; 



结果呢?

知道了这是统计9999的二进制数值中有多少个1的函数,且有

=9×1024+512+256+15



9×1024中含有1的个数为2;

中含有1的个数为1;

中含有1的个数为1;

中含有1的个数为4;

故共有1的个数为8,结果为8。

1000 - 1 = 0111,正好是原数取反。这就是原理。

用这种方法来求1的个数是很效率很高的。

不必去一个一个地移位。循环次数最少。



int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题

bool add (int a, int b,int *c)

{

*c=a+b;

return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b)));

}





分析:

struct bit 

{ int a:3; 

int b:2; 

int c:3; 

}; 

int main() 



bit s; 

char *c=(char*)&s; 

cout<<sizeof(bit)<<endl;

*c=0x99;

cout << s.a <<endl <<s.b<<endl<<s.c<<endl; 

int a=-1;

printf("%x",a);

return 0; 



输出为什么是

4

1

-1

-4

ffffffff

因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100

当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理 

b = -1;

当c为有符合数时, c = 100,即 c = 4,同理 b = 3





位域 : 

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: 

struct 位域结构名 

{ 位域列表 }; 

其中位域列表的形式为: 类型说明符 位域名:位域长度 

例如: 

struct bs 



int a:8; 

int b:2; 

int c:6; 

}; 

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如: 

struct bs 



int a:8; 

int b:2; 

int c:6; 

}data; 

说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明: 



1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如: 

struct bs 



unsigned a:4 

unsigned :0 /*空域*/ 

unsigned b:4 /*从下一单元开始存放*/ 

unsigned c:4 



在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。 



2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。 



3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如: 

struct k 



int a:1 

int :2 /*该2位不能使用*/ 

int b:3 

int c:2 

}; 

从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。 



二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名•位域名 位域允许用各种格式输出。 

main(){ 

struct bs 



unsigned a:1; 

unsigned b:3; 

unsigned c:4; 

} bit,*pbit; 

bit.a=1; 

bit.b=7; 

bit.c=15; 

pri



改错:

#include <stdio.h>



int main(void) {



int **p;

int arr[100];



p = &arr;



return 0;

}

解答:

搞错了,是指针类型不同,

int **p; //二级指针

&arr; //得到的是指向第一维为100的数组的指针

#include <stdio.h>

int main(void) {

int **p, *q;

int arr[100];

q = arr;

p = &q;

return 0;

}





下面这个程序执行后会有什么错误或者效果:

#define MAX 255

int main()

{

unsigned char A[MAX],i;//i被定义为unsigned char

for (i=0;i<=MAX;i++)

A[i]=i;

}

解答:死循环加数组越界访问(C/C++不进行数组越界检查)

MAX=255 

数组A的下标范围为:0..MAX-1,这是其一..

其二.当i循环到255时,循环内执行:

A[255]=255;

这句本身没有问题..但是返回for (i=0;i<=MAX;i++)语句时,

由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.



struct name1{

char str;

short x;

int num;

}



struct name2{

char str;

int num;

short x;

}



sizeof(struct name1)=8,sizeof(struct name2)=12

在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。



intel

A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?

static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。

他们都放在数据区,但是编译器对他们的命名是不同的。

如果要使变量在其他模块也有意义的话,需要使用extern关键字。



struct s1

{  

int i: 8;

int j: 4;

int a: 3;

double b;

};



struct s2

{

int i: 8;

int j: 4;

double b;

int a:3;

};



printf("sizeof(s1)= %d/n", sizeof(s1));

printf("sizeof(s2)= %d/n", sizeof(s2));

result: 16, 24

第一个struct s1

{

int i: 8;

int j: 4;

int a: 3;

double b;

};

理论上是这样的,首先是i在相对0的位置,占8位一个字节,然后,j就在相对一个字节的位置,由于一个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对0要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。

第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数

)读文件file1.txt的内容(例如):

12

34

56

输出到file2.txt:

56

34

12

(逆序)

)输出和为一个给定整数的所有组合

例如n=5

5=1+4;5=2+3(相加的数不能重复)

则输出

,4;2,3。

望高手赐教!!



第一题,注意可增长数组的应用.

#include <stdio.h>

#include <stdlib.h>



int main(void)

{

int MAX = 10;

int *a = (int *)malloc(MAX * sizeof(int));

int *b;



FILE *fp1;

FILE *fp2;



fp1 = fopen("a.txt","r");

if(fp1 == NULL)

{printf("error1");

exit(-1);

}



fp2 = fopen("b.txt","w");

if(fp2 == NULL)

{printf("error2");

exit(-1);

}



int i = 0;

int j = 0;

while(fscanf(fp1,"%d",&a[i]) != EOF)

{

i++;

j++;

if(i >= MAX)

{

MAX = 2 * MAX;

b = (int*)realloc(a,MAX * sizeof(int));

if(b == NULL)

{

printf("error3");

exit(-1);

}

a = b;

}

}



for(;--j >= 0;)

fprintf(fp2,"%d/n",a[j]);



fclose(fp1);

fclose(fp2);



return 0;

}



第二题.

#include <stdio.h>

int main(void)

{

unsigned long int i,j,k;

printf("please input the number/n");

scanf("%d",&i);

if( i % 2 == 0)

j = i / 2;

else

j = i / 2 + 1;



printf("The result is /n");

for(k = 0; k < j; k++)

printf("%d = %d + %d/n",i,k,i - k);

return 0;

}



#include <stdio.h>

void main()

{

unsigned long int a,i=1;

scanf("%d",&a);

if(a%2==0)

{

for(i=1;i<a/2;i++)

printf("%d",a,a-i);

}

else

for(i=1;i<=a/2;i++)

printf(" %d, %d",i,a-i);

}



兄弟,这样的题目若是做不出来实在是有些不应该, 给你一个递规反向输出字符串的例子,可谓是反序的经典例程.



void inverse(char *p)

{

if( *p = = '/0' ) 

return;

inverse( p+1 );

printf( "%c", *p );

}



int main(int argc, char *argv[])

{

inverse("abc/0");



return 0;

}



借签了楼上的“递规反向输出”

#include <stdio.h>

void test(FILE *fread, FILE *fwrite)

{

char buf[1024] = {0};

if (!fgets(buf, sizeof(buf), fread))

return;

test( fread, fwrite );

fputs(buf, fwrite);

}

int main(int argc, char *argv[])

{

FILE *fr = NULL;

FILE *fw = NULL;

fr = fopen("data", "rb");

fw = fopen("dataout", "wb");

test(fr, fw);

fclose(fr);

fclose(fw);

return 0;

}



在对齐为4的情况下

struct BBB

{

long num;

char *name;

short int data;

char ha;

short ba[5];

}*p;

p=0x1000000;

p+0x200=____;

(Ulong)p+0x200=____;

(char*)p+0x200=____;

希望各位达人给出答案和原因,谢谢拉

解答:假设在32位CPU上,

sizeof(long) = 4 bytes

sizeof(char *) = 4 bytes

sizeof(short int) = sizeof(short) = 2 bytes

sizeof(char) = 1 bytes



由于是4字节对齐,

sizeof(struct BBB) = sizeof(*p) 

= 4 + 4 + 2 + 1 + 1/*补齐*/ + 2*5 + 2/*补齐*/ = 24 bytes (经Dev-C++验证)



p=0x1000000;

p+0x200=____;

= 0x1000000 + 0x200*24



(Ulong)p+0x200=____;

= 0x1000000 + 0x200



(char*)p+0x200=____;

= 0x1000000 + 0x200*4



你可以参考一下指针运算的细节

写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。函数接口为:int find_orderk(const int* narry,const int n,const int k) 

要求算法复杂度不能是O(n^2)

谢谢!

可以先用快速排序进行排序,其中用另外一个进行地址查找

代码如下,在VC++6.0运行通过。给分吧^-^



//快速排序



#include<iostream>



usingnamespacestd;



intPartition (int*L,intlow,int high)

{

inttemp = L[low];

intpt = L[low];



while (low < high)

{

while (low < high && L[high] >= pt)

--high;

L[low] = L[high];

while (low < high && L[low] <= pt)

++low;

L[low] = temp;

}

L[low] = temp;



returnlow;

}



voidQSort (int*L,intlow,int high)

{

if (low < high)

{

intpl = Partition (L,low,high);



QSort (L,low,pl - 1);

QSort (L,pl + 1,high);

}

}



intmain ()

{

intnarry[100],addr[100];

intsum = 1,t;



cout << "Input number:" << endl;

cin >> t;



while (t != -1)

{

narry[sum] = t;

addr[sum - 1] = t;

sum++;



cin >> t;

}



sum -= 1;

QSort (narry,1,sum);



for (int i = 1; i <= sum;i++)

cout << narry[i] << '/t';

cout << endl;



intk;

cout << "Please input place you want:" << endl;

cin >> k;



intaa = 1;

intkk = 0;

for (;;)

{

if (aa == k)

break;

if (narry[kk] != narry[kk + 1])

{

aa += 1;

kk++;

}



}



cout << "The NO." << k << "number is:" << narry[sum - kk] << endl;

cout << "And it's place is:" ;

for (i = 0;i < sum;i++)

{

if (addr[i] == narry[sum - kk])

cout << i << '/t';

}





return0;

}

、找错

Void test1()

{

char string[10];

char* str1="0123456789";

strcpy(string, str1);// 溢出,应该包括一个存放'/0'的字符string[11]

}





Void test2()

{

char string[10], str1[10];

for(I=0; I<10;I++)

{

str1[i] ='a';

}

strcpy(string, str1);// I,i没有声明。

}



Void test3(char* str1)

{

char string[10];

if(strlen(str1)<=10)// 改成<10,字符溢出,将strlen改为sizeof也可以

{

strcpy(string, str1);

}

}



2.

void g(int**);

int main()

{

int line[10],i;

int *p=line; //p是地址的地址

for (i=0;i<10;i++)

{

*p=i;

g(&p);//数组对应的值加1

}

for(i=0;i<10;i++)

printf("%d/n",line[i]);

return 0;

}



void g(int**p)

{

(**p)++;

(*p)++;// 无效

}

输出:1 2 3 4 5 6 7 8 9 10

3. 写出程序运行结果

int sum(int a)

{ auto int c=0;

  static int b=3;

  c+=1;

  b+=2;

  return(a+b+c);

}

void main()

{  int I;

   int a=2;

   for(I=0;I<5;I++)

 {

   printf("%d,", sum(a));

  }

}// 考察static会保存上次结果

输出:8,10,12,14,16,



4.int func(int a)

{ int b;

  switch(a)

 {

  case 1: 30;

   case 2: 20;

   case 3: 16;

   default: 0

 }

 return b;

}

则func(1)=?

// b定义后就没有赋值。

5:int a[3];

a[0]=0; a[1]=1; a[2]=2;

int *p, *q;

p=a;

q=&a[2];

则a[q-p]=a[2]=2      解释:指针一次移动一个int但计数为1



今天早上的面试题9道,比较难,向牛人请教,国内的一牛公司,坐落在北京北四环某大厦:

、线形表a、b为两个有序升序的线形表,编写一程序,使两个有序线形表合并成一个有序升序线形表h;

答案在严锐敏《数据结构第二版》第二章例题,数据结构当中,这个叫做:两路归并排序

Linklist *unio(Linklist *p,Linklist *q){

linklist *R,*pa,*qa,*ra;

pa=p;

qa=q;

R=ra=p;

while(pa->next!=NULL&&qa->next!=NULL){

if(pa->data>qa->data){

ra->next=qa;

qa=qa->next;   取两线性表的大值放入ra,并将取值的表指针加1

}

else{

ra->next=pa;

pa=pa->next;

}

}

if(pa->next!=NULL)

ra->next=pa;

if(qa->next!=NULL)

ra->next==qa;

return R;

}

、运用四色定理,为N个局域举行配色,颜色为1、2、3、4四种,另有数组adj[][N],如adj[i][j]=1则表示i区域与j区域相邻,数组color[N],如color[i]=1,表示i区域的颜色为1号颜色。

四色填充

、用递归算法判断数组a[N]是否为一个递增数组。递归的方法,记录当前最大的,并且判断当前的是否比这个还大,大则继续,否则返回false结束:

bool fun( int a[], int n )

{

if( n= =1 )

return true;

if( n= =2 )

return a[n-1] >= a[n-2];

return fun( a,n-1) && ( a[n-1] >= a[n-2] );

}

、编写算法,从10亿个浮点数当中,选出其中最大的10000个。(google,百度,腾讯)

一种是用外部排序,在《数据结构》书上有《计算方法导论》在找到第n大的数的算法上加工?

另外一种是用一个有序容器保存10000个数,然后其他的数字依次和容器中的最小数字比较,如果大于容器已有的,就插入容器并删除原先最小的那个,而容器仍旧保持有序。

、编写一unix程序,防止僵尸进程的出现.

同学的4道面试题,应聘的职位是搜索引擎工程师,后两道超级难,(希望大家多给一些算发)

1.给两个数组和他们的大小,还有一动态开辟的内存,求交集,把交集放到动态内存dongtai,并且返回交集个数

long jiaoji(long* a[],long b[],long* alength,long blength,long* dongtai[])

2.单连表的建立,把'a'--'z'26个字母插入到连表中,并且倒叙,还要打印!

方法1:

typedef struct val

{ int date_1;

struct val *next;

}*p;



void main(void)

{ char c;



for(c=122;c>=97;c--)

{ p.date=c;

p=p->next;

}



p.next=NULL;



}

方法2:

node *p = NULL;

node *q = NULL;



node *head = (node*)malloc(sizeof(node));

head->data = ' ';head->next=NULL;



node *first = (node*)malloc(sizeof(node));

first->data = 'a';first->next=NULL;head->next = first;

p = first;



int longth = 'z' - 'b';

int i=0;

while ( i<=longth )

{

node *temp = (node*)malloc(sizeof(node));

temp->data = 'b'+i;temp->next=NULL;q=temp;



head->next = temp; temp->next=p;p=q;

i++;

}



print(head);

3.可怕的题目终于来了

象搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前十条,我们每次输入的一个字符串为不超过255byte,内存使用只有1G,

请描述思想,写出算发(c语言),空间和时间复杂度,

4.国内的一些帖吧,如baidu,有几十万个主题,假设每一个主题都有上亿的跟帖子,怎么样设计这个系统速度最好,请描述思想,写出算发(c语言),空间和时间复杂度,





#include string.h

main(void)

{ char *src="hello,world";

char *dest=NULL;

dest=(char *)malloc(strlen(src));

int len=strlen(str);

char *d=dest;

char *s=src[len];

while(len--!=0)

d++=s--;

printf("%s",dest);

}

找出错误!!

#include "string.h"

#include "stdio.h"

#include "malloc.h"

main(void)



char *src="hello,world";

char *dest=NULL;

dest=(char *)malloc(sizeof(char)*(strlen(src)+1));

int len=strlen(src);

char *d=dest;

char *s=src+len-1;

while(len--!=0)

*d++=*s--;

*d='/0';

printf("%s",dest);

}



1. 简述一个Linux驱动程序的主要流程与功能。



2. 请列举一个软件中时间换空间或者空间换时间的例子。

void swap(int a,int b)

{

int c; c=a;a=b;b=a;

}

--->空优 

void swap(int a,int b)

{

a=a+b;b=a-b;a=a-b;

}

6. 请问一下程序将输出什么结果?

char *RetMenory(void)

{

char p[] = “hellow world”;

return p;

}

void Test(void)

{

char *str = NULL;

str = RetMemory();

printf(str);

}

RetMenory执行完毕,p资源被回收,指向未知地址。返回地址,str的内容应是不可预测的, 打印的应该是str的地址





写一个函数,它的原形是int continumax(char *outputstr,char *intputstr)

功能:

在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中一个函数参数outputstr所指内存。例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回9,outputstr所指的值为123456789

int continumax(char *outputstr, char *inputstr)

{

char *in = inputstr, *out = outputstr, *temp, *final;

int count = 0, maxlen = 0;



while( *in != '/0' )

{

if( *in > 47 && *in < 58 )

{

for(temp = in; *in > 47 && *in < 58 ; in++ )

count++;

}

else

in++;



if( maxlen < count )

{

maxlen = count;

count = 0;

final = temp;

}

}

for(int i = 0; i < maxlen; i++)

{

*out = *final;

out++;

final++;

}

*out = '/0';

return maxlen;

}



不用库函数,用C语言实现将一整型数字转化为字符串

方法1:

int getlen(char *s){

int n;

for(n = 0; *s != '/0'; s++)

n++;

return n;

}

void reverse(char s[])

{

int c,i,j;

for(i = 0,j = getlen(s) - 1; i < j; i++,j--){

c = s[i];

s[i] = s[j];

s[j] = c;

}

}

void itoa(int n,char s[])

{

int i,sign;

if((sign = n) < 0)

n = -n;

i = 0;

do{/*以反序生成数字*/

s[i++] = n%10 + '0';/*get next number*/

}while((n /= 10) > 0);/*delete the number*/



if(sign < 0)

s[i++] = '-';



s[i] = '/0';

reverse(s);

}

方法2:

#include <iostream>

using namespace std;



void itochar(int num);



void itochar(int num)

{

int i = 0;

int j ;

char stra[10];

char strb[10];

while ( num )

{

stra[i++]=num%10+48;

num=num/10;

}

stra[i] = '/0';

for( j=0; j < i; j++)

{

strb[j] = stra[i-j-1];

}

strb[j] = '/0';

cout<<strb<<endl;



}

int main()

{

int num;

cin>>num;

itochar(num);

return 0;

}



前几天面试,有一题想不明白,请教大家!

typedef struct 



int a:2;

int b:2;

int c:1;

}test;



test t;

t.a = 1;

t.b = 3;

t.c = 1;



printf("%d",t.a);

printf("%d",t.b);

printf("%d",t.c);



谢谢!

t.a为01,输出就是1

t.b为11,输出就是-1

t.c为1,输出也是-1

3个都是有符号数int嘛。

这是位扩展问题 

01

11

1

编译器进行符号扩展





求组合数: 求n个数(1....n)中k个数的组合....

如:combination(5,3)

要求输出:543,542,541,532,531,521,432,431,421,321,

#include<stdio.h>



int pop(int *);

int push(int );

void combination(int ,int );



int stack[3]={0};

top=-1;



int main()

{

int n,m;

printf("Input two numbers:/n");

while( (2!=scanf("%d%*c%d",&n,&m)) )

{

fflush(stdin);

printf("Input error! Again:/n");

}

combination(n,m);

printf("/n");

}

void combination(int m,int n)

{

int temp=m;

push(temp);

while(1)

{

if(1==temp)

{

if(pop(&temp)&&stack[0]==n) //当栈底元素弹出&&为可能取的最小值,循环退出

break;

}

else if( push(--temp))

{

printf("%d%d%d ",stack[0],stack[1],stack[2]);//§&auml;¨ì¤@?

pop(&temp);

}

}

}

int push(int i)

{

stack[++top]=i;

if(top<2)

return 0;

else

return 1;

}

int pop(int *i)

{

*i=stack[top--];

if(top>=0)

return 0;

else

return 1;

}



1、用指针的方法,将字符串“ABCD1234efgh”前后对调显示

#include <stdio.h>

#include <string.h>

#include <dos.h>

int main()

{

char str[] = "ABCD1234efgh";

int length = strlen(str);

char * p1 = str;

char * p2 = str + length - 1;

while(p1 < p2)

{

char c = *p1;

*p1 = *p2;

*p2 = c;

++p1;

--p2;

}

printf("str now is %s/n",str);

system("pause");

return 0;

}

2、有一分数序列:1/2,1/4,1/6,1/8……,用函数调用的方法,求此数列前20项的和

#include <stdio.h>

double getValue()

{

double result = 0;

int i = 2;

while(i < 42)

{

result += 1.0 / i;//一定要使用1.0做除数,不能用1,否则结果将自动转化成整数,即0.000000

i += 2;

}

return result;

}

int main()

{

printf("result is %f/n", getValue());

system("pause");

return 0;

}

有一个数组a[1000]存放0--1000;要求每隔二个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。

以7个数为例:

{0,1,2,3,4,5,6,7} 0-->1-->2(删除)-->3-->4-->5(删除)-->6-->7-->0(删除),如此循环直到最后一个数被删除。

方法1:数组

#include <iostream>

using namespace std;

#define null 1000

int main()

{

int arr[1000];

for (int i=0;i<1000;++i)

arr[i]=i;

int j=0;

int count=0;

while(count<999)

{

while(arr[j%1000]==null)

j=(++j)%1000;

j=(++j)%1000;

while(arr[j%1000]==null)

j=(++j)%1000;

j=(++j)%1000;

while(arr[j%1000]==null)

j=(++j)%1000;

arr[j]=null;

++count;

}

while(arr[j]==null)

j=(++j)%1000;



cout<<j<<endl;

return 0;

}方法2:链表

#include<iostream>

using namespace std;

#define null 0

struct node

{

int data;

node* next;

};

int main()

{

node* head=new node;

head->data=0;

head->next=null;

node* p=head;

for(int i=1;i<1000;i++)

{

node* tmp=new node;

tmp->data=i;

tmp->next=null;

head->next=tmp;

head=head->next;

}

head->next=p;

while(p!=p->next)

{

p->next->next=p->next->next->next;

p=p->next->next;

}

cout<<p->data;

return 0;

}

方法3:通用算法

#include <stdio.h>

#define MAXLINE 1000 //元素个数

/*

MAXLINE 元素个数

a[] 元素数组

R[] 指针场

suffix 下标

index 返回最后的下标序号

values 返回最后的下标对应的值

start 从第几个开始

K 间隔

*/

int find_n(int a[],int R[],int K,int& index,int& values,int s=0) {

int suffix;

int front_node,current_node;

suffix=0;

if(s==0) {

current_node=0;

front_node=MAXLINE-1;

}

else {

current_node=s;

front_node=s-1;

}

while(R[front_node]!=front_node) {

printf("%d/n",a[current_node]);

R[front_node]=R[current_node];

if(K==1) {

current_node=R[front_node];

continue;

}

for(int i=0;i<K;i++){

front_node=R[front_node];

}

current_node=R[front_node];

}

index=front_node;

values=a[front_node];



return 0;

}

int main(void) {

int a[MAXLINE],R[MAXLINE],suffix,index,values,start,i,K;

suffix=index=values=start=0;

K=2;



for(i=0;i<MAXLINE;i++) {

a[i]=i;

R[i]=i+1;

}

R[i-1]=0;

find_n(a,R,K,index,values,2);

printf("the value is %d,%d/n",index,values);

return 0;

}



试题: 

void test2() 



char string[10], str1[10]; 

int i; 

for(i=0; i<10; i++) 



str1[i] = 'a'; 



strcpy( string, str1 ); 



解答:对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;

str1不能在数组内结束:因为str1的存储为:{a,a,a,a,a,a,a,a,a,a},没有'/0'(字符串结束符),所以不能结束

strcpy( char *s1,char *s2)他的工作原理是,扫描s2指向的内存,逐个字符付到s1所指向的内存,直到碰到'/0',因为str1结尾没有'/0',所以具有不确定性,不知道他后面还会付什么东东。

正确应如下

void test2() 



char string[10], str1[10]; 

int i; 

for(i=0; i<9; i++) 



str1[i] = 'a'+i; //把abcdefghi赋值给字符数组



str[i]='/0';//加上结束符

strcpy( string, str1 ); 

}



第二个code题是实现strcmp

int StrCmp(const char *str1, const char *str2)

做是做对了,没有抄搞,比较乱

int StrCmp(const char *str1, const char *str2)

{

assert(str1 && srt2);

while (*str1 && *str2 && *str1 == *str2) {

str1++, str2++;

}

if (*str1 && *str2)

return (*str1-*str2);

elseif (*str1 && *str2==0)

return 1;

elseif (*str1 = = 0 && *str2)

return -1;

else

return 0;

}



int StrCmp(const char *str1, const char *str2)

{

//省略判断空指针(自己保证)

while(*str1 && *str1++ = = *str2++);

return *str1-*str2; 

}

第三个code题是实现子串定位

int FindSubStr(const char *MainStr, const char *SubStr)

做是做对了,没有抄搞,比较乱

int MyStrstr(const char* MainStr, const char* SubStr)

{

const char *p;

const char *q;

const char * u = MainStr;



//assert((MainStr!=NULL)&&( SubStr!=NULL));//用断言对输入进行判断

while(*MainStr) //内部进行递增

{

p = MainStr;

q = SubStr;

while(*q && *p && *p++ == *q++);

if(!*q )

{

return MainStr - u +1 ;//MainStr指向当前起始位,u指向

}

MainStr ++;

}

return -1;

}



分析:

int arr[] = {6,7,8,9,10};

int *ptr = arr;

*(ptr++)+=123;

printf(“ %d %d ”, *ptr, *(++ptr));

输出:8 8

过程:对于*(ptr++)+=123;先做加法6+123,然后++,指针指向7;对于printf(“ %d %d ”, *ptr, *(++ptr));从后往前执行,指针先++,指向8,然后输出8,紧接着再输出8

/*雅虎笔试题(字符串操作)

给定字符串A和B,输出A和B中的最大公共子串。

比如A="aocdfe" B="pmcdfa" 则输出"cdf"

*/

//Author: azhen

#include<stdio.h>

#include<stdlib.h>

#include<string.h>



char *commanstring(char shortstring[], char longstring[])

{

int i, j;



char *substring=malloc(256);



if(strstr(longstring, shortstring)!=NULL) //如果……,那么返回shortstring

return shortstring; 



for(i=strlen(shortstring)-1;i>0; i--) //否则,开始循环计算

{

for(j=0; j<=strlen(shortstring)-i; j++){

memcpy(substring, &shortstring[j], i);

substring[i]='/0';

if(strstr(longstring, substring)!=NULL)

return substring;

}

}

return NULL;

}



main()

{

char *str1=malloc(256);

char *str2=malloc(256);

char *comman=NULL;

gets(str1);

gets(str2);



if(strlen(str1)>strlen(str2)) //将短的字符串放前面

comman=commanstring(str2, str1);

else

comman=commanstring(str1, str2);



printf("the longest comman string is: %s/n", comman);

}



11.写一个函数比较两个字符串str1和str2的大小,若相等返回0,若str1大于

str2返回1,若str1小于str2返回-1

int strcmp ( const char * src,const char * dst)

{

int ret = 0 ;

while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)

{

++src;

++dst;

}

if ( ret < 0 )

ret = -1 ;

else if ( ret > 0 )

ret = 1 ;

return( ret );

}

3,求1000!的未尾有几个0(用素数相乘的方法来做,如72=2*2*2*3*3);

求出1->1000里,能被5整除的数的个数n1,能被25整除的数的个数n2,能被125整除的数的个数n3,

能被625整除的数的个数n4.

1000!末尾的零的个数=n1+n2+n3+n4;

#include<stdio.h>

#define NUM 1000



int find5(int num){

int ret=0;

while(num%5==0){

num/=5;

ret++;

}

return ret;

}

int main(){

int result=0;

int i;

for(i=5;i<=NUM;i+=5)

{

result+=find5(i);

}

printf(" the total zero number is %d/n",result);

return 0;

}



1. 有双向循环链表结点定义为: 

struct node 

{ int data; 

struct node *front,*next; 

}; 

有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data值相同的结点删除 

BOOL DeteleNode(Node *pHeader, DataType Value)

{

if (pHeader == NULL) return;



BOOL bRet = FALSE;

Node *pNode = pHead;

while (pNode != NULL)

{

if (pNode->data == Value)

{

if (pNode->front == NULL)

{

pHeader = pNode->next;

pHeader->front = NULL;

}

else

{

if (pNode->next != NULL)

{

pNode->next->front = pNode->front;

}

pNode->front->next = pNode->next;

}



Node *pNextNode = pNode->next;

delete pNode;

pNode = pNextNode;



bRet = TRUE; 

//不要break或return, 删除所有

}

else

{

pNode = pNode->next;

}

}



return bRet;

}



void DE(Node *pHeadA, Node *pHeadB)

{

if (pHeadA == NULL || pHeadB == NULL)

{

return;

}



Node *pNode = pHeadA;

while (pNode != NULL)

{

if (DeteleNode(pHeadB, pNode->data))

{

if (pNode->front == NULL)

{

pHeadA = pNode->next;

pHeadA->front = NULL;

}

else

{

pNode->front->next = pNode->next;

if (pNode->next != NULL)

{

pNode->next->front = pNode->front;

}

}

Node *pNextNode = pNode->next;

delete pNode;

pNode = pNextNode;

}

else

{

pNode = pNode->next;

}

}

}

2. 编程实现:找出两个字符串中最大公共子字符串,如"abccade","dgcadde"的最大子串为"cad" 

int GetCommon(char *s1, char *s2, char **r1, char **r2)

{

int len1 = strlen(s1);

int len2 = strlen(s2);

int maxlen = 0;



for(int i = 0; i < len1; i++)

{

   for(int j = 0; j < len2; j++)

   {

      if(s1[i] == s2[j])

      {

        int as = i, bs = j, count = 1;

        while(as + 1 < len1 && bs + 1 < len2 && s1[++as] == s2[++bs])

            count++;



        if(count > maxlen)

        {

           maxlen = count;

           *r1 = s1 + i;

           *r2 = s2 + j;

        }

      }

   }

}

3. 编程实现:把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列库函数

char* test3(long num) {

char* buffer = (char*)malloc(11);

buffer[0] = '0';

buffer[1] = 'x';

buffer[10] = '/0';



char* temp = buffer + 2;

for (int i=0; i < 8; i++) {

temp[i] = (char)(num<<4*i>>28);

temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;

temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;

}

return buffer;

}



斐波拉契数列递归实现的方法如下:

int Funct( int n )

{

if(n==0) return 1;

if(n==1) return 1;

retrurn Funct(n-1) + Funct(n-2);

}

请问,如何不使用递归,来实现上述函数?

请教各位高手!

解答:int Funct( int n ) // n 为非负整数

{

int a=0;

int b=1;

int c;

if(n==0) c=1;

else if(n==1) c=1;

else for(int i=2;i<=n;i++) //应该n从2开始算起

{

c=a+b;

a=b;

b=c;

}

return c;

}

解答:

现在大多数系统都是将低字位放在前面,而结构体中位域的申明一般是先声明高位。

100 的二进制是 001 100 100

低位在前 高位在后 

001----s3

100----s2

100----s1

所以结果应该是 1

如果先申明的在低位则:

001----s1

100----s2

100----s3

结果是 4

1、原题跟little-endian,big-endian没有关系

、原题跟位域的存储空间分配有关,到底是从低字节分配还是从高字节分配,从Dev C++和VC7.1上看,都是从低字节开始分配,并且连续分配,中间不空,不像谭的书那样会留空位

、原题跟编译器有关,编译器在未用堆栈空间的默认值分配上有所不同,Dev C++未用空间分配为

01110111b,VC7.1下为11001100b,所以在Dev C++下的结果为5,在VC7.1下为1。



注:PC一般采用little-endian,即高高低低,但在网络传输上,一般采用big-endian,即高低低高,华为是做网络的,所以可能考虑big-endian模式,这样输出结果可能为4



判断一个字符串是不是回文

int IsReverseStr(char *aStr)

{

int i,j;

int found=1;

if(aStr==NULL)

return -1;

j=strlen(aStr);

for(i=0;i<j/2;i++)

if(*(aStr+i)!=*(aStr+j-i-1))

{

found=0;

break;

}

return found;

}

Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

数组实现:

#include <stdio.h>

#include <malloc.h>

int Josephu(int n, int m)

{ int flag, i, j = 0;

  int *arr = (int *)malloc(n * sizeof(int));

  for (i = 0; i < n; ++i)

  arr[i] = 1;

  for (i = 1; i < n; ++i)

  { flag = 0;

    while (flag < m)

    {  if (j == n)

       j = 0;

       if (arr[j])

       ++flag;

       ++j;

    }

  arr[j - 1] = 0;

  printf("第%4d个出局的人是:%4d号/n", i, j);

 }

 free(arr);

 return j;

}

int main()

{ int n, m;

  scanf("%d%d", &n, &m);

  printf("最后胜利的是%d号!/n", Josephu(n, m));

  system("pause");

  return 0;

}

链表实现:

#include <stdio.h>

#include <malloc.h>

typedef struct Node

{ int index;

  struct Node *next;

}JosephuNode;

int Josephu(int n, int m)

{ int i, j;

  JosephuNode *head, *tail;

  head = tail = (JosephuNode *)malloc(sizeof(JosephuNode));

  for (i = 1; i < n; ++i)

  { tail->index = i;

    tail->next = (JosephuNode *)malloc(sizeof(JosephuNode));

    tail = tail->next;

  }

  tail->index = i;

  tail->next = head;

  for (i = 1; tail != head; ++i)

  { for (j = 1; j < m; ++j)

   {

    tail = head;

    head = head->next;

   }

  tail->next = head->next;

  printf("第%4d个出局的人是:%4d号/n", i, head->index);

  free(head);

  head = tail->next;

 }

  i = head->index;

  free(head);

  return i;

}

int main()

{ int n, m;

  scanf("%d%d", &n, &m);

  printf("最后胜利的是%d号!/n", Josephu(n, m));

  system("pause");

  return 0;

}



已知strcpy函数的原型是:

char * strcpy(char * strDest,const char * strSrc);

1.不调用库函数,实现strcpy函数。

2.解释为什么要返回char *。

解说:

1.strcpy的实现代码

char * strcpy(char * strDest,const char * strSrc)

{

if ((strDest==NULL)||(strSrc==NULL)) file://[/1]

throw "Invalid argument(s)"; //[2]

char * strDestCopy=strDest; file://[/3]

while ((*strDest++=*strSrc++)!='/0'); file://[/4]

return strDestCopy;

}

错误的做法:

[1]

(A)不检查指针的有效性,说明答题者不注重代码的健壮性。

(B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。

(C)检查指针的有效性时使用((strDest==0)||(strSrc==0)),说明答题者不知道使用常量的好处。直接使用字面常量(如本例中的0)会减少程序的可维护性。0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误,编译器不能发现,生成的程序内含逻辑错误,很难排除。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。

[2]

(A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。

(B)return 0;,说明答题者没有掌握异常机制。调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。

[3] 

(A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。

[4]

(A)循环写成while (*strDest++=*strSrc++);,同[1](B)。

(B)循环写成while (*strSrc!='/0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'/0'。

为什么说用PHP开发大型系统令人不爽

笔者在过去的四年里一直致力于PHP应用的开发。PHP确实十分容易编写。但是PHP也有一些十分严重的缺陷。

  下面笔者会给出自己的理由,为什么PHP不适合于比小型业余网站更大的网站。

1. 对递归的不良支持

  递归是一种函数调用自身的机制。这是一种强大的特性可以把某些复杂的东西变得很简单。有一个使用递归的例子是快速排序(quicksort)。不幸的是,PHP并不擅长递归。Zeev,一个PHP开发人员,说道:“PHP 4.0(Zend)对密集数据使用了栈方式,而不是使用堆方式。也就是说它能容忍的递归函数的数量限制和其他语言比起来明显少。”见bug 1901。这是一个很不好的借口。每一个编程语言都应该提供良好的递归支持。

2. 许多PHP模块都不是线程安全的

  在几年前,Apache发布了Web服务器的2.0版。这个版本支持多线程模式,在这个模式下,软件一个一部分可以同时运行多个。PHP的发明者说PHP的核心是线程安全的,但是非核心模块不一定是。但是十次有九次,你想要在PHP脚本中使用这种模块,但这又使你的脚本不能合适Apache的多线程模式。这也是为什么PHP小组不推荐在Apache 2 的多线程模式下运行PHP。不良的多线程模式支持使PHP常被认为是Apache 2依然不流行的原因之一。

  请阅读这篇讨论: Slashdot: Sites Rejecting Apache 2?.

3. PHP 由于商业原因而不健全

  通过使用缓存,PHP的性能可以陡增500%[见基准测试]。那么为什么缓存没有被构建在PHP中呢?因为Zend——PHP的制造者,它在销售自己的Zend Accelerator,所以当然,他们不想抛弃自己的商业产品这块肥肉。

  但是有另一个可选择的: APC. (Zend后来推出Zend Optimizer,免费的加速器——译者)

4. 没有命名空间

  设想某个人制作了一个PHP模块用来阅读文件。模块中一个函数叫做read。然后另一个人的模块可以读取网页的,同样包含一个函数read。然后我们就无法同时使用这两个模块了,因为PHP不知道你要用哪个函数。

  但是有一个很简单的解决方法,那就是命名空间。曾经有人建议PHP5加入这个特性,但不幸得是他没有这么做。现在,没有命名空间,每个函数都必须加上模块名作为前缀,来避免名称冲突。这导致了函数名恐怖得长,例如xsl_xsltprocessor_transform_to_xml让代码难于书写和理解。

5. 不标准的日期格式字符

  很多程序员对 日期格式字符 都很熟悉,它是从UNIX和C语言中来的。其他一些编程语言采用了这个标准,但是很奇怪的,PHP有它自己的一套完全不兼容的日期格式字符。在C中,“%j”表示一年中的当天,在PHP中他表示一个月中的当天。然而使事情更混乱的是:Smarty (一个很流行的PHP模版引擎)的 strftime 函数和 date_format 函数,却使用了C/UNIX的格式化字符。

6. 混乱的许可证

  你也许认为PHP是免费的,所有的在手册中提到的PHP模块也是免费的。错了!例如,如果你想在PHP中生成PDF文件,你会在手册中发现两个模块:PDF 和 ClibPDF。但是这两个都是有商业许可证的。所以,你所使用的每个模块,你都要确保你同意他的许可证。

7. 不一致的函数命名规则

  有些函数名称是有多个单词组成的。一般有三种单词组合的习惯:

  直接拼接:getnumberoffiles

  用下划线分开:get_number_of_files

  骆驼法则:getNumberOfFiles

  大部分语言选择其中一中。但是PHP都用到了。

  例如,你想要把一些特殊字符转换成HTML实体,你会使用函数htmlentities(直接拼接单词)。如果你要使用相反的功能,你要用到它的小弟弟html_entity_decode。由于某些特殊的原因,这个函数名是由下划线分隔单词。怎么能这样呢?你知道有一个函数叫strpad。或者他是str_pad?每次你都要查看一下到底这个符号是什么或者直接等他出现一个错误。函数是不分大小写的,所以对于PHP来说rawurldecode和RawUrlDecode之间没有什么区别。这也很糟糕,因为两个都使用到了同时他们看上去还不一样,混淆了阅读者。

8. 魔法引用的地狱

  魔法引用(Magic quote)可以保护PHP脚本免受SQL注入攻击。这很好。但是出于某些原因,你可以在php.ini中关闭这个配置。所以你如果要写出一个有弹性的脚本,你总要检查魔法引用是开启还是关闭。这样一个“特性”应该让编程更简单,而事实上变得更复杂了。

9. 缺少标准框架

  一个成长中的网站没有一个整体框架,最终会变成维护的噩梦。一个框架可以让很多工作变得简单。现在最流行的框架模型时MVC-模型,在其中表现层、业务逻辑和数据库访问都分离开了。

  很多PHP网站不使用MVC-模型。他们甚至没有一个框架。甚至现在有一些PHP框架同时你都可以自己写一个,关于PHP的文章和手册没有提高框架的一个字。同时JSP-开发人员使用像Struts的框架、ASP开发人员使用.Net,看起来好像这些概念都广泛被PHP开发人员所了解。这就说明了PHP实际上到底是多专业。

  总结

  什么问题?

  对于非常小的项目,它可以是一个十分符合人意的编程语言。但是对于较大的和更为复杂的项目,PHP就显出他的薄弱了。当你不断地摸索之后,你会发现笔者提到的某些问题的解决方案。所以,当解决方案已知之后,为什么不能修正他呢?另外为什么这些修补不在手册中提到呢?

  一个开源的语言十分流行是一件好事。但不幸得是,它不是一个伟大的语言。笔者希望所有的问题能有一天得到解决(也许在PHP6?),然后我们就将拥有一个开源语言,他既开源,又好用。

  到现在,当你要启动一个多于5个脚本页面的项目的时候,你最好考虑C#/ASP.Net 或者 Java/JSP或者也许Python同样是一个更好的选择。

C语言最长平台算法

已知一个已经从小到大排列好的数组,说这个数组中的一个平台(Plateau),就是连续的一串相同的元素,并且这一串元素不能再延伸.例如,在1,2,2,3,3,3,4,5,5,6中1,2.2,3.3.3,4,5.5,6都是平台.编写程序把这个数组中最长的平台找出来.

#include <stdio.h>

int longest_plateau(int x[],int n)

{

int length=1;

int i;

for(i=1;i<n;i++)

{

if(x[i]==x[i-length])

length++;

}

return length;

}

void main()

{

int a[]={1,2,2,3,3,3,4,5,5,6};

int tmp;

tmp=longest_plateau(a,9);

printf("%d/n",tmp);

}

本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵。文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见。



  许多面试题看似简单,却需要深厚的基本功才能给出完美的解答。企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分。读者可从本文看到strcpy 函数从2分到10分解答的例子,看看自己属于什么样的层次。此外,还有一些面试题考查面试者敏捷的思维能力。 

分析这些面试题,本身包含很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。



2.找错题

  试题1:

void test1()

{ char string[10];

 char* str1 = "0123456789";

 strcpy( string, str1 );

}

 试题1字符串str1需要11个字节才能存放下(包括末尾的’’),而string只有10个字节的空间,strcpy会导致数组越界;



试题2:

void test2()

{

 char string[10], str1[10];

 int i;

 for(i=0; i<10; i++)

 {

  str1[i] = 'a';

 }

 strcpy( string, str1 );

}

 对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10 分;

  试题3:

void test3(char* str1)

{

 char string[10];

 if( strlen( str1 ) <= 10 )

 {

  strcpy( string, str1 );

 }

}

对试题3,if(strlen(str1) <= 10)应改为if(strlen(str1) < 10),因为strlen的结果未统计’’所占用的1个字节。  

  剖析:

  考查对基本功的掌握:(1)字符串以’’结尾;(2)对数组越界把握的敏感度;

(3)库函数strcpy的工作方式,如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案:  

char * strcpy( char *strDest, const char *strSrc ) 

{

 assert( (strDest != NULL) && (strSrc != NULL) );

 char *address = strDest; 

 while( (*strDest++ = * strSrc++) != ‘’ ); 

  return address;

}

  从2分到10分的几个答案我们可以清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功才能写一个完美的strcpy啊!



(4)对strlen的掌握,它没有包括字符串末尾的''。

  读者看了不同分值的strcpy版本,应该也可以写出一个10分的strlen函数了,完美的版本为: int strlen( const char *str ) //输入参数const

{

 assert( strt != NULL ); //断言字符串地址非0

 int len;

 while( (*str++) != '' ) 

 { 

  len++; 

 } 

 return len;

}

  试题4:

void GetMemory( char *p )

{

 p = (char *) malloc( 100 );

}

void Test( void ) 

{

 char *str = NULL;

 GetMemory( str ); //!!!

strcpy( str, "hello world" );

 printf( str );

}

试题4传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完

char *str = NULL;

GetMemory( str );后的str仍然为NULL;



试题5:

char *GetMemory( void )



 char p[] = "hello world"; 

 return p; 

}



void Test( void )



 char *str = NULL; 

 str = GetMemory(); 

 printf( str ); 

}

试题5中

char p[] = "hello world"; 

return p;的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。

试题6:

void GetMemory( char **p, int num )

{

 *p = (char *) malloc( num );

}

void Test( void )

{

 char *str = NULL;

 GetMemory( &str, 100 );

 strcpy( str, "hello" ); 

 printf( str ); 

}

试题6的GetMemory避免了试题4的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句*p = (char *) malloc( num );后未判断内存是否申请成功,应加上:

if ( *p == NULL )

{

 ...//进行申请内存失败处理

}

试题6的Test函数中也未对malloc的内存进行释放。



试题7:

void Test( void )

{

 char *str = (char *) malloc( 100 );

 strcpy( str, "hello" );

 free( str ); 

 ... //省略的其它语句

}

试题7存在与试题6同样的问题,在执行char *str = (char *) malloc(100);后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:str = NULL;

剖析:

试题4~7考查面试者对内存操作的理解程度,基本功扎实的面试者一般都能正确的回答其中50~60的错误。但是要完全解答正确,却也绝非易事。

对内存操作的考查主要集中在:(1)指针的理解;(2)变量的生存期及作用范围;(3)良好的动态内存申请和释放习惯。



再看看下面的一段程序有什么错误:

swap( int* p1,int* p2 )

{

 int *p;

 *p = *p1;

 *p1 = *p2;

 *p2 = *p;

}

在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在VC++中DEBUG运行时提示错误“Access Violation”。该程序应该改为:

swap( int* p1,int* p2 )

{

 int p;

 p = *p1;

 *p1 = *p2;

 *p2 = p;

}

3.内功题

  试题1:分别给出BOOL,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)

  解答:

BOOL型变量:if(!var)

  int型变量: if(var==0)

  float型变量:  const float EPSINON = 0.00001;

                 if ((x >= - EPSINON) && (x <= EPSINON)

  指针变量:  if(var==NULL)



  剖析:

  考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。 

  一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断;如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯。

  浮点型变量并不精确,所以不可将float变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。如果写成if (x == 0.0),则判为错,得0分。

试题2:以下为Windows NT下的32位C++程序,请计算sizeof的值

void Func ( char str[100] )

{

 sizeof( str ) = ?

}

void *p = malloc( 100 );

sizeof ( p ) = ?

解答:

sizeof( str ) = 4

sizeof ( p ) = 4

剖析:

Func ( char str[100] )函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

数组名的本质如下:

(1)数组名指代一种数据结构,这种数据结构就是数组;

  例如:char str[10];

          cout << sizeof(str) << endl;

输出结果为10,str指代数据结构char[10]。

(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;

char str[10];

str++; //编译出错,提示str不是左值 

(3)数组名作为函数形参时,沦为普通指针。

Windows NT 32位平台下,指针的长度(占用内存的大小)为4字节,故sizeof( str ) 、sizeof ( p ) 都为4。

试题3:写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?least = MIN(*p++, b);

解答:

#define MIN(A,B) ((A) <= (B) ? (A) : (B))

MIN(*p++, b)会产生宏的副作用

 剖析:

  这个面试题主要考查面试者对宏定义的使用,宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对“参数”进行的是一对一的替换。

程序员对宏定义的使用要非常小心,特别要注意两个问题:

(1)谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。所以,严格地讲,下述解答:

#define MIN(A,B) (A) <= (B) ? (A) : (B)

#define MIN(A,B) (A <= B ? A : B )

都应判0分;

(2)防止宏的副作用。

宏定义#define MIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:

((*p++) <= (b) ? (*p++) : (*p++))

这个表达式会产生副作用,指针p会作三次++自增操作。

除此之外,另一个应该判0分的解答是:

#define MIN(A,B) ((A) <= (B) ? (A) : (B));

这个解答在宏定义的后面加“;”,显示编写者对宏的概念模糊不清,只能被无情地判0分并被面试官淘汰。

试题4:为什么标准头文件都有类似以下的结构?

#ifndef __INCvxWorksh

#define __INCvxWorksh 

#ifdef __cplusplus



extern "C" {

#endif 

/*...*/ 

#ifdef __cplusplus

}



#endif 

#endif /* __INCvxWorksh */

解答:头文件中的编译宏

#ifndef __INCvxWorksh

#define __INCvxWorksh

#endif的作用是防止被重复引用。

  作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在symbol库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo(int x, int y);

该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。

    为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern "C"来解决名字匹配问题,函数声明前加上extern "C"后,则编译器就会按照C语言的方式将该函数编译为_foo,这样C语言中就可以调用C++的函数了。

 试题5:编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh” 

 函数头是这样的:

//pStr是指向以''结尾的字符串的指针

//steps是要求移动的n



void LoopMove ( char * pStr, int steps )

{

 //请填充...

}

解答:

正确解答1:

void LoopMove ( char *pStr, int steps )

{

 int n = strlen( pStr ) - steps;

 char tmp[MAX_LEN]; 

 strcpy ( tmp, pStr + n );  //将要移动的部分放入tmp的前部

strcpy ( tmp + steps, pStr);  //将原字符串放入tmp的后部

*( tmp + strlen ( pStr ) ) = '';  //保持tmp和原字符串长度一致

strcpy( pStr, tmp );

}

正确解答2:

void LoopMove ( char *pStr, int steps )

{

 int n = strlen( pStr ) - steps;

 char tmp[MAX_LEN]; 

 memcpy( tmp, pStr + n, steps ); 

 memcpy(pStr + steps, pStr, n ); 

 memcpy(pStr, tmp, steps ); 

}

剖析:

这个试题主要考查面试者对标准库函数的熟练程度,在需要的时候引用库函数可以很大程度上简化程序编写的工作量。最频繁被使用的库函数包括:

  (1) strcpy(2) memcpy(3) memset

试题6:已知WAV文件格式如下表,打开一个WAV文件,以适当的数据结构组织WAV文件头并解析WAV格式的各项信息。

WAVE文件格式说明表

偏移地址

字节数

数据类型

内 容

文件头

00H

Char

"RIFF"标志

04H

int32

文件长度

08H

Char

"WAVE"标志

0CH

Char

"fmt"标志

10H

过渡字节(不定)

14H

int16

格式类别

16H

int16

通道数

18H

int16

采样率(每秒样本数),表示每个通道的播放速度

1CH

int32

波形音频数据传送速率

20H

int16

数据块的调整数(按字节算的)

22H

每样本的数据位数

24H

Char

数据标记符"data"

28H

int32

语音数据的长度

  解答:

  将WAV文件格式定义为结构体WAVEFORMAT:

typedef struct tagWaveFormat



 char cRiffFlag[4]; 

 UIN32 nFileLen; 

 char cWaveFlag[4]; 

 char cFmtFlag[4]; 

 char cTransition[4]; 

 UIN16 nFormatTag ; 

 UIN16 nChannels; 

 UIN16 nSamplesPerSec; 

 UIN32 nAvgBytesperSec; 

 UIN16 nBlockAlign; 

 UIN16 nBitNumPerSample; 

 char cDataFlag[4]; 

 UIN16 nAudioLength; 



} WAVEFORMAT; 

假设WAV文件内容读出后存放在指针buffer开始的内存单元内,则分析文件格式的代码很简单,为:

WAVEFORMAT waveFormat;

memcpy( &waveFormat, buffer,sizeof( WAVEFORMAT ) );

直接通过访问waveFormat的成员,就可以获得特定WAV文件的各项格式信息。

  剖析:

试题6考查面试者组织数据结构的能力,有经验的程序设计者将属于一个整体的数据成员组织为一个结构体,利用指针类型转换,可以将memcpy、memset等函数直接用于结构体地址,进行结构体的整体操作。 透过这个题可以看出面试者的程序设计经验是否丰富。

试题7:编写类String的构造函数、析构函数和赋值函数,已知类String的原型为:

class String



 public: 

  String(const char *str = NULL); // 普通构造函数 

String(const String &other); // 拷贝构造函数 

~ String(void); // 析构函数 

String & operate =(const String &other); // 赋值函数 

private: 

  char *m_data; // 用于保存字符串 

};

解答:

//普通构造函数

String::String(const char *str) 

{ if(str==NULL)          //加分点:对m_data加NULL 判断

{

  m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志''的空                     

  *m_data = ''; 

 } 

 else

 { int length = strlen(str); 

  m_data = new char[length+1]; // 若能加 NULL 判断则更好 

strcpy(m_data, str); 

 }

}

// String的析构函数

String::~String(void) 

{  delete [] m_data; // 或delete m_data; }



//拷贝构造函数

String::String(const String &other) // 得分点:输入参数为const型

{ int length = strlen(other.m_data); 

m_data = new char[length+1];     //加分点:对m_data加NULL 判断

strcpy(m_data, other.m_data); 

}

//赋值函数

String & String::operate =(const String &other) // 得分点:输入参数为const型

{  if(this == &other) //得分点:检查自赋值

  return *this; 

 delete [] m_data;     //得分点:释放原有的内存资源

int length = strlen( other.m_data ); 

 m_data = new char[length+1];  //加分点:对m_data加NULL 判断

strcpy( m_data, other.m_data ); 

 return *this;         //得分点:返回本对象的引用

}

  剖析:

  能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上!

  在这个类中包括了指针类成员变量m_data,当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数,这既是对C++程序员的基本要求,也是《Effective C++》中特别强调的条款。

  仔细学习这个类,特别注意加注释的得分点和加分点的意义,这样就具备了60%以上的C++基本功!



 试题8:请说出static和const关键字尽可能多的作用

 解答:

static关键字至少有下列n个作用:

  (1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;

  (2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

  (3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

  (4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝; 

  (5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。 

const关键字至少有下列n个作用:

  (1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

  (2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;

 (3)在一个函数声明中const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

 (4)对于类的成员函数,若指定其为const类型则表明其是一个常函数,不能修改类的成员变量;

 (5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。  例如:const classA operator*(const classA& a1,const classA& a2);

operator*的返回结果必须是一个const对象。如果不是,这样的变态代码也不会编译出错:

classA a, b, c;

(a * b) = c; // 对a*b的结果赋值

操作(a * b) = c显然不符合编程者的初衷,也没有任何意义。

  剖析:

  惊讶吗?小小的static和const居然有这么多功能,我们能回答几个?如果只能回答1~2个,那还真得闭关再好好修炼修炼。

  这个题可以考查面试者对程序设计知识的掌握程度是初级、中级还是比较深入,没有一定的知识广度和深度,不可能对这个问题给出全面的解答。大多数人只能回答出static和const关键字的部分功能。



  4.技巧题

试题1:请写一个C函数,若处理器是Big_endian的则返回0;若是Little_endian的则返回1

  解答:

int checkCPU()

{

 {  union w

  { int a;

   char b;} c;

    c.a = 1;

   return (c.b == 1);

 }

}

剖析:

  嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,16bit宽的数0x1234在Little- endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

存放内容

0x4000

0x34

0x4001

0x12

  而在Big-endian模式CPU内存中的存放方式则为:

内存地址

存放内容

0x4000

0x12

0x4001

0x34

32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

存放内容

0x4000

0x78

0x4001

0x56

0x4002

0x34

0x4003

0x12

  而在Big-endian模式CPU内存中的存放方式则为:

内存地址

存放内容

0x4000

0x12

0x4001

0x34

0x4002

0x56

0x4003

0x78

  联合体union的存放顺序是所有成员都从低地址开始存放,面试者的解答利用该特性,轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。如果谁能当场给出这个解答,那简直就是一个天才的程序员。



试题2:写一个函数返回1+2+3+…+n的值(假定结果不会超过长整型变量的范围) 

  解答:

int Sum( int n )

{ return ( (long)1 + n) * n / 2;  //或return (1l + n) * n / 2;}

  剖析:

  对于这个题,只能说,也许最简单的答案就是最好的答案。下面的解答,或者基于下面的解答思路去优化,不管怎么“折腾”,其效率也不可能与直接return ( 1 l + n ) * n / 2相比!

int Sum( int n )

{ long sum = 0;

 for( int i=1; i<=n; i++ )

 {sum += i;}

 return sum;

} 所以程序员们需要敏感地将数学等知识用在程序设计中。

1.C与C++的异同,优劣;

.C,C++,VC,BC,TC的区别;

.C++中try…catch关键字的用法与优点;

.枚举的用法,以及它与宏的区别;

.const的用法,以及声明const变量与宏的区别;

   const的用法有四种:1. const常量,如const int max = 100;2. const 修饰类的数据成员;3. const修饰指针的情况;4. 在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。

 区别:1.const常量有数据类型, 而宏常量没有数据类型;2.编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有类型安全检查,而且字符替换可能会带来料想不到的边界效应;3. 有些集成化工具可以对const常量进行调试, 但不能对宏量进行调试。

.C++中引用与指针的区别;

 答:1 引用实际上是所引用的对象或变量的别名,而指针是包含所指向对象或变量的地址的变量。

 2 引用在定义时必须初始化,而指针在定义时不初始化。

 3 不可以有努NULL的引用,而可以有指向NULL的指针。

 4 引用在初始化后不可以改变引用关系,而指针可以随时指向其他对象(非const指针)。

.C++中virtual与inline的含义分别是什么?

 答:在基类成员函数的声明前加上virtual关键字,意味着将该成员函数声明为虚函数。

 inline与函数的定义体放在一起,使该函数称为内联。inline是一种用于实现的关键字,而不是用于声明的关键字。

虚函数的特点;如果希望派生类能够重新定义基类的方法,则在基类中将该方法定义为虚方法,这样可以启用动态联编。

内联函数的特点;使用内联函数的目的是为了提高函数的运行效率。内联函数体的代码不能过长,因为内联函数省去调用函数的时间是以代码膨胀为代价的。内联函数不能包含循环语句,因为执行循环语句要比调用函数的开销大。

一个函数能否即是虚函数又是内联函数?可以,建议不使用?

.以下关键字的含义与用法:

extern,extern “C”,static,explicit,register,#undef,#ifndef

9.什么是函数重载与覆盖?

为什么C不支持函数重载?

为什么C++能支持函数重载?

10.VC中,编译工具条内的Debug与Release选项是什么含义?

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。Debug带有大量的调试代码,运行时需要相应的运行库,发布模式程序紧凑不含有调试代码和信息,直接可以运行(如果不需要运行库)

11.编写my_memcpy函数,实现与库函数memcpy类似的功能,不能使用任何库函数;

 void* mymemcpy(void* pvTo, const char* pvFrom, size_t size)

 { assert((dest != NULL) && (src != NULL));

   byte* psTo = (byte*)pvTo;

   byte* psFrom = (byte*)pvFrom;

   while (size-- > 0) 

   {*psTo++ = *psFrom++;}

   return pvTo;

 }

12.编写my_strcpy函数,实现与库函数strcpy类似的功能,不能使用任何库函数;

 答:char* my_strcpy(char* strdest, const char* strsrc)

 { assert((strdest != NULL) && (strsrc != NULL))

   char* address = strdest;

   while((*strdest++ = *strsrc++) != NULL)

   return address;

 }

13.编写gbk_strlen函数,计算含有汉字的字符串的长度,汉字作为一个字符处理;

已知:汉字编码为双字节,其中首字节<0,尾字节在0~63以外;(如果一个字节是-128~127)

14.函数assert的用法?

答:断言assert是仅在debug版本起作用的宏,用于检查“不应该“发生的情况。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。

15.为什么在头文件的最前面都会看到这样的代码:

#ifndef _STDIO_H_

#define _STDIO_H_

头文件中的#ifndef一般格式是这样的#ifndef <标识> ,#define <标识>;<标识>在理论上来说可以是*命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h

#ifndef _STDIO_H_ 

#define _STDIO_H_

16.为什么数组名作为参数,会改变数组的内容,而其它类型如int却不会改变变量的值?

答:当数组名作为参数时,传递的实际上是地址。而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调函数内部对形参的改变并不影响实参的值。

1.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。

2.写一个函数,将其中的/t都转换成4个空格。

3.Windows程序的入口是哪里?写出Windows消息机制的流程。

4.如何定义和实现一个类的成员函数为回调函数?

5.C++里面是不是所有的动作都是main()引起的?如果不是,请举例。

6.C++里面如何声明const void f(void)函数为C程序中的库函数?

7.下列哪两个是等同的

int b;

  A const int* a = &b;

  B const* int a = &b;

  C const int* const a = &b;

  D int const* const a = &b;

  8.内联函数在编译时是否做参数类型检查?

void g(base & b){

   b.play;

  }

  void main(){

   son s;

   g(s);

   return;

  }

3、WinMain

 while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)

 { 

 if (bRet == -1)

 {

 // handle the error and possibly exit

 }

 else

 {

 TranslateMessage(&msg); 

 DispatchMessage(&msg); 

 }

 }

华为3COM

选择、填空、简答、程序都有。基本上是C和网络方面的DD,还有几道概率和推理

道选择,大多数是C的,50分,然后两题填空,20分,第二题不是编程,是个数学题。第三部分写两个函数,3 0分,第一题是把一个unsigned long的数转成一个IP地址输出,应该很容易的,结果自己想复杂了,浪费了不少时间,最后还没做对,晕。第二题是两个长度为N的数字字符串相加,结果保存在一个长度为N+1的字符串里,思路倒是很清楚,后来发现好像在处理进位和前一位的和的时候还有进位的问题,但是懒得改了,就这样吧。最后一部分是附加题,10题选择,20分,内容主要是和IP网络有关的,笔试中有英译汉。请翻译一下ipv6的路由发现机制。是将arp和irdp和icmp重定向的融合等等。

1 H.323协商。(笔试题) 

2 ipsec为什么是三层的。l2tp为什么是二层的? 

答:ipsec是需要三层IP路由的。l2tp是打穿的。 

反问:那l2tp不需要ip吗? 

无语。 

3 ospf中包的ttl值是多少?(回忆不清了。可能是吧。但没听说过有介绍啊。) 

4 为什么要划分区域? 

答:用来防止LSA在整个区域内泛洪。减少对CPU和内存的损耗。 

反问:那area 0的一条路由条目发生了变化。area 1要不要知道呢? 

答:要。 

反问:既然要的话,那不还是要泛洪吗?那划分区域的话就没有什么意义了嘛。 

答:可以通过缺省路由的方式或建立stub区域等方法。 

反问:正面回答。 

无语。 

5 MPLS VPN的标签一共有几层。内网的标签放在哪里。 

答:骨干里传递一层。到Mp-ibgp邻居一层。跨域一层。好象TE还可以加一层标签。内网的标签放在lfib表里。 

对方没怎么做声。但估计答得不好。 

(我有一点不明,MPLS标签有分内网和外网吗?) 

6 MPLS中RD和RT的作用分别是什么? 

答:RD的作用是允许VPN用户地址的重叠。RT可以用来区分不同的VPN用户。控制路由条目的出口入口策略。 

反问:既然RT可以区分不同的VPN用户。那RD有什么用。地址重叠那是你的规划没做好。 

答:RD是肯定要的。 

反问:为什么?不是有RT可以区分用户吗? 

无语。 

7 RR防止环路的机制。 

答:两个属性originate id。包含了始发这条路由的路由器的route-id,因此RR不会将此路由又重新发回给源。 

一个是cluster-id。包含了RR的route-id。 

8 BGP控制out-bound用local-pre,控制进来的用med.(笔试题) 

9 ospf是工作在哪个协议上的?(可能是我记不清了?) 

10 ospf的LSA类型。 

答:(这个我不打字了。大家应该都知道吧。) 

11 简述OSPF的基本工作机制。 

答:(昨晚补了下卷一)一。向邻接路由器发出hello包。根据hello包中携带的area id ,hello time,dead interval,stub标记。如果都相同的话。建立起邻居关系。 

二 向邻居发送链路状态更新包. (根据ospf 类型而定。如果是broadcast和nbma的话,由DR发出)三 收到邻居路由器发来的更新包后,以自己为根,根据 

spf算法建立一条无环路的路径。四在整个区域内泛洪。五整个区域内的database同步。六数据库稳定后,hello包变为keepalive报文,30min发送一次。 

(回答肯定不是很好。请高手指正) 

12 ppp的lcp和ncp协商过程。 

答:(说得不好。基本无语) 

13 笔试中还有一道PSTN的信令控制有哪三种?(笔试题) 

14sloari 8.0查看进程的命令是什么?linux 7.3查看IP的命令是什么?(笔试题) 

15 IP是5.32.0.0,掩码255.224.0.0。请问最大的有效地址是多少。(笔试题) 

16 下列哪一项不属于于7号信令标准?(选择。我乱蒙了一个) 

17 lx/???的有效距离是多少?我选的10km 

18 IP 包头几个字节?加上数据部分几个字节19 QOS有一点点。 

随便蒙吧,反正这方面对方问得不是很细。把你知道的说出来就可以了。 

20 CQ能不能有一种流量统治第二种流量,(由于是英文,dominate)? (笔试题) 

21 FTP下载一个文件完成。有几个TCP连接??四次 (笔试题)

snmp,arp,ospf协议,c++的异常处理,局部静态变量 ,全局变量的存放问题,

一道是测试时的那个覆盖问题,一道是int型溢出问题(没考虑到!),其他的基本满分^_^

程序题为把一个un int转4进制村数组,考验编程的严密性,还有一道是比较发散的思路题

前面50分10个选择题,前七个是C程序,后三个数学题。都计较简单,呵呵。中间是两个填空题,各填三空,题一为比较两个输入字符串的大小,简单。题二是填写程序注释,对内存进行操作方面的,如检查内存溢出,内存泄漏,避免产生野指针之类的。后面是两道综合题,题一写C程序函数,将一个整数转换为4进制的字符串;题二要求提供解决一个代理服务器由于应答无响应而导致的资源得不到释放的解决方案。题一简单,题二偶就模仿TCP虚电路连接的算法,写了一下自己的思路和主要步骤,感觉应该不会偏得很远!

做完这些题后还剩十分钟,后面还有10道选择题为通讯知识题,为附加题,都是关于网络,偏数据链路层和网络层的知识,

刚刚考完华为3com的软件笔试,从9:00-10:00,共一小时。 

前面50分10个选择题,前七个是C程序,后三个数学题。 

中间是两个填空题,各填三空,题一为比较两个输入字符串的大小,简单。题二是填写程序注释,对内存进行操作方面的,如free(p)什么作用。 

后面是两道综合题,题一写C程序函数,将一个整数转换为4进制的字符串;题二要求提供解决一个代理服务器由于应答无响应而导致的资源得不到释放的解决方案。 

最后20分共10道选择题为通讯知识题,关于路由器,网络方面的知识,如果看过的话不难。

第一面技术面,还有点挑战,简单介绍自己后,技术gg就开始正式发起技术进攻了,首先问了,指针函数和函数指针的区别,欧最讨厌这种绕口令式的问题了,不就一个是指针,然后该指针指向一个函数,另一个是一个函数,返回一个指针啊!简单一句话就是指与被指的关系。呵呵,不过当时紧张,绕了一小会!然后技术gg又丢出一个问题,一个单向链表怎样实现,快速查找。偶立马想到了数组的二分查找,就告诉他,给单链表增加一个数据项表示它的序号,然后用类数组二分查找算法开始查找。技术gg立马之处偶的错误之处,要是改链表要插入删除的话,改序号很麻烦,而且该单向链表有个条件要排好序的,唉!这可为难我了!:(过了一小会,技术gg笑着说给你降低点难度,假设单链表是排好序的,偶还是没有放弃二分查找,偶就回答,常规查找是指针一位一位的移,我可以一次多移几位,然后缩小查找范围,技术gg问偶这样做有什么好处,偶说可以减少比较次数,他想了会说,嗯,这个方法不错,偶正打算得意的笑,他又问还有其他方法吗?偶晕,还不肯放过!!偶回答,应该可以把单链表转化成排序二叉树吧,这样查找,插入,删除,就都很easy了!技术gg听了,略加思索,说,嗯这个方法不错!然后就要偶等二面,唉,终于pass啦!

二面是hr面,基本都是常规问题,什么别人对我的评价啊,自己的职业规划啊,可不可以提前上班啊,云云!二面完后填了个表,都到11点了,被通知不早了,明天早上继续三面。

今天早上8点就爬起来了,8点20多一点到大活,准备最后一面。到了一看,门还没开呢,只有一个面试的mm等在那里!他们也真准时,8:28终于看到工作人员了!说是8:30面试,可是三面的面试官,迟迟未出现,终于等啊等啊,等了一个小时,才听到了偶的名字,偶跟着面试官刚到指定位置,面试官的手机响了,偶狂晕,中途杀出个电话来!此时偶的肚子已经在打鼓了,唉!十几分钟后电话终于讲完了,面试开始了,介绍了下自己的项目,由于不对口,所以他也没有仔细问,然后就是自己的优点,还有就是问偶面华为没?

c题目比较多,一道网络选择,几道操作系统题目选择,还有两道大题,关于双向链表和哈希算法的。内存拷贝memcopy问题,插入排序问题

moto:

  笔试20题通讯多选,10题计算机多选。

  通讯考的都是基础知识,但是不是通讯专业的一般都要靠摸的,计算机考的比较有深度,主要是c和c++;类的继承关系(初始化顺序);二*树的先序、中序、后序,知道其中两个,推导剩下的一个;i++和++i问题。

例如:

  int i=1;

  int j;

  j=(++i)+(++i)+(++i)+(++i);//j=15

int i=1;

  int j;

  j=(++i)+(++i)+(i++)+(i++)+(++i);//j=16

  moto面试中英语口语很重要,技术面试一开始就是用英语的,后来不行了,只好用中文。第二面的那个人力资源的主管就是全英文了,一路面下来不吐一个汉字。二面的时候主要就是聊天了,问问你的爱好,和同学关系什么的,主要是看口语,以及你个人的性格。

moto待遇6000+770。干满三年一次性发6000*20%的住房公积金

//计算字符串长度的函数

     int strlen_mod(char* str)

      {   int count = 0;

          while(str[count] != '/0')

          { ++count;} 

          return count;

      }

    

 //将字符串反转输出的函数

    void print_reverse(char* str)

    {  size_t size = strlen(str);

       int size2= strlen_mod(str);

       printf("The length of %s is %d ### %d/n", str, size, size2);

       int i;

       char temp = ' ';

       for(i=0; i < size/2; i++)

       {  printf("%d/n", i);

          temp = str[i];

          str[i] = str[size - 1 - i];

          str[size - 1 - i]= temp;

       }

       printf("Reverse string: %s/n", str);

     }

What will print out?  输出结果是?

main() 

{ char *p1=“name”; 

  char *p2; 

  p2=(char*)malloc(20); 

  memset (p2, 0, 20); //

  while(*p2++ = *p1++); 

  printf(“%sn”,p2); 



Answer:empty string. 



What will be printed as the result of the operation below:

main() 

{ int x=20,y=35; 

  x=y++ + x++; 

  y= ++y + ++x; 

  printf(“%d%dn”,x,y); 



Answer : 5794

What will be printed as the result of the operation below:

main() 



int x=5; 

printf(“%d,%d,%dn”,x,x< <2,x>>2); 

}



Answer: 5,20,1 



What will be printed as the result of the operation below:



#define swap(a,b) a=a+b;b=a-b;a=a-b; 

void main()



int x=5, y=10; 

swap (x,y); 

printf(“%d %dn”,x,y); 

swap2(x,y); 

printf(“%d %dn”,x,y); 





int swap2(int a, int b) 



int temp; 

temp=a; 

b=a; 

a=temp; 

return 0; 





Answer: 10, 5

10, 5

What will be printed as the result of the operation below:



main()



char *ptr = ” Cisco Systems”; 

*ptr++; printf(“%sn”,ptr); 

ptr++; 

printf(“%sn”,ptr); 





Answer:Cisco Systems

isco systems 



What will be printed as the result of the operation below:



main()



char s1[]=“Cisco”; 

char s2[]= “systems”; 

printf(“%s”,s1); 



Answer: Cisco 



What will be printed as the result of the operation below:



main()



char *p1; 

char *p2; 

p1=(char *)malloc(25); 

p2=(char *)malloc(25); 



strcpy(p1,”Cisco”); 

strcpy(p2,“systems”); 

strcat(p1,p2); 



printf(“%s”,p1); 







Answer: Ciscosystems 



The following variable is available in file1.c, who can access it?:



static int average;



Answer: all the functions in the file1.c can access the variable. 



WHat will be the result of the following code?



#define TRUE 0 // some code 

while(TRUE) 



// some code 





Answer: This will not go into the loop as TRUE is defined as 0. 



What will be printed as the result of the operation below:



int x; 

int modifyvalue() 



return(x+=10); 



int changevalue(int x) 



return(x+=1); 





void main()



int x=10; 

x++; 

changevalue(x); 

x++; 

modifyvalue(); 

printf("First output:%dn",x); 



x++; 

changevalue(x); 

printf("Second output:%dn",x); 

modifyvalue(); 

printf("Third output:%dn",x); 







Answer: 12 , 13 , 13 



What will be printed as the result of the operation below:



main()



int x=10, y=15; 

x = x++; 

y = ++y; 

printf(“%d %dn”,x,y); 





Answer: 11, 16 



What will be printed as the result of the operation below:



main()



int a=0; 

if(a==0) 

printf(“Cisco Systemsn”); 

printf(“Cisco Systemsn”); 





Answer: Two lines with “Cisco Systems” will be printed.

C语言题库

*1 



一个C程序的执行是从_____。 

 A)本程序的main函数开始,到main函数结束 

 B)本程序文件的第一个函数开始,到本程序文件的最后一个函数结束 

 C)本程序的main函数开始,到本程序文件的最后一个函数结束 

 D)本程序文件的第一个函数开始,到本程序main函数结束 

*2 



以下叙述正确的是: 

A)在C程序中,main函数必须位于程序的最前面 

B)C程序的每行中只能写一条语句 

C)C语言本身没有输入输出语句 

D)在对一个C程序进行编译的过程中,可发现注释中的拼写错误 

*3 



以下叙述不正确的是。 

A)一个C源程序可由一个或多个函数组成 

B)一个C源程序必须包含一个main函数 

C)C程序的基本组成单位是函数 

D)在C程序中,注释说明只能位于一条语句的后面 

*4 



C语言规定:在一个源程序中,main函数的位置 。 

A)必须在最开始 

B)必须在系统调用的库函数的后面 

C)可以任意 

D)必须在最后 

*5 



一个C语言程序是由 

A)一个主程序和若干子程序组成    B)函数组成 

C)若干过程组成                  D)若干子程序组成 

*6 



在C语言中(以16位PC机为例),5种基本数据类型的存储空间长度的排列顺序为 

A)char<INT&NBSP;&NBSP;<1ONG&NBSP;&NBSP;INT<=FLOAT

B)char=int<1ong  int<=float

C)char<  int  <1ong  int=float=double 

D)char=int  =1ong  int<=float

*7 



若x,i,j和k都是int型变量,则执行下面表达式后x的值为 

 x=(i=4,j=16,k=32) 

 A)4   B)16  C)32     D)52 

*8 



假设所有变量均为整型,则表达式(a=2,b=5,b++,a+b)的值是: 

 A)7    B)8   C)6   D)2 

*9 



下列四组选项中,均不是C语言关键字的选项是 

A)define    B)getc    C)include   D)while 

 IF           char       scanf        go 

type          printf       case        pow 

*10 



下面四个选项中,均是C语言关键字的选项是 

A)auto      B)switch    C)signed    D)if 

 enum       typedef       union      struct 

 include     continue      scanf      type 

*11 



下面四个选项中,均是不合法的用户标识符的选项是。 

 A)  A            B)float       C)b-a       D)一123 

    P_0            1a0          goto          temp 

    do             一A          int           INT 

*12 



C语言中的标识符只能由字母、数字和下划线三种字符组成,且第一个字符 

 A)必须为字母            B)必须为下划线 

 C)必须为字母或下划线   D)可以是字母,数字和下划线中任一种字符 

*13 



下面四个选项中,均是合法整型常量的选项是: 

A)160      B)一0xcdf    C)一01    D)一0x48a 

 一0xffff      01a       986, 012      2e5 

     011        0xe        0668         0x 

*14 



下面四个选项中,均是不合法的整型常量的选项是: 

A)一一0f1    B)一0Xcdf  C)一018    D)一0x48eg 

一0xffff          017        999        一068 

   

      0011        12,456      5e2         03f 

*15 



下面四个选项中,均是不合法的浮点数的选项是 

A)  160.    B)  123     C)一.18    D)一e3 

   0.12        2e4.2     123e4          .234 

     e3        .e5        0.0           1e3       

*16  



下面四个选项中,均是合法浮点数的选项是 

  A)  +le+1    B)-.60    C)  123e      D)一e3 

      5e一9.4    12e-4     1.2e-.4     .8e4 

      03e2     一8e5        +2e一1     5.e一0 

*17 



下面四个选项中,均是合法转义字符的选项是 

 A)'/''        B)'/'    C)'/018'   D)'//0' 

    '//'     '/017'    '/f'       '101' 

    '/n'     '/"'       'xab'       'xlf' 

*18 



下面四个选项中,均是不合法的转义字符的选项是 

  A)'/''     B)'/1011'    C)'/011'    D)'/abc' 

    '//'         '/'        '/f'         '/101' 

    '/xf'       '/a'         '/}'        'xlf' 

*19 



下面正确的字符常量是: 

A)"a"    B)'//''    C)'W'    D)'' 

*20 



   

下面四个选项中,均是不正确的八进制数或十六进制数的选项是。 

    A)  016      B)oabc       C)010      D)  0a12 

0x8f  017 -0x11   7ff 

018   0x8  0x16   -123 

*21 



下面四个选项中,均是正确的八进制数或十六进制数的选项是。 

 A)一10 B)0abc      C)0010   0)  0al2 

   0x8f    一017       一0x11-0xl23 

  一011     0xc 0xf1      一0x8 

*22 



下面四个选项中、均是正确的数值常量或字符常量的选项是: 

   A)0.0       日)"a"     C)'3'D)十001 

      0f  3.9E-2.5       011     0xabcd 

     8.9e   lel0xFFOO  2e2 

      '&' '/'''       0a       50. 

*23 



下面不正确的字符串常量是。 

  A)'abc'  B)"12'12"     C)"0"     D)"" 

*24 



若有代数式3ae/bc,则不正确的C语言表达式是: 

 A) a/b/c*e*3      B)3*a*e/b/c 

 C)3*a*e/b*c       D)a*e/c/b*3 

*25 



已知各变量的类型说明如下: 

   int   k,a,b; 

   unsigned  long  w= 5; 

  double    x=1.42; 

则以下不符合C语言语法的表达式是: 

A)  x%(一3)   B)  w+=-2 

C)k=(a=2,b=3,a十b)      D)a十= a一=(b=4)*(a=3) 

*26 



已知各变量的类型说明如下: 

 int i=8,k,a,b; 

unsigned  long  w=5; 

 double  x=1.42,y=5.2; 

则以下符合C语言语法的表达式是: 

A)  a十=a一=(b= 4)*(a=3)  B)a=a*3=2 

C)  x%(一3)  D)y=f1oat(i) 

*27 



以下不正确的叙述是 

A)在C程序中,逗号运算符的优先级最低 

B)在C程序中,APH和aph是两个不同的变量 

C)若a和b类型相同,在执行了赋值表达式a=b后b中的值将放人a中,而b中的值不变。 

D)当从键盘输入数据时,对于整型变量只能输入整型数值,对于实型变量只能输入实型数值。 

*28 



以下正确的叙述是: 

A)在C程序中,每行中只能写一条语句 

B)若a是实型变量,C程序中允许赋值a=10,因此实型变量中允许存放整型数 

C)在C程序中,无论是整数还是实数,都能被准确无误地表示 

D)在C程序中,%是只能用于整数运算的运算符 

*29 



以下符合C语言语法的赋值表达式是 

A)d=9+e+f=d+9B)  d=9+e,f=d+9 

C)d=9十e,e++,d十9     D)d=9十e++=d十7 

*30 



已知字母A的ASCII码为十进制数65,且c2为字符型,则执行语句c2='A'十'6'一'3';后,c2中的值为 

A)D     B)68   C)不确定的值     D)C 

*31 



在C语言中,要求运算数必须是整型的运算符是。 

A) /   B) ++  c) !=   D)% 

*32 



若以下变量均是整型,且num=sum=7;则执行表达式sUM=num++,sUM++,++num后sum的值为 

 A)  7    B)  8  C)  9  D)  10 

*33 



在C语言中,int、char和short种类型数据在内存中所占用的字节数 

A)由用户自己定义     B)均为2个字节 

C)是任意的   D)由所用机器的机器字长决定 

*34 



若有说明语句:char c='/72'则变量c 

A)包含1个字符   B)包含2个字符 

C)包含3个字符   D)说明不合法,c的值不确定 

*35 



若有定义:int a=7;float x=2.5,y=4.7;则表达式x+a%3*(int)(x+y)%2/4的值是 

A)2•500000  B)2.7500OO  c)  3.500000  D)  0.000000。 

*36 



sizeof(float)是: 

A)一个双精度型表达式  B)一个整型表达式 

C)一种函数调用D)一个不合法的表达式 

*37 



设变量a是整型,f是实型,i是双精度型,则表达式10+'a'+i*f值的数据类型为 

 A)int     B)  float  C)  double  D)不确定 

*38 



下面四个选项中,均是非法常量的选项是。 

A)'as'    B)'//'  c)-0xl8    D)0xabc 

  -0fff '/01'    01177     '/0' 

'/0xa'     12,456     0xf"a" 

*39 



在C语言中,  char型数据在内存中的存储形式是: 

A)补码 B)反码 C)原码     D)ASCII码 

*40 



设变量n为f1oat类型,m为int类型,则以下能实现将n中的数值保留小数点后两位,第三位进行四舍五人运算的表达式是一一一。 

A) n=(n*100+0.5)/100.0     B)m=n*100+0.5 ,n= m/100.0 

C) n=n*100+0.5/100.0   D)n=(n/100+0.5)*100.0 

*41 



表达式18/4*sqrt(4.0)/8值的数据类型为: 

A)  int    B)float   C)double  D)不确定 

*42 



设C语言中,一个int型数据在内存中占2个字节,则unsigned  int型数据的取值范围为: 

   

A)  0~255   B) 0~32767     C) 0~65535  D)  0~2147483647 

*43 



设有说明:  char w; int  x;  f1oat  y;  double  z;则表达式w* x+z一y值的数据类型为: 

A)float    B)char   C)int     D)double 

*44 



若有以下定义,则能使值为3的表达式是: 

int  k= 7,x =12; 

A)  x%=(k%= 5)B)  x%=(k一k%5) 

C)  x%=k- k%5   D)  (x%=k)一(k%=5) 

*45 



设以下变量均为int类型,则值不等于7的表达式是 

A)  (x= y= 6,  x+y,x+1)   B)(x= y= 6,x+y,y+1) 

C)  (x= 6,x+1,y= 6,x+y)   D)  (y=6,y+l,x = y,x+1) 

*46 



putchar函数可以向终端输出一个: 

A)整型变量表达式值 

B)实型变量值 

C)字符串 

D)字符或字符型变量值 

*47 



printf函数中用到格式符%5s ,其中数字5表示输出的字符串占用5列。如果字符串长度大于5,则输出按方式 

A)从左起输出该字串,右补空格 

B)按原字符长从左向右全部输出 

C)右对齐输出该字串,左补空格 

D)输出错误信息 

*48 



printf函数中用到格式符%5s ,其中数字5表示输出的字符串占用5列。如果字符串长度小于5,则输出按方式。 

A)从左起输出该字串,右补空格 

B)按原字符长从左向右全部输出 

C)右对齐输出该字串,左补空格 

D)输出错误信息 

*49 



已有定义 int a=-2;和输出语句:printf("%8lx",a);以下正确的叙述是: 

A)整型变量的输出格式符只有%d一种 

B)%x 是格式符的一种,它可以适用于任何一种类型的数据 

C)%x 是格式符的一种,其变量的值按十六进制输出,但%8lx 是错误的 

D)%8lx 不是错误的格式符,其中数字8规定了输出字段的宽度 

*50 



若x ,y均定义为int型,z定义为double型,以下不合法的scanf函数调用语句是: 

A)  scanf(" %d%lx,%le",&x,&y,&z); 

B)  scanf("%2d * %d%lf"&x,&y,&z );   

C)  scanf("%x %* d%o",&x,&y); 

D)  scanf("%x%o%6.2f",&x,&y,&z);    

*51 



已有如下定义和输入语句 ,若要求a1,a2,c1,c2值分别为10,20,A和B,当从第一列开始输入数据时,正确的数据输入方式是 

int  a1,a2;  char  c1,c2; 

scanf("%d%c%d%c",&a1,&c1,&a2,&c2); 

A)10A 20B< CR>     B)10 A 20 B 

C)10A20   D)10A20 B。 

*52 



已有定义int  x;  f1oat  y;且执行scanf("%3d%f",&x,&y);语句,若从第一列开始输入数据12345  678(回车),则x 的值为 

A)12345  B)123   。  C)  45       D)  345 

*53 



已有定义int  x;  f1oat  y;且执行scanf("%3d%f",&x,&y);语句,若从第一列开始输入数据12345  678(回车),则y 的值为: 

A)无定值B)45.0000  C)  678.000000  D)  123.00000 

*54 



已有如下定义和输入语句,若要求a1,a2,c1,c2的值分别为10,20,A,B,当从第一列开始输入数据时,正确的数据输入方式是: 

int  a1,a2;  char  c1,c2; 

scanf("%d%d",&a1,&a2); 

scanf("%c%c",&c1,&c2); 

 A)  1020AB    B)10  20AB 

 C)10  20   AB   D)10 20AB 

*55 



已有程序段和输入数据的形式如下,程序中输入语句的正确形式应当为 

 main() 

{int  a;float f; 

    printf("/nInput number:"); 

  输入语句 

    printf("/nf=%f,a= %d/n ,f,a); 



Input  number:  4.5   2 

A )scanf("%d,%f",&a,&f);  B)scanf("%f,%d",&f,&a) 

C)scanf("%d%f",&a,&f);   D)scanf("%f%d",&f,&a); 

*56 



根据定义和数据的输入方式,输入语句的正确形式为: 

已有定义:  float  fl,f2; 

数据的输入方式:4.52 

3. 5 

A)scanf("%f,%f",&f1,&f2);  B)scanf("%f%f",&f1,&f2 ); 

C)scanf("%3.2f%2.1f",&f1,&f); D)scanf("%3.2f%2.1f",&f1,&f2); 

*57 



阅读以下程序,当输入数据的形式为25,13,10正确的输出结果为: 

 main() 

{int  x,y,z 

 scanf("%d%d%d",&x,&y,&z ); 

 printf("x+y+z=%d/n ,x+y+z);。 

 } 

 A)x +y+z=48      B)x +y+z=35 

 C)x +z=35D)不确定值 

*58 



阅读 下程序,若运行结果为如下形式  ,输入输出语句的正确内容是: 

main() 

{int  x;  float  y;printf("enter  x,y  :") 

输入语句    输出语句 



输入形式    enter  x,y:  2  3.4 

输出形式    x+y=5.40 

A)scanf("%d,%f",&x,&y);printf("/nx+y= %4.2f",x+y); 

B)scanf("%d%f",&x,&y );printf("/nx+y=%4.2f",x+y); 

C)scanf("%d%f",&x,&y); printf("/nx+y=%6.lf",x+y); 

D)scanf("%d%3.1f",&x,&y );printf("/nx十y=%4.2f",x+y); 

*59 



以下说法正确的是: 

A)输入项可以为一实型常量,如scanf("%f",3.5); 

B)只有格式控制,没有输入项,也能进行正确输入,如scanf("a=%d,b=%d"); 

C)当输入一个实型数据时,格式控制部分应规定小数点后的位数, 

如scanf("%4.2f",&f); 

D)当输入数据时,必须指明变量的地址,如scanf("%f",&f); 

*60 



根据下面的程序及数据的输入方式和输出形式,程序中输入语句的正确形式应该为: 

 main() 

{char  ch1  ,ch2  ,ch3; 

 输入语句 

printf("%c%c%c",ch1,ch2,ch3);} 

 输入形式:  A B C 

 输出形式:  A B 

 A)  scanf("%c%c%c",&ch1,&ch2,&ch3); 

 B)  scanf("%c,%c,%c", &ch1,&ch2, &ch3); 

 C)  scanf("%c %c %c",&ch1,&ch2,&ch3); 

 D)  scanf("%c%c",&ch1,&ch2,&ch3); 

*61 



有输入语句:  scanf("a= %d,b= %d,c=%d",&a,&b,&c);为使变量a的值为1,b为3,c为2,从键盘输入数据的正确形式应当是 

A)132(回车) 

B)1,3,2(回车) 

C)a=1b=3c=2(回车) 

D)a=1,b =3,c =2(回车) 

*62 



以下能正确地定义整型变量a,b和c 并为其赋初值5的语句是 

 A)int a=b= c= 5;       B) int a,b, c= 5; 

 C)a= 5,b=5,c=5;     D)  a= b= c=5; 

*63 



已知ch是字符型变量,下面不正确的赋值语句是 

A)ch='a+b';  B)ch='/0';  C)ch='7'+'9';  D)  ch=5+9; 

*64 



已知ch是字符型变量,下面正确的赋值语句是  

A)  ch= '123';  B)  ch= '/xff';  C)  ch= '/08';  D)  ch="/"; 

*65 



若有以下定义,则正确的赋值语句是: 

 int  a,b;float  x; 

  A)  a=1,b=2,    B)b++;  C)  a= b= 5     D)  b= int(x); 

*66 



设x 、y均为f1oat型变量,则以下不合法的赋值语句是 

A)++x;   B)y=(x%2)/10; C)  x*=y+8;  D)x=y=0; 

*67 



x,y,z均为int型变量,则执行语句x=(y=(z=10)+5)一5;后,x 、y 和之的值是: 

  A)  x=10    B)  x=10  C)  x=10  D)  x=10 

       y=15 y=10       y=10       y=5 

       z=10 z=10       z=15       z=10 

       

*68   

D   

逻辑运算符两侧运算对象的数据类型一一一。 

  A)只能是0或1 

  B)只能是0或非0正数 

  C)只能是整型或字符型数据 

  D)可以是任何类型的数据 

*69 



下关于运算符优先顺序的描述中正确的是一一一。 

A)关系运算符< 算术运算符< 赋值运算符< 逻辑与运算符 

B)逻辑 运算符< 关系运算符< 算术运算符< 赋值运算符 

C)赋值运算符< 逻辑与运算符< 关系运算符< 算术运算符 

D)算术运算符< 关系运算符< 赋值运算符< 逻辑与运算符 

*70 



下列运算符中优先级最高的是一一一。 

  A)<   B)十   C)&&     D)!= 

*71 



能正确表示"当x 的取值在[1,10]和[200,210]范围内为真,否则为假"的表达式是一一一。 

  A)  (x>=1)  &&(x<=10)  &&(x> = 200)  &&(x<=210) 

  B)  (x>=1)  || (x<=10)  ||(x>=200)  ||(x<=210) 

  c)  (x>=1)  &&(x<=10)||(x>= 200)  &&(x<=210) 

  D) (x > =1)||(x< =10)  &&  (x> = 200)||(x<=210) 

*72 



表示图中坐标轴上阴影部分的正确表达式是: 

      /////||//////| 

      /////||//////| 

   ----------------------------->   X 

  a  b      c      

  A)(X<=A)&&(X>=B)&&(X<=C) 

  B) (x< =a)||(b<=x<=c) 

  C)(x<=a)|| (x> =b)  &&  (x<=c) 

  D)(x < =a)&&(b< = x < = c) 

*73 



判断char型变量ch是否为大写字母的正确表达式是一一一。 

  A)' A' <=ch<='z'     B)(ch> = 'A')&(ch<=' z' ) 

  C)(ch>=' A' )&&(ch<='z') D)(' A' < = ch)AND('z'> = ch) 

*74 



设x,y 和z是int型变量,且x = 3,y= 4,z= 5,则下面表达式中值为0的是 

  A)'y'&&'y' 

  B)x < =y 

  C) x||y+z&&y-z 

  D) !(x<Y)&&!Z||1) 

*75 



已知x =43,ch='A',y=0则表达式(x > = y && ch<'B'&&!Y) 的值是 

   A)0   B)语法错   C)1   D)"假"   

*76 



若希望当A的值为奇数时,表达式的值为"真",A的值为偶数 表达式的值 

   

为"假"。则以下不能满足要求的表达式是: 

A)  A%2= =1    B)!(A%2 = =0)   C)!(A%2)    D)  A%2 

*77 



设有 int a = 1,b=2,c =3, d =4, m=2, n=2; 

       执行(m= a>b)&&(n=c>d)后n的值为: 

    A)1B )2       C)3      D)4 

 *78 

 D      

判断char型变量c1是否为小写字母 正确表达式为: 

    A)' a' <=cl<=' z'    B)  (cl> = a)&&(cl<=z) 

    C)(' a' >=cl)||(' z' < = cl)  D)(c1>='a')&&(cl<='z') 

*79 



以下程序的运行结果是: 

   #include  "stdio.h" 

    main()      ,,  / 

    {int  a,b,d= 241; 

      a=d/100 % 9 

      b= (一1)&&(一1); 

    printf("%d,%d",a  ,b); 

  }  

  A)6,1     B)2,1     C) 6,0     D)2,0 

*80 



执行以下语句后a的值为: 

int a,b,c; 

a= b= c= 1; 

++a||++b&&++c     

  A)错误    B)  0      C)  2  D)  1 

*81 



 执行以下语句后b 的值为: 

    int  a=5,b=6,w=1,x=2,y=3,z=4; 

    (a=w>x)&&(b=y>z); 

  A)  6     B)  0     C)  1      D)  4 

*82 



以下不正确的if语句形式是:    

  A)if(x>y && x!=y); 

  B)if(x= =y)  x+=y     

  C)if(x != y)scanf("%d",&x )else scanf("%d",&y); 

  D)if(X<Y)&NBSP;{X++;Y++;} 

*83 



下列运算符中优先级最低的是: 

  A)?:   B)&&     c)+     D)  != 

*84 



以下if语句语法正确的是一一一。 

    A)if(x>0) 

printf("%f",x) 

else  printf("%f",- -x); 

    B) if (x>0) 

       {x=x+y;printf("%f",x);} 

       else  printf("f",-x); 

    C) if(x>0) 

       {x=x+y;  prinrf("%f",x);}; 

       else  printf("%f",-x); 

    D) if(x > 0) 

       { x = x +y;printf("%f",x)} 

else  printf("%f",-x); 

*85 



   

请阅读以下程序: 

    main() 

    {int  a=5,b=0,c=0;  

    if(a=b+c)  printf("***/n  "); 

    e1se   printf("$$$/n"); 

   以上程序 : 

      A)有语法错不能通过编译   B)可以通过编译但不能通过连接 

      C)输出***D)输出$$$ 

*86 



以下程序的运行结果是 : 

     main()     

    {int m=5; 

    if(m++> 5)  printf(" %d/n",m); 

    e1se     printf("%d/n",m- - ); 

  } 

  A)4    B)5   C)6    D)7 

*87 



当a=1,b=3,c=5,d=4 ,执行完下面一段程序后x 的值是 : 

       if(a

       if(c

       else 

       if(a

       if(b

       else x= 3; 

       else x=6; 

       else x=7; 

      A)18)2      C)3      D)6 

*88 



以下程序的输出结果是: 

   main() 

  {int  a=100,x =10,y=20,okl=5,ok2=0; 

    if  (x

    if(y ! =10) 

    if(!okl)  a=1; 

   else 

     if(ok2)  a=10; 

      a=-1: 

    printf( "%d/n",a ) 

  } 

  A)  1      B)  0    C)一1    D)值不确定 

*89 



以下程序的输出结果是: 

      main() 

      {int  x= 2,y= 一1,z=2; 

if (x<Y)&NBSP;

 if(y<0)  z= 0; 

  else    z+ =1; 

    printf("%d/n",z); 

    } 

    A)3      B )2       C)1      D) 0 

*90 



为了避免在嵌套的条件语句If一else中产生二义性,C语言规定else子句 

    总是与(  )配对。 

    A)缩排位置相同的if     B)其之前最近的if 

    C) 之后最近的if D)同一行上的if 

*91 



以下不正确的语句为: 

  A)  if(x>y); 

  B)  if  (x= y) &&(x! = 0)  x+= y; 

  C)  if(x!= y)scanf("%d",&x);  else  scanf("%d",&y); 

  D)if(x< y){x++ ;y十十;} 

*92 



请阅读以下程序: 

      #include<STDIO.&NBSP;H /> 

       main() 

      {float  a,b 

      scanf("%f",&a); 

      if (a<10.0) b=1.0/x; 

      else if((a<0.5)&&(a!=2.0))b= 1.0/(a十2.0); 

      else  if(a<10.0)  b= 1.0/x ; 

      else  b=10.0; 

    printf("%f/n",y); 

    } 

    若运行时输入2.0(回车),则上面程序的输出结果是: 

    A)0.000000   B)0.500000  C)  1. 000000   D) 0.250000 

*93 



若有条件表达式(exp) ?  a++:b--,则以下表达式中能完全等价于表 

    达式(exp)的是: 

    A)  (exp==0) B)  (exp!=0) 

    C)  (exp== 1) D)  (exp!=1)    

*94 



若运行时给变量x 输入12,则以下程序的运行结果是: 

    main() 

    {int  x,y;  

     scanf("%d",&x); 

    y=x > 12?x+10:  x一12; 

    printf("%d/n",y); 

    } 

      A)0      B)22C)12       0)10 

*95 



以下程序的运行结果是: 

      main()

      {int  k= 4,a=3,b=2,c=1; 

       printf("/n %d/n",k< a ? k:c

    } 

    A)4      B )3     C)2      D)1 

*96 



执行以下程序段后、变量a,b,c的值分别是一。 

    int  x=10,y=9; 

    int  a,b,c; 

    a =(- -x = = y++)?- -x:++y ; 

    b = x ++; 

    c = y; 

    A)a=9,b= 9,c= 9       B )a=8,b=8,c=10 

    C)a=9,b= 10,c=9      0)a=1,b= 11,c=10 

*97 



若w,x,y,z,m均为int型变量,则执行下面语句后的m值是: 

    w= 1;x = 2;y= 3;z=4; 

    m=(w

    m= (m

    m=(m

    A)1B )2     C)3D)4 

*98 



若w=1,X = 2,y= 3,z=4,则条件表达式w<Y<Z?Y:Z的值是:&NBSP;&NBSP; 

    A)4      B)3      C)20)1 

*99 



执行以下程序段后的输出结果是 

    int  w=3,  z=7,x =10; 

    printf("%d/n",x> 10?  x+100:x 一10); 

    printf("%d/n",w++||z++ ); 

    printf("%d/n",!w>z); 

    printf("%d/n",w&&z); 

    A)0       B)   1       C)0      D) 0 

        1            1           1          1

        1            1           0          0

        1            1           1          0

*100 



设有程序段 

  int  k=10; 

  while  (k=0)  k= k—1; 

  则下面描述中正确的是 

A)  while循环执行10次      B)循环是无限循环 

C)循环体语句一次也不执行   D)循环体语句执行一次 

*101 



有以下程序段 

    int  x=0,s=0; 

    while  (!  x!= 0)  s+=++x; 

    printf("%d",s); 

    则 

A)运行程序段后输出0 B)运行程序段后输出1 

C)程序段中的控制表达式是非法的       D)程序段执行无限次 

*101 



语句while(!E)中的表达式!E等价于: 

A)  E==0   B)  E!=1  C)  E!=0    D)  E==1 

   





下面程序段的运行结果是 

    a=1;b= 2;c=2; 

while(a<B<C)&NBSP;&NBSP;{&NBSP;&NBSP;&NBSP;T=&NBSP;A;A=&NBSP;B;&NBSP;&NBSP;B=T;&NBSP;C-&NBSP;-;} 

printf("%d,%d,%d",a,b,c); 

A)1,2,0    B)2,1,0    C)1,2,1    D)2,1,1 

*102 

   

D

下面程序段的运行结果是: 

x = y= 0; 

while(x<15)  y++,x + = ++y; 

printf("%d,%d",y,x); 

A)  20,7    B)6,12      c)  20,8      D)8,20 





【题5.6】下面程序段的运行结果是 

  if    n=0; 

  while(n++<=2);  printf("%d",n);  A)  2      B)  3C)  4     D)有语法错 

*103 



设有程序段 

    t=0; 

    while  (printf"*"))

     {t++; 

      if(t<3)  break 

      } 

  面描述正确的是: 

  A)其中循环控制表达式与0等价       B)其中循环控制表达式与'0'等价 

  C)其中循环控制表达式是不合法的     D)以上说法部不对 

*104 



下面程序的功能是将从键盘输入的一对数,由小到大排序输出。当输入一对相等数时结束循环,请选择填空: 

    #indude   

      main() 

      {int  a,b,t; 

scanf("%d%d",&a,&b); 

while(  【1】  ) 

{if(a>b) 

 {t=a;a=b;b=t;} 

  printf("%d,%d",a,b); 

scahf("%d%d",&a,&b);人 



【1】   A)  !a=b    B)  a!=b     C)  a= =b     D)  a=b 

*105 



下面程序的功能是从键盘输入的一组字符中统计出大写字母的个数m和小写字母的个数n,并输出m、n中的较大者,请选择填空: 

    #indude   "stdio.h"    

      main() 

      {int  m=0,n=0; 

      char    c;  1 

      while((【1】)!='/n') 

      { if(c>='A' && C<='Z') m++ ; 

      if(c>='a'  && c<='z')  n++; }      

      printf("%d/n",  m<M);&NBSP;&NBSP;&NBSP;&NBSP;}&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; 

1】 A) c=getchar()  B)  getchar()  C)c=getchar()  D)  scanf("%c",c) 

*106 



下面程序的功能是将小写字母变成对应大写字母后的第二个字母。其中y变成A,z 变成B.请选择填空。 

    #include "stdio. H" 

    main() 

    {    char c; 

  while((c=getchar())!='/n')   

{if(c>= 'a'&& c<='z') 

  c - = 30;    

   if(c>'z' && c<='z'+ 2) 

      【2】; } 

    printf(" %c",c) 

      } 

  【2】A)  c='B'   B)  c='A'      C)  c-=26     D)  c=c+26 

*107 



下面程序的功能是在输入的一批正整数中求出最大者,输入0结束循环,请选择填空。 

#include   

      main() 

      {int a,max= 0; 

      scanf("%d",&a)   

      while(【1】)     

     {if(max<A&NBSP;&NBSP;MAX=&NBSP;A;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; 

      scanf("%d",&a); } 

   printf("%d" ,max  );} 

       

【1】  A)  a==o    B)A     C)  !A = = 1D)!a  

*108 



下面程序的运行结果是。 

    #include<STDIO.H&NBSP;&NBSP; /> 

    main() 

    { int  num= 0;      

     while(num<= 2) 

     {num++     

    printf ("%d/n", num);} 

       }     

    A)1      B )  1   c)1D)1 

    2      2  2 

   3  3 

       4      

*109 



以下程序段 

x= -1; 

do 

       {x=x*x;} 

  while(!x); 

    A)是死循环 B)循环执行二次 

    C)循环执行一次     D)有语法错误 

*110 



以下描述中正确的是: 

     A)由于do一while循环中循环体语句只能是一条可执行语句,所以循环体内不能使用复合语句 

     B)  do一while循环由do开始,用while结束,在while(表达式)后面不能写分号 

     C)在do一while循环体中,一定要有能使while后表达式值变为零("假")的操作 

     D)do一while循环中,根据情况可以省略while 

*111 



若有如下语句 

 int  x=3; 

 do { printf(" %d/n",x -=2);} while(!(--x)); 

    则上面程序段 

    A)输出的是 1  B)输出的是1和-2 

    C)输出的是3和0      D)是死循环 

*112 

C

下面程序的功能是计算正整数2345的各位数字平方和,请选择填空。 

    #include<STDIO.&NBSP;H /> 

main() 

       {int  n,sum=0; 

n=2345 

do{ sum=sum+(n%10)*n%10);  

n=【2】; 

}while(n); 

printf("sum=%d",sum);}  

【2】 A)  n/1000   B)n/100      C)  n/10    D)  n%10 

*113 



下面程序是从键盘输入学号,然后输出学号中百位数字是3的学号,输入0时结束循环。请选择填空。 

   #  include<STDIO.&NBSP;H /> 

    main() 

  {1ong  int  num; 

    scanf("%ld",&num); 

    do  { if( 【1】) printf("%ld",num); 

scanf("%ld",&num); 

      }while(!num==0);} 

  【1】 A)num%100/10==3 B)num/100%10==3

C)num%10/10==3 D)num/10%10==3

 

*114 



下面程序的功能是把316表示为两个加数的和,使两个加数分别能被13和11整除。请选择填空。 

 #include   

   main() 

 {int  i=0,j,k; 

  do{  i++;k=316一13*i;} 

  while(【1】);j=k/11; 

  printf(" 316=13* %d十11*%d",i,j); 

   } 

【1】A)k/11    B) k%11    C) k/11==0   D) k/11== 0 

*115 



下面程序的运行结果是: 

      #indude 

      main() 

      {int  y=10; 

       do{y--;} 

       while(--y); 

       printf("%d/n",y--); 



    A)一1B) 1      C)8      D) 0 

*116 



若运行以下程序时,从键盘输入ADescriptor(CR)表示回车),则下面程序的运行结果是: 

      #include<STDIO.&NBSP;H /> 

      main()    

      { char c; 

      int v0=0.v1=0,v2=0; 

  do{ 

    switch(c=getchar()) 

      {case 'a':case  'A'  : 

case 'e':case  ' E' : 

case 'i':case 'I' : 

case 'o':Case  'O'  : 

case 'u':case  'U'  :vl+=1; 

default:v0+=1;v2+=1  ;}     ; 

while(c!='/n'); 

      printf("v0=%d,v1=%d,v2=%d/n",v0,v1,v2); 

  

    }     

A)v0=7,v1=4,v2=7B)  v0=8,v 1=4,v2=8     

C)v0= 11,v1=4,v2=11      D)  v0=12,vl=4,v2=12 

*117 



下面程序的运行结果是:     

      #include<STDIO.&NBSP;H /> 

       main()   

      {int   a==1,b=10; 

 do 

{b-=a;a++;}while(b--<0); 

printf("a=%d,b=%d/n",a,b); 

      }    ' 

   A)a=3,b=11   B )a=2,b=8    C)a=1,  b=一1    D)a=4,b=9 

*118 



下面有关for循环的正确描述是:    

    A)  for循环只能用于循环次数已经确定的情况 

    B)  for循环是先执行循环体语句,后判断表达式 

    C)  在for循环中,不能用break语句跳出循环体 

    D)  for循环的循环体语句中, 可以包含多条语句,但必须用花括号括起来 

*119 



对for(表达式1;;表达式3)可理解为: 

A)  for(表达式1;  0;表达式3) 

B)  for(表达式1;1;表达式3) 

C)    for(表达式1;表达式1;表达式3) 

D)    for(表达式1;表达式3;表达式3) 

*120 



若i为整型变量,则以下循环执行次数是: 

  for  (i=2;i==0;)  printf("%d",i-- );  

  A)无限次   B) 0次   C) 1 次     D)  2次 

*121 



以下for循环的执行次数是: 

  for  (x=0,y一0;  (y=123)&&(x<4);  x++); 

  A)是无限循环 B)循环次数不定 C)执行4次  D)执行3次 

*122 



以下不是无限循环的语句为: 

  A)  for  (y=0,x=1;x > ++y;x =i++)  i=x ; 

  B)   for (;;  x++=i); 

  C)  while  (1){x ++;} 

  D)  for(i=10; ;i--)sum+=i; 

*123 



下面程序段的运行结果是: 

for (y= 1;y<10;) y=((x=3* y,x+1),x-1); 

printf  ("x=%d,y=%d",x,y); 

A)x=27,y=27   B)x=12,y=13   C)x=15,y=14   D)x=y=27 

*124 



下面程序段的运行结果是 

 for(x=3;x<6;x++)printf((x %2)?("**%d"):(" ##%d/n"),x); 

   A)**3      B )##3     C)##3  D)**3##4 

      ##4  **4 **4##5 **5 

      **5  ##5 

*125 



下列程序段不是死循环的是 

      A)  int  i=100; 

   whiLe  (1) 

  {i=i%100+1; 

  if  (i>100)  break;     

   }    

      B)  for(;;);     

      C)  int  k=0;      

   do{++k;}  while  (k> =0)  ; 

      D)  int  s=36; 

   while  (s);--s   

*126 



执行语句for(i=1;i++<4;);后变量i的值是 

  A)3    B )4     C)5    D)不定 

       

*127 



下面程序的功能是计算:至50中是7的倍数的数值之和,请选择填空。 

     #include<STDIO.&NBSP;H />    • 

     main() 

    {int  i,sum= 0;   

      for(i=1;i<=50;i++) 

if([1])  sum+=i; 

      printf("%d",sum); 

    }      

A) (int)(i/7)==i/7  

B) (int)i/7==i/7 

C)  i%7= 0 

D)  i%7==0 

*128 



下面程序的功能是计算 1至10之间的奇数之和及偶数之和。请选择填空; 

    # include <STDIO.&NBSP;H /> 

    main() 

   {int  a,b,c,i; 

     a=c=0; 

    for(i=0;i<=10;i+=2) 

    { a+=i; 

     [1]; 

     c+=b; 



     printf("偶数之和=%d/n",a);       

     printf("奇数之和=%d/n",c-11), 



[1] A )b=i--  B)  b=i+1   C)  b=i++   D)b=i-1 

*129 



下面程序的运行结果是: 

    #include  <STDIO.&NBSP;H /> 

      main()      

    {int i; 

for(i=1;i<=5;i++) 

  switch(i%5) 

{case  0:printf("* ");break; 

  case  1  :printf("#");break; 

  default  :printf("/n"); 

  case  2  :printf("&"); 

    } 

      A)#&&&*  B) #&   C)  #    D)#&  

        &         & 

        &         & 

                  * 

*130 



下面程序的运行结果是: 

    #include <STDIO.&NBSP;H /> 

      main() 

     {  int    x,i;     

      for(j-1;i<=100;i++) 

      {x=i; 

  if(++x%2==0) 

    if(++x%3==0) 

   

      if(++x%7==0) 

      printf("%d",x); 

   

  } 

      } 

    A)39  81     日)42  84      C)26  68       D)  28  70 

*131 



下面程序段的功能是计算1000!的末尾含有多少个零。请选择填空。 

     (提示:只要算出1000!中含有因数5的个数即可 

    for(k=0,i=5;i<=1000;  i+=5) 

      

    while(【1】){k++; m=m/5;} 

      

【1】A)m%5==0   B)m=m%5==0  C)m%5==0  D)m%5!=0 

*132 



下面程序的运行结果是: 

    #include  

    main() 

    {int i,b,k=0; 

    for(i=1;i< =5;i++) 

      {b=i%2; 

       while(b-->=0)     k++; 

      } 

    printf("%d,%d",k,b); 

  } 

    A)3,-1     B )8,-1    C)3,0     D)8,-2 

*133 



以下正确的描述是。 

   

    A)continue语句的作用是结束整个循环的执行 

    B)只能在循环体内和switch语句体内使用break语句 

    C)在循环体内使用break语句或continue语句的作用相同 

    D)从多层循环嵌套中退出时, 只能使用goto语句 

   

*134 



下面程序段:     

      for  (t=1;  t<=100;t++) 

  {scanf("%d",&x);  

   if(x<0)  continue;  

      printf("%3d",t);}  

   A) 当x<0时整个循环结束 

   B) x>=0时什么也不输出 

   C) printf函数永远也不执行 

   D)最多允许输出100个非负整数 

*135 



下面程序段: 

  x=3; 

  do 

  {y=x--; 

  if(!y){ printf("x");continue;} 

  printf("#"); 

  }  while (1<=x<=2); 

    A)将输出##       B)将输出##* 

    C)是死循环 D)含有不合法的控制表达式 

   

   

*136 



以下描述正确的是 

    A)  goto语句只能用于退出多层循环 

    B)  switch语句中不能出现continue语句 

    C)  只能用continue语句来终止本次循环 

    D)  在循环中break语句不能独立出现 

*137 



与下面程序段等价的是: 

  for(n=100;n<= 200; n++) 

  {if (n%3==0)  continue; 

      printf("%4d",n);}  

     A) for(n=100;(n%3)&& n<=200;n++) printf("%4d",n); 

     B)  for(n=100;(n%3)|| n<=200;n++) printf("%4d",n); 

     C) for(n=100;n<=200;n++)if(n%3!=0)printf("%4d",n) 

     D) for(n=100;n<=200;  n++) 

      {if(n%3)  printf("%4d",n); 

       else  continue; 

       break;}  

*138 



下面程序的运行结果是:       

    #include    

  { int k=0; 

     char  c='A'; 

      do 

       {switch(c++) 

{case  'A':k++;break; 

 case  'B':k--; 

 case  'C':k+=2;break; 

 case  'D':k=k%2;continue; 

 case  'E':k=k*10;breab; 

 default:k=k/3;} 

 k++;} 

      while(c<'G') 

 printf("k=%d",k);}      

      A)k=3     B)k=4    C)k=2    D)k=0 

*139 



若运行以下程序时,从键盘输入3.6,2.4,(表示回车),则下面程序的运行结果是: 

  #indude   

  # include  

 main() 

  {float x,y,z; 

   scanf("%f%f",&x,&y); 

   z=x/y; 

   while(1) 

    {if(fabs(z)>1.0) {x=y;y=z;z=x/y;} 

    else break;} 

    printf("%f",y);} 

   A) 1.5  B)1.6 C) 2.0 D)  2.4    

   

*140 



下面程序的运行结果是: 

#include  "stdio.h" 

main() 

{int a,b; 

for(a=1,b=1;a<=100;a++) 

{if (b>=20) break; 

if(b%3==1) {b+=3;continue;} 

b-=5;} 

printf("%d/n",a);} 

A) 7      B) 8     C)9      D) 10 

*141 



下面程序的运行结果是: 

 #include "stdio.h" 

 main() 

{int i; 

for(i=1;i<=5;i++)  

{if (i%2) printf("#"); 

else continue; 

printf("*"); 



printf("$");} 

A) *#*#$   B)   #*#*#*$   C) *#*#$   D)#*#*$ 

*142 



下面程序的运行结果是: 

  

main() 

{int i,j,a=0; 

for (i=0;i<2;i++) 

{ for (j=0;j<=4;j++) 

{if (j%2)  break; 

a++;} 

a++;} 

printf("%d/n",a); 



A)  4       B)  5       C)  6      D)  7  

   

*179 



在c语言中,引用数组元素时,其数组下标的数据类型允许是__. 

        A)整型常量         B)整型表达式 

        c)整型常量或整型表达式D)任何类型的表达式 

*180 



以下对一维整型数组a的正确说明是__。 

        A)  int a(10);  B)int n= 10,a[n]; 

        c)  int  n;       D)  #define  SIZE  10; 

scanf("%",&J1);  int a[SIZE]; 

int a[n]; 

*181 



若有说明:int a[10];则对a数组元素的正确引用是__。 

        A)a[10] B) a[3.5] C) a(5) D) a[10-10]

*182 



在C语言中,一维数组的定义方式为:,类型说说明符 数组名__。 

A) [常量表达式]   B) [整形表达式]     

c)[ 整型常量]或[整型表达式] D)[整型常量] 

   

*183 



以下能对一维数组a进行正确初始化的语句是__。 

        A)  int a[10]=(0,0,0,0,0) B)int  a[10]={} 

C)  int  a[]={0};D) int a[10]={10*1}; 

*184 



以下对二维数组a的正确说明是__。 

      A)  int a[3][];   B)  floatf a(3,4); 

       c)  double a[1][4];  D)  float a(3)(4); 

*185 



若有说明:int a[3][4]; 则对a数组元素的正确引用是__。 

        A)  a[2][4]     B)  a[1,3]   C)  a[1+1][0]    D)  a(2)(1); 

*186 



若有说明:int a[3][4];则对a数组元素的非法引用是__。 

   

   

A)  a[0][2*1]  B)  a[1][3]  C)a[4-2][0]    D)a[0][4]"       " 

*187 



以下能对二维数组a进行正确初始化的语句是__。 

   

        A)  int a[2][]={{1,0,1},{5,2,3}}; 

        B)  int a[][3」={{1,2,3},{4,5,6}}; 

        C)   int  a  [2][4]={{1,2,3},{4,5},{6}}; 

        D)  int  a[][3={{1,0,1},{},{1,1}}; 

*188 



以下不能对二维数组a进行正确初始化的语句是__。 

   

 A)  int  a[2][3]={0}; 

 B)  int  a[][3」={{1,2,3},{4,5,6}}; 

 C)  int  a[2][4]={{1,2,3},{4,5}{6}}; 

 D)   int  a[][3]={{1,0,1},{0},{1,1}};  

*189 



若有说明:  int  a[3]「4]={0};则下面正确的叙述是 

 A)只有元素a[0][0]可得到初值0  

 B)此说明语句不正确:。     

 C)数组a中各元素都可得到初值,但其值不一定为0。 

 D)数组a中每个元素均可得到初值0 



*190 



若有说明:int  a[][4]={0,0};则下面不正确的叙述是__。 

A)数组a的每个元素都可得到初值0   

 B)二维数组a的第一维大小为1   

 C)因为二维数组0中第二维大小的值除以初值个数的商为1,故数组a行 

 数为1 

 D)只有元素a[0]「0」和a[0]「1」可得初值0,其余元素均得不到初值0 

*191 



若有说明:int  a[3]「4];则数组a各元素 

 A)可在程序的运行阶段得到初值0 

 B)可在程序的编译阶段得到初值0    

 C)不能得到确定的初值

D)可在程序的编译或运行阶段得初值0 

*192 



以下各组选项中,均能正确定义二维实型数组a的选项是 

   

 A)float a[3][4];                      B)float a(3,4);   

 float a[][4];                             float a[3][4]; 

 float a[3][]={{1},{0}};                   float a[][]={{0},{0}}; 

 C)float a[3][4];                      D)float a[3][4]; 

static float a[][4]={{0},{0}};             float a[3][]; 

auto float a[][4]={{0},{0},{0}};           float a[][4] 

*193 

A  

下面程序(每行程序前面的数字表示行号) 

 1   main() 

 2     { 

 3     int  a[3]={3*0}; 

 4     int  i; 

 5     for(i=0;i<3;i++)  scanf("%d",&a[ i]); 

 6     for(i=1;i<3;i++) a[0]=a[0]+a[ i] ;

 7     printf("%d/n",a[0]); }

A)没有错误B)第3行有错误 

C)第5行有错误 D)第7行有错误  

*194 

C  

下面程序一一一(每行程序前面的数字表示行号)。 

1    main() 

2    { 

3     float a[10]={0.0}; 

4     int  i 

5     for(i=0;i<3;i++)  scanf("%d",&a[ i]); 

6     for(i=0;i<10;i++)  a[0]=a[0]+a[ i]; 

7     printf("%d/n",a[0]); 

8     } 

A)没有错误         B)第3行有错误 

C)第5行有错误      D)第7行有错误   

*195 



下面程序有错的行是 

 1  main() 

 2{ 

 3   int  a[3]={1}; 

 4   int  i; 

 5   scanf("%d",&a); 

 6   for(i=1;i<3;i++)  a[0]=a[0]+a[ i]; 

 7   printf("a[0]=%d/n",a[0]); 

 8   } 

 A)3      B)6   C)7      D)5 

*196 



下面程序(每行程序前面的数字表示行号) 

 1  main() 

 2  { 

 3   int a[3]={0}; 

 4   int i; 

 5   for(i=0;i<3;i++)scanf("%d",&a[ i]); 

 6   for(i=1;i<4;i++)a[0]=a[0]+a[ i]; 

 7   printf("%d/n",a[0]); 

 8                     } 

  

 A)没有错误            B)第3行有错误 

 C)第5行有错误        D)第6行有错误 

*197 



若二维数组a有m列,则计算任一元素a[ i][j]在数组中位置的公式为 

(假设a[0][0]位于数组的第一个位置上。) 

 A)i*m+j    B)j*p+i。C)i*m+j-1    D)i*m+j+1   

*198 



对以下说明语句的正确理解是 

 int a[10]={6,7,8,9,10}; 

 A)将5个初值依次赋给a[1]至a[5] 

 B)将5个初值依次赋给a[0]至a[4] 

 C)将5个初值依次赋给a[6]至a[10] 

 D)因为数组长度与初值的个数不相同,所以此语句不正确 

*199 



以下不正确的定义语句是__. 

 A)  double  x[5]={2.0,4.0,6.0,8.0,10.0}; 

 B)  int  y「5」={0,1,3,5,7,9}; 

 C)  char  c1[]={’1’,’2’,’3’,’4’,’5’};    4       。二入广    /   "’   (: 

 D)  char c2[]=}{'/x10','/xa','/x8'}; 

*200 



若有说明:int  a[」「3」={1,2,3,4,5,6,7};则a数组第一维的大小是__. 

 A)  2    B)  3  C)  4  D)无确定值 

*201 



若二维数组a有m列,则在a[ i][j]前的元素个数为__. 

 A)j*m+j  B)i*m+j    C)i*m+j  D)i*m+j+1 

*202 



定义如下变量和数组:  

 int k;  

 int a[3][3]={1,2,3,4,5,6,7,8,9}; 

 则下面语句的输出结果是    。" 

 for(k=0;k<3;k++)  printf  ("%d",a[k][2-k]); 

 A)  3  5  7B)3 6  9   C) 1 5 9 D)  1 4 7 

*203 



若有以下程序段: 

...... 

 int a[]={4,0,2,3,1};i,j,t; 

 for(i=1;i<5;i++) 

 {t=a[ i];j=i-1; 

 while(j>=0&&t>a[j]) 

   {a[j+1]=a[j];j--;} 

        ...... 

 则该程序段的功能是 __.   

 A)对数组a进行插入排序(升序) 

 B)对数组a进行插入排序(降序) 

 C)对数组a进行选择排序(升序) 

 D)对数组a进行选择排序(降序) 

*204 



以下正确的定义语句是__. 

 A)  int  a[1」[4」={1,2,3,4,5}; 

 B)  float x[3][]={{1},{2},{3}}; 

 C)  long b[2][3]={{1},{1,2},{1,2,3}}; 

 D)  double  y[][3]={0}; 

*205 



下面程序的运行结果是__.

main()  

 {int  a[6」「6」,i,j; 

   for(i=1;i<6;i++) 

   for(j=1;j<6,j++) 

     a[ i][j]=(i/j)*(j/i); 

   for(i=1;i<6;i++) 

     {for(j=1;j<6;j十十) 

   printf("%2d",a[ i][j]); 

       printf("/n"_);} 

         } 

   

A)11111     B)00001 C)10000     D)10001 

11111        00010    01000         01010 

11111        00100    00100         00100 

11111        01000    00010         01010 

11111        10000    00001         10001 

*206 



下面程序的运行结果是 __. 

     main() 

     {int  a[6],i; 

         for(i=1;i<6;i十十) 

     {a[ i]=9*(i-2+4*(i>3))%5; 

      printf("%2d",a[ i]); 

}         

       } 

   

     A)—40404B)—40403 

     C)一40443D)一40440 

*207 



下面是对s的初始化,其中不正确的是__. 

 A)  char  s[5」={"abc"} B)char s[5]={'a','b','c'}; 

 C)  char  s[5]=""       D) char s[5]="abcdef"; 

*208 



下面程序段的运行结果是 __. 

 char  c[5]={'a','b','/0','c','/0'}; 

   printf("%s",c);} 

A)’a’’b’ B)  ab   C)  ab c   D)  ab     

   (其中 表示空格)     

*209 



对两个数组a和6进行如下初始化         

   char  a[]="ABCDEF"; 

   char  b[]={’A’,’B’,’C’,’D’,’E’,’F’};卜 

   则以下叙述正确的是 __.    

   A)  a与b数组完全相同       B)  a与b长度相同 

   C)  a和b中都存放字符串     D)  a数组比b数组长度长 

*210 



有两个字符数组a、b,则以下正确的输入格式是  __. 

   A)  gets  (a,b);   B)  scanf  ("%s%s",a,b); 

   C)  scanf  ("%s%s",&a,&b);  D)  gets  ("a"),  gets  ("b"); 

*211 



有字符数组a[80]和b[80],则正确的输出形式是__. 

A)  puts  (a,b);  B)  printf  ("%s,%s,a[],b[]); 

C)  putchar(a,b);  D)  puts  (a),  puts  (b); 

*212 



下面程序段的运行结果是__. 

 char  a[7]="abcdef"; 

 char  b[4]="ABC"; 

 strcpy(a,b); 

 printf  ("%c",a[5]); 

         J。        "      了 

A)一   B)/O  C) e D)f(其中一表示空格) 

*213 



有下面的程序段 

char  a[3],b[]="china"; 

a=b; 

printf("%s",a); 

则__. 

A)运行后•将输出Chm、"、B)运行后将输出Ch’一 

C)运行后将输出Chi      D)编译出错 

*214 



下面程序段的运行结果是__. 

char  c[]="/t/v///0will/n"; 

printf("%d",strlen(c));        

A)14     B)  3  C)  9  D)字符串中有非法字符,输出值不确定 

*215 



判断字符串a和b是否相等,应当使用__. 

A)  if  (a==b)   B)  if  (a=b) 

C)  if  (strcpy(a,b)),  D)  if  (strcmp(a,b)) 

*216 



判断字符串s1是否大于字符串s2应当使用__. 

A)  if  (sl>s2)   B)  if  (strcmp(s1,s2)) 

C)  if  (strcmp(s2,sl)>0)  D)  if  (strcmp(s1,s2)>0) 

*217 



下面程序段是输出两个字符串中对应字符相等的字符。请选择填空。

char  x[]="programming";

char  y[]="Fortran";

int  i=0;

while  (x[ i]!='/0'&& y[ i]!='/0')

{if  (x[i ]==y[ i]) printf  ("%c", 1  );

else i++;}

}

【1】A)x[i++] B)y[++i]  C)x[ i]    D)y[ i] 

*218 



下面描述正确的是__. 

 A)两个字符串所包含的字符个数相同时,才能比较字符串 

 B)字符个数多的字符串比字符个数少的字符串大 

 C)字符串"STOP "与"STOp"相等 

 D)字符串"hat"小于字符串"he"

*219 



下述对C语言字符数组的描述中错误的是 

 A)字符数组可以存放字符串 

 B)字符数组的字符串可以整体输入、输出 

 C)可以在赋值语句中通过赋值运算符"="对字符数组整体赋值 

 D)不可以用关系运算符对字符数组中的字符串进行比较 

*220 



有已排好序的字符串a,下面的程序是将字符串s中的每个字符按a中元素

的规律插入到a中。请选择填空。 

 #indude 

  main() 

 {char  a[20」="cehiknqtw"; 

   char  s[]="fbla"; 

   int i,k,j; 

   for(k=0;s[k]!='/0';k十+) 

    {j=0;    

        

   while(s[k]>=a[j]&&a[j]!='/0')j++; 

       for(i=str1en(a);i>=j;i--) 【2】; 

      a[j」=S[k」; 

     } 

 puts(a); 

   } 

  【2】  A)  a[ i]=a[i+1]  B)  a[i+1]=a[ i]; 

        C)   a[ i]=a[i-1] D) a[i-1]=a[ i]; 

*221 



下面程序的功能是将字符串5中所有的字符c删除。请选择填空。 

 #include   

 main() 

     {char  s[80]; 

int i,j; 

      gets(s); 

       for(i=j=0;s[ i]!='/0';i++) 

         if(s[ i]!='c')【1】 

     

     puts(s); 

  

 【1】A)s[j++]=s[ i]  B)s[++j]=s[ i]; 

   C)  s[j]=s[ i];j++;   D)  s[j]=s[ i]; 

*222 



下面程序的功能是从键盘输入一行字符,统计其中有多少个单词,单词之间 

 用空格分隔。请选择填空。        

   #indude 

   main() 

       {char  s[80」,c1,c2=''; 

         int  i=0,num=0; 

         gets(s); 

         while(s[ i]!='/0') 

         {c1=s[ i]; 

1f(i==0)  c2=''; 

else  c2=s[i-1]; 

if(【1】)  num++; 

i++; 

 ) 

     printf("There are %d words./n",num); 

 } 

   

         【1】A)c1='' && c2=='' B)cl!='' && c2=='' 

   C)c1=='' && c2!='' D)cl!='' && c2!='' 

*223 



下面程序的运行结果是 

   #indude 

main() 

  {char  ch[7]={"12ab56"}; 

         int  i,s=0; 

   for(i=0;ch[ i]>='0'&&ch[ i]<='9';i+=2) 

     s=10*s+ch[ i]-'0'; 

        printf("%d/n",s); 

       } 

   A)1       B)1256        C)  12ab56      D)1 

                                                              2 

                                                              5 

                                                              6 

*224 



当运行以下程序时,从键盘输入:aa  bb 

cc dd 

(表示回车),则下面程序的运行结果是 

 #  include 

 main()     

 {char  a1[5],a2[5」,a3[5],a4[5]; 

 scanf("%s%s",a1,a2);  

 gets(a3);  gets(a4); 

 puts(al);  puts(a2); 

 puts(a3);  puts(a4); 

       }

A)  aa     B)  aa ()aa        D)  aa bb

bb         bb    bb           cc

cc    cc  dd       dd

cc dd      dd ee

*225 



   

当运行以下程序时,从键盘输入:ab 

    c 

    dd 

 (表示回车),则下面程序的运行结果是 

 #include 

   #difine N 6 

  main() 

   {  char  c[N];        

       int  i=0; 

       for  (;i

   for(i=0;  i<N;&NBSP;&NBSP;I++)&NBSP;&NBSP;PUTCHAR(C[ 

、 

 A)abcdef   B)a    C)b      D)ab 

 b       c         c 

 c       d         d 

 e       

     

 f       

*226 



当运行以下程序时,从键盘输入:AhaMA  Aha(

 则下面程序的运行结果是 

   #include  "stdio.h" 

   main() 

 {char  s[80],c='a'; 

   int i=0; 

   scanf("%s",s); 

   while(s[ i]!='/0') 

     {if(s[ i]==c)  s[ i]=s[ i]-32; 

   else  if(s[ i]==c-32)  s[ i]=s[ i]+32; 

     i++; 

     } 

   puts(s); 



A)ahAMa      B)AhAMa      C)  AhAMa  ahA  D)  ahAMa ahA 

*227 



下面程序的运行结果是一一一。 

 #include 

 #inc1ude 

 main() 

 {char  a[80」="AB",b[80]="LMNP"; 

       int  i=0; 

       strcat(a,b);  

   whi1e(a[i++]!='/0')b[ i]=a[ i]; 

   puts(b); 

 } 

 A)LB   B)ABLMNP     C)AB     D)LBLMNP 

*228 



下面程序的运行结果是 

  #include  

   main() 



char str[]="SSSWLIA",c; 

int k; 

for(k=2;(c=str[k])!='/0';k++) 

{switch(c)

{case 'I':++k;break; 

case 'L':continue; 

default:putchar(c);continue; 



putchar('*'); 





A)SSW*    B)SW*   C)  SW*A  D)SW 

*229 



下面程序的运行结果是 

 #include  

main() 

{char a[]="morning",t; 

int i,j=0; 

for(i=1;i<7;i++) if(a[j]

t=a[j];a[j]=a[7]; 

a[7]=a[j];puts(a); 



A)  mogninr  B)  mo  C)  morning  D)  mornin

将两个无序数组合并为有序链表

实现思想:

把两个无序的数组首先排序,然后再按照链表结构把它们分别构造好,然后再把两个有序链表合并。

int const array1_size = 5;//数组1的长度

int const array2_size = 7;//数组2的长度

//链表结构体

typedef struct ListNode

{

 int data;

 ListNode * next;

}ListNode;

//合并两个有序链表返回不带头结点的头指针

ListNode * MergeList(ListNode *p,ListNode *q)

{

 ListNode *h,*r;

 h = new ListNode;

 h->next = NULL;

 r = h;

 while(p !=NULL && q != NULL)

 {

         if(p->data <= q->data)

         { 

           r->next = p;

           r =p;

           p = p->next;

         }

        else

       {

          r->next = q;

          r =q;

          q = q->next;

}

 }

 if(p != NULL)

      r->next = p;

 else

      r->next = q;

 p = h;

 h = h->next;

 delete p;

 return h;

}

//构造一个链表(没有头结点的)

ListNode * GenerateList(int array[],int length)

{

 ListNode * h,*temp,*old_head ;

 h = new ListNode;

 h->next = NULL;

 temp = h;

 for(int i = 0; i< length;i++)

 {

  ListNode *p = new ListNode;

  p->data = array[i];

  temp->next = p; 

  temp = p;

 }

 temp->next = NULL; 

 old_head = h;

 h = h->next;

 delete old_head;

 return h;

}

//打印链表

void Print_List(ListNode *h)

{

 ListNode *p;

 p = h;

 for(;p!=NULL;p=p->next)

  printf("%d ",p->data);

}

//引入冒泡排序算法

void Swap(int *a,int *b)

{

 int temp;

 temp = *a;

 *a = *b;

 *b = temp;

}

void Bubble_Sort(int *array,int length)

{

 int pass,j;

 for(pass =1;pass<=length-1;pass++)

  for(j=0;j<=length-2;j++)

   if(array[j]>array[j+1])

    Swap(&array[j],&array[j+1]);

}

/*********************OK,所有准备工作已经做好,开始main()函数**********/

//输入字符表示结束

int _tmain(int argc, _TCHAR* argv[])

{

 char end;

 int List1[array1_size]={9,5,6,10,45};

 int List2[array2_size]={3,1,4,6,7,9,0};

 Bubble_Sort(List1,array1_size);

 Bubble_Sort(List2,array2_size);

 ListNode * m_list1,*m_list2,*m_list;

 m_list1 = GenerateList(List1,array1_size);

 m_list2 = GenerateList(List2,array2_size);

 m_list = MergeList(m_list1,m_list2);

 Print_List(m_list);

 scanf("%c",&end);

 return 0;

}

上海聚力传媒技术有限公司官方VC笔试题解答

  上海聚力传媒技术有限公司成立于2005年5月,是家新冒出来的公司,而他能够冒出来的原因是由于它的电视直播软件PPLIVE(www.pplive.com)抢占了基于P2P技术的网络视讯服务的先机,超级女生电视节目的火爆成就了PPLIVE软件这款软件,不过现在这个领域的竞争者蜂拥而上,日子并不轻松。如果是我,我会很慎重的考虑这类新兴小公司的,当然我还是很佩服它的,公司的创始人是华中科技大学的校友,有幸见过他的演讲。

  下面是它2005年度的官方VC笔试题,他称:如有自信2小时能做完的应聘者请将做完答案发mail至campus_hr@synacast.com,我们会马上和你联系的。呵呵,我并不打算把答案发到这个邮箱去。



一、问答

、实模式与保护模式。为什么要设计这两种模式?好处在什么地方?分别写出各自寻址的过程。

答:

1. 实模式,又叫实地址模式,CPU完全按照8086的实际寻址方法访问从00000h--FFFFFh(1MB大小)的地址范围的内存,在这种模式下,CPU只能做单任务运行;寻址公式为:物理地址=左移4位的段地址+偏移地址,即:物理地址是由16位的段地址和16位的段内偏移地址组成的。

2.保护模式,又叫内存保护模式,寻址采用32位段和偏移量,最大寻址空间4GB,在这种模式下,系统运行于多任务,设计这种模式的原因和好处是:保护模式增加了寻址空间,增加了对多任务的支持,增加了段页式寻址机制的内存管理(分段机制使得段具有访问权限和特权级,各应用程序和操作系统的代码和核心是被保护的,这也是多任务支持的实现关键和保护这个名字的由来)。寻址过程为:物理地址=由段地址查询全局描述符表中给出的段基址+偏移地址,即:物理地址由影像寄存器中的基址加上16位或者32位的偏移组成。



、请阅读以下一段程序,并给出答案。

class A

{

public:

    A(){ doSth(); }

    virtual void doSth(){printf("I am A");}

};

class B:public A

{

public:

    virtual void doSth(){ printf("I am B");}

};

B b;

执行结果是什么?为什么?

答:执行结果是I am A

因为b对象构造时调用基类A的构造函数A(),得此结果。

、在STL的应用中 map这种key-value的应用很多,如果key的类型是GUID,该如何处理?

答:谁知道怎么处理补上吧。



、一个内存变量a=5,有5个线程需要对其进行操作,其中3个对a进行加1操作,2个对a进行减1操作,为了保证能够得到正常结果6,需要使用什么方法?(列出越多越好)

答:即要求列出线程同步方法,具体答案可见下面一题。



、描述并比较以下对象:事件,信标,临界区,互斥对象。

答:这些对象都是用于线程同步的对象。

临界区:一种保证在某一时刻只有一个线程能访问数据的简便办法。它只可以在同一进程内部使用。主要API函数有,产生临界区:InitializeCriticalSection,删除临界区:DeleteCriticalSection,进入临界区:EnterCriticalSection,退出临界区:LeaveCriticalSection。

互斥对象:互斥对象跟临界区相似,但它不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享,当然下面两者也有这个特点。主要API函数有,创建互斥量: CreateMutex,打开一个存在的互斥量: OpenMutex,释放互斥量的使用权:ReleaseMutex,关闭互斥量:CloseHandle。

信标:使用信号量(信标)最重要用途是:信号允许多个线程同时使用共享资源,它指出了同时访问共享资源的线程最大数目。它的API函数和使用方法都与互斥对象相似,如创建信号灯:CreateSemaphore,传入的参数可以指定信号灯的初始值。

事件:用来通知其他进程/线程某件操作已经完成。API函数有创建,打开事件对象等,特殊点的是可以用函数SetEvent人工设置事件为有无信号状态,因此创建事件对象时可以有两种方式,一种为自动重置,一种为人工重置。只有人工重置方式创建的事件对象才能正确使用函数SetEvent。

鉴于本套题考的是VC,有必要说明的是在MFC中对于各种同步对象都提供了相对应的类CCtiticalSection,CMutex,CSemaphore ,CEvent,另外为使用等待功能封装了两个类:CSingleLock和CMultiLock。这些类方便了使用这些同步对象。



、cdecl、stdcall、fastcall是什么?哪种可以实现个数不定的入口参数,为什么?

答:三者都是函数调用的约定。

cdecl:c declare(C调用约定)的缩写,是C和C++程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,由调用者把参数弹出栈,对于传送参数的内存栈是由调用者来维护的,正因为如此,只有这种调用方式可实现个数不定的入口参数(可变参数)。

stdcall:是Pascal程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,被调用的函数在返回前清理传送参数的内存栈。

上两者的主要区别是前者由调用者清理栈,后者由被调用的函清理栈。当然函数名的修饰部分也是不同的。

fastcall:采用寄存器传递参数,特点就是快了。



二、程序设计(以下题目请写出实现代码)

、有一段文本,统计其中的单词数。例如:

As a technology , "HailStorm" is so new that it is still only known by its 

code name.

注意:单词间的间隔不一定是一个空格。

答:可执行程序代码如下,假设该文本已存入text这个数组里。

void main()

{

  char text[1000]={"As a technology , 'HailStorm' is so new that it is still only known by its code name."};

  int i=0,count=0;

  bool flag=true;

  while (text[i]&&i<1000) 

  {

    if (text[i]==' ') 

    {

      flag=true;

    }

    else if (flag==true && ((text[i]>='a'&&text[i]<='z')||(text[i]>='A'&&text[i]<='Z'))) 

    {  // 前有空格,接着出现字母,表示出现一个单词。

      count++;

      flag=false;

    }

    i++;

  }

  cout<<count;

}

、国际象棋有8×8格,每个格子可放一个棋子。皇后的规则是可以横、竖、斜移动。在一个棋盘放置8个皇后,并使它们互相无法威胁到彼此。

答:以下是可执行C代码,采用非递归解法,你如果想了解皇后问题的算法的详细过程可看下面网址:

http://www.cnjcw.cn/infoview/2005031720203563221270.html

不过下面的代码是以列优先进行试探的,不是上面网址介绍的那样以行优先的,当然本质是一样的。

#include <iostream.h>

#define QUEEN 8  //皇后数量

int queen[QUEEN] ;  //下标代表所在列号,值代表所在行号,

          //如queen[1]=2表示第1列第2行有个皇后

bool row_YN[QUEEN] ;      //棋局的每一行是否有棋,有则为1,无为0 ;

bool passive_YN[2*QUEEN-1] ;  //斜率为1的斜线方向上是否有棋,共有2*QUEEN-1个斜线

bool negative_YN[2*QUEEN-1] ; //斜率为负1的斜线方向上是否有棋

//用全局变量,因全局数组元素值自动为0

int main()



  int row = 0 ;//游标,当前移动的棋子(以列计)

  bool flag = false ;   //当前棋子位置是否合法

  queen[0] = -1 ;      //第0列棋子准备,因一开始移动的就是第0列棋子

  int count = 0 ;      //一共有多少种解法的计数器 ;



  while(row>=0 ) //跳出条件是回溯到无法回溯时 

  {

    queen[row]++ ;      //row列上的皇后走到下一行试试

    if(queen[row] >= QUEEN) //当前列全部走完

    {  

      queen[row] = -1 ; //当前列棋子置于准备状态

      row-- ;        //回溯到上一列的棋子

      if(row>=0)      //回溯时要清理如下行,斜线的标志位   

      {

        row_YN[queen[row]] = false ; 

        passive_YN[queen[row] + row] = false ;

        negative_YN[QUEEN-1 + row - queen[row]] = false ;

      } 

    }

    else

    { 

      //先判断棋子所在行没有棋子

      if(row_YN[queen[row]] == false) 

      {

        flag = true ; 

        //以下检查当前棋子是否与之前的棋子斜线相交

        if( passive_YN[queen[row] + row] == true || negative_YN[QUEEN-1 + row - queen[row]] == true)  

          flag = false ;

        else     

          flag = true ;

        if(flag)  // flag为真表示位置合法

        {  

          if(row == QUEEN-1)  //列到达最后,即最后一个皇后也找到位置,输出解

          {

            count++ ;  //解法的数目加一 ;

            cout<<"***第"<<count<<"种解法***"<<endl  ;

            for(int i=0;i<QUEEN;i++)

              cout<<"第"<<i<<"列皇后在第"<<queen[i]<<"行"<<endl;

          }

          row_YN[queen[row]] = true ;// 当前行设为有棋子

          passive_YN[queen[row] + row] = true ;//当前行正斜率方向有棋子

          negative_YN[QUEEN-1 + row - queen[row]] = true ; //当前行负斜率方向上也有棋子

          row++ ;

          if(row >= QUEEN) 

          {  // 找到解后再次回溯找另外的解,这同上面无解回溯是一样的

            row-- ;

            row_YN[queen[row]] = false ; 

            passive_YN[queen[row] + row] = false ;

            negative_YN[QUEEN-1 + row - queen[row]] = false ;//原理同回溯

          }      

          flag = false ;     

          }

      }

    }

  }

  cout<<QUEEN<<"皇后问题一共有"<<count<<"种解法"<<endl  ;

  return 0 ;

}

、输入二个64位的十进制数,计算相乘之后的乘积。

答:以下代码为网上别人贴出的,输入任意位数十进制数(包括小数,负数)都可以得出正确结果。

思路是:将大数当作字符串进行处理,也就是将大数用10进制字符数组进行表示,然后模拟人们手工进行“竖式计算”的过程编写乘法。

#include <iostream.h>

#define MAX 100

int str_num(char str[]) //计算字符串的长度,等效于strlen(str);

{

  int i=0,num_str=0;

  while(str[i]!=0)

  {num_str++;

  i++;

  }

  return(num_str);

}

void place(int num_str,char str[]) //将字符串高低颠倒。

{

  int temp=0,i=0,j=0;

  for(i=0,j=num_str-1;i<j;i++,j--)

  {temp=str[j];

  str[j]=str[i];

  str[i]=temp;

  }

}

void transition(unsigned int a[],char str1[]) //数字字符转化为数字。

{

  int i=0;

  while(str1[i]!=0)

  {a[i]=str1[i]-'0';

  i++;

  }

}

void multiply_int(unsigned int a[],unsigned int b[],unsigned int c[]) //大数相乘算法,入口为整形数组。

{

  int i=0,j=0;

  for(i=0;i<MAX;i++)

  for(j=0;j<MAX;j++)

  {

    c[i+j]+=a[i]*b[j];

    c[i+j+1]+=c[i+j]/10;

    c[i+j]%=10;

  }

}

void output(int sign,unsigned int c[],int quan) //数据输出。

{

  int sign_temp=0,i=0;

  cout<<"The result is: ";

  if(sign==1)

  cout<<"-";

  for(i=MAX-1;i>-1;i--)

  {

    if(sign_temp==0)

    {if(c[i]!=0)

    sign_temp=1;

    }

    if(sign_temp==1)

    {

      if(i==quan-1)

      cout<<".";

      cout<<c[i];

      c[i]=0;

    }

  }

  cout<<endl;

}

void multiply_string(char str1[],char str2[],unsigned int c[]) //大数相乘,入口为字符串。

{

  unsigned int a[MAX]={0},b[MAX]={0};

  int sign=0;

  transition(a,str1);

  transition(b,str2);

  multiply_int(a,b,c);

}

int sign_comp(char str1[],char str2[]) //符号判断,如果为负数将作相应处理。

{

  int i=0,sign_num=0;

  if(str1[0]==45)

  {sign_num=!sign_num;

  for(i=0;i<MAX-1;i++)

  str1[i]=str1[i+1];

  }

  if(str2[0]==45)

  {sign_num=!sign_num;

  for(i=0;i<MAX-1;i++)

  str2[i]=str2[i+1];

  }

  return (sign_num);

}

int format(char str[]) //将输入的字符串进行格式化。以得到字符的一些标志信息和相应格式的新数据串。

{

  int point=0,quan=0,i=0,j,k=0,sign_point=0,num_str=0;

  num_str=str_num(str);

  while(str[i]!=0)

  {

    if(str[i]<'0'||str[i]>'9')

    if(str[i]!='.')

    {cout<<"data error"<<endl;

    return(-1);

    }

    else

    {point++;

    sign_point=i;

    }

    if(point>1)

    {cout<<"data error"<<endl;

    return(-1);

    }

    i++;

  }

  if(point==1)

  {

    for(j=sign_point;j<num_str;j++)

    str[j]=str[j+1];

    num_str--;

    quan=num_str-sign_point;

  }

  place(num_str,str);

  return(quan);

}

void clear(char str[]) //清空函数。

{

  int i;

  for(i=0;i<MAX;i++)

  {

    str[i]=0;

  }

}



void main(void) //主函数。

{

  char str1[MAX]={0},str2[MAX]={0};

  int quan1=0,quan2=0,sign=0;

  unsigned int c[MAX*2+1]={0};

  do

  {

    cout<<"Please input the first number:";

    cin>>str1;

    cout<<"Please input the second number:";

    cin>>str2;

    sign=sign_comp(str1,str2);

    quan1=format(str1);

    quan2=format(str2);

    if(quan1==-1||quan2==-1)

    { 

      clear(str1);

      clear(str2);

    }

  }while(quan1==-1||quan2==-1||str1[0]==0||str2[0]==0);

  multiply_string(str1,str2,c);

  output(sign,c,quan1+quan2);

}

所有题目到此结束,说实话后面两题的算法我就是看别人的代码(呵呵,再次实话,后两题代码也不是我写的,只是对已有代码做了些修改,使结构更清晰,便于阅读)

intel的面试题:不用任何局部和全局变量实现int strlen(char *a)

int strlen(char *a)

{

if(0 == *a)

return  0;   

          else

return  1 + strlen(a +1);

}

传说中的baidu笔试题(另一个版本)

一、选择题:15分 共10题 

1.    已知一个线性表(38,25,74,63,52,48),采用的散列函数为Hash($Key)=$Key mod 7,将元素散列到表长为7的哈希表中存储。请选择后面两种冲突解决方法分别应用在该散列表上进行等概率成功查找的平均查找长度,拉链法   ,线性探测法    . 

A. 1.0            B. 1.5           C. 1.7           D. 2.0          E. 2.3         

F. 7/6            G. 4/3           H. 3/2

2.    需要将OS缓冲区的数据刷新到硬盘,可以调用的函数有(多选): 

A.fflush()     B. fsync()       C. sync()        D.writev()

3.    下面哪个shell语句不能打印出用户主目录的路径? 

A. echo “$HOME”              B. echo ~        

C. echo `$HOME`              D. echo $HOME

4.    最坏情况下,合并两个大小为n的已排序数组所需要的比较次数  

A.2n              B.2n-1            C.2n+1             D.2n-2

5.    一个B类网的子网掩码是255.255.240.0,这个子网能拥有的最大主机数是: 

A. 240           B. 255            C.4094           D. 65534

6.    以下代码执行后,val的值是___: 

unsigned long val = 0; 

char a = 0x48; 

char b = 0x52; 

val = b << 8 | a; 

A  20992        B  21064         C   72            D 0

7.    内存的速度远远高于磁盘速度,所以为了解决这个矛盾,可以采用: 

A 并行技术       B 虚存技术         C 缓冲技术        D 通道技术

8.    以下代码打印的结果是(假设运行在i386系列计算机上): 

    struct st_t 

    { 

        int    status; 

        short* pdata; 

        char   errstr[32]; 

    };

st_t  st[16]; 

    char* p = (char*)(st[2].errstr + 32); 

    printf("%d", (p - (char*)(st)));

A   32             B 114 

C   120            D 1112

9.    同一进程下的线程可以共享以下 

A. stack            B. data section 

C. register set        D. thread ID

10.    以下哪种操作最适合先进行排序处理?  

A 找最大、最小值                B 计算算术平均值  

C 找中间值                      D 找出现次数最多的值

二、简答题:20分,共2题

1.    (6分)下面是一个http请求: 

    GET /baidu/blog/item/6605d1b4eb6433738ad4b26d.html HTTP/1.1 

    Host: hi.baidu.com 

    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6 

    Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 

    Accept-Language: zh-cn,zh;q=0.5 

    Accept-Encoding: gzip,deflate 

    Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7 

    Keep-Alive: 300 

    Connection: keep-alive 

    Referer: http://hi.baidu.com/baidu 

    Cookie: BAIDUID=AFB70E986AC48B336ABAB7505CDD1C76;     

    请解释以下各字段基本含义: Host、User-Agent、Accept-Charset、Connection、Referer、Cookie

2.    (14分)函数A将字符串str1转成小写,并打印出转化前后的字符串。另外,改错时不能改变函数的接口和主要思路。改错时,请指出行号。 

1 #include <stdio.h> 

 2 #include <stdlib.h> 

 5 char* str1   = "ABDFLjlero我们都是saf"; 

 7 char*  ToLower(char s[]) 

 8 { 

 9     static size_t i=sizeof(s); 10      

11     for (i; i>=0; i--) { 

12         if (s[i]>"A" && s[i]<"Z") { 

13             s[i] += 26; 

14         } 

15     } 

16     return s;

}

19 int A() 

20 { 

21     printf("old str[%s] after lower[%s]n", str1, ToLower(str1)); 

22 }

三、编程题:30分 共1题 

注意:要求提供完整代码,如果可以编译运行酌情加分。

1.    两个已排序的整型数组,求交集,最快算法 

输入:两个已排序的整型数组(int a[m], b[n]) 

输出:两个数组的交集

四、设计题:35分 共1题 

注意:请尽可能详细描述你的数据结构、系统架构、设计思路等。建议多写一些伪代码或者流程说明。 

1.    考虑一个字符串替换的过程,在一个文本文件中含有一些文本内容和一些需要替换的变量,变量的格式为“$Var$”,原来的“$”使用“$$”进行转义,原来的“$$”表示为“$$$”。我们将含有变量的文件称为模板(文件名为t),文本文件的平均长度为100K。另外,还有一系列的变量文件,里面为变量名和变量值的对应关系(文件名为1.v , 2.v… n.v),每个变量文件包含的变量数在百万数量级,且变量排列次序不定。现要求将,模板里的变量分别用变量文件里的变量替换,并将生成的文件写成(1.r,
2.r… n.r)。 

要求:从算法和实现上和实现技术上的细节对程序进行优化,尽量使程序高效。程序运行环境为2G内存,4CPU。阐明主要思路,给出伪码和说明,可以着重指出你使用的优化技术。 

例子:模板文件为 

This is an $FF$ $$. I like $FF$ and $FA$。 

变量文件为 

1.v 

FF : banana 

FA : apple 

2.v 

FA: 苹果 

FF : 香蕉 

则生成文件为 

1.r 

This is an banana $$. I like banana and apple。 

2.r 

This is an香蕉 $$. I like 香蕉and苹果。

百度11月4日网上笔试题及答案(仅供参考)

用C语言实现一个revert函数,它的功能是将输入的字符串在原串上倒序后返回。

2 编程:

用C语言实现函数void * memmove(void *dest,const void *src,size_t n)。memmove

函数的功能是拷贝src所指的内存内容前n个字节

到dest所指的地址上。



3 英文拼写纠错:

在用户输入英文单词时,经常发生错误,我们需要对其进行纠错。假设已经有一个包

含了正确英文单词的词典,请你设计一个拼写纠错

的程序。

(1)请描述你解决这个问题的思路;

(2)请给出主要的处理流程,算法,以及算法的复杂度;

(3)请描述可能的改进(改进的方向如效果,性能等等,这是一个开放问题)。



4 寻找热门查询:

搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串

的长度为1-255字节。假设目前有一千万个记录,

这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个

。一个查询串的重复度越高,说明查询它的用户越多,

也就是越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。

(1)请描述你解决这个问题的思路;

(2)请给出主要的处理流程,算法,以及算法的复杂度。



5 集合合并:

给定一个字符串的集合,格式如:

{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}

要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应

输出

{aaa bbb ccc ddd hhh},{eee fff}, {ggg}

(1)请描述你解决这个问题的思路;

(2)请给出主要的处理流程,算法,以及算法的复杂度

(3)请描述可能的改进(改进的方向如效果,性能等等,这是一个开放问题)。

////////////////////////////////1

1 题

char *revert(char * str)

{

int n=strlen(str);

int i=0;

char c;

for(i=0;i

 {

c=str;

str=str[n-i];

str[n-i]=c;

}

return str;

}

///////////////////////////////////

2 题

void * memmove(void *dest,const void *src,size_t n)

{

assert((dest!=0)&&(src!=0));

char * temp=(char * )dest;

char * ss=(char * )src;

int i=0;

for(;i<N;I++)

 {

*temp++=*ss++;

}

return temp;

}



/////////////////////////////////////////////////

3 题

(1)思路 : 

字典以字母键树组织,在用户输入同时匹配



(2)

流程:

每输入一个字母: 

沿字典树向下一层,

a)若可以顺利下行,则继续至结束,给出结果;

b)若该处不能匹配,纠错处理,给出拼写建议,继续至a);

算法:

1.在字典中查找单词

字典采用27叉树组织,每个节点对应一个字母,查找就是一个字母

一个字母匹配.算法时间就是单词的长度k.

2.纠错算法

情况:当输入的最后一个字母不能匹配时就提示出错,简化出错处理,动态提示

可能 处理方法:

(a)当前字母前缺少了一个字母:搜索树上两层到当前的匹配作为建议;

(b)当前字母拼写错误:当前字母的键盘相邻作为提示;(只是简单的描述,可 

以有更多的)

根据分析字典特征和用户单词已输入部分选择(a),(b)处理



复杂性分析:影响算法的效率主要是字典的实现与纠错处理

(a)字典的实现已有成熟的算法,改进不大,也不会成为瓶颈;

(b)纠错策略要简单有效 ,如前述情况,是线性复杂度;

(3)改进

策略选择最是重要,可以采用统计学习的方法改进。



//////////////////////////////////////////////

4 题

(1)思路:

用哈希做

(2)

首先逐次读入查询串,算哈希值,保存在内存数组中,同时统计频度

(注意值与日志项对应关系)

选出前十的频度,取出对应的日志串,简单不过了。

哈希的设计是关键。 

//////////////////////////////////////////////////

5 题

(1)思路:先将集合按照大小排列后,优先考虑小的集合是否与大的集合有交集。有

就合并,如果小集合与所有其他集合都没有交集,则独立。独立的集合在下一轮的比

较中不用考虑。这样就可以尽量减少字符串的比较次数。当所有集合都独立的时候,

就终止。

(2)处理流程:

1.将集合按照大小排序,组成集合合并待处理列表

2.选择最小的集合,找出与之有交集的集合,

如果有,合并之;

如果无,则与其它集合是独立集合,从待处理列表 中删除。

3.重复直到待处理列表为空



算法:

。将集合按照大小从小到大排序,组成待处理的集合列表。

。取出待处理集合列表中最小的集合,对于集合的每个元素,依次在其他集合中搜索

是否有此元素存在:

1>若存在,则将此小集合与大集合合并,并根据大小插入对应的位置 。转3



2>若不存在,则在该集合中取下一个元素。如果无下一个元素,即所有元素

都不存在于其他集合。则表明此集合独立,从待处理集合列表中删除。并加入结果集

合列表。转3。

。如果待处理集合列表不为空,转2。

如果待处理集合列表为空,成功退出,则结果集合列表就是最终的输出。

算法复杂度分析:

假设集合的个数为n,最大的集合元素为m

排序的时间复杂度可以达到n*log(n)

然后对于元素在其他集合中查找,最坏情况下为(n-1)*m

查找一个集合是否与其他集合有交集的最坏情况是m*m*(n-1)

合并的时间复杂度不会超过查找集合有交集的最坏情况。

所以最终最坏时间复杂度为O(m*m*n*n)

需要说明的是:此算法的平均时间复杂度会很低,因为无论是查找还是合并,都是处

于最坏情况的概率很小,而且排序后优先用最小集合作为判断是否独立的对象,优先

与最大的集合进行比较,这些都最大的回避了最坏情况。

(3)可能的改进:

首先可以实现将每个集合里面的字符串按照字典序进行排列,这样就可以将查找以及

合并的效率增高。

另外,可能采取恰当的数据结构也可以将查找以及合并等操作的效率得到提高

百度笔试题:

写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。函数接口为:int   find_orderk(const int * narry,  const int n,  const int k)     

要求算法复杂度不能是O(n^2)

参考答案:

/***************************************   

  输入:   n:数组元素的个数   k:第几大的数   

              a:待查找的数组元素   

  ****************************************/   

 #include   <stdio.h>

#include   <stdlib.h>

#include   <time.h>

#define   N   100

void Rand_select(int*, int, int );

int partition( int*, int, int );

int swap( int&, int& );

int k, ans;

int  main()

{

int n, a[N], i;

while(scanf( "%d%d",  &n,  &k ) != EOF )

{

srand(time(NULL));

k--;

for( i = 0;  i < n;  i++ )

scanf("%d", a + i );

Rand_select( a, 0, n-1 );

printf( "%d/n", ans );

}

return   0;

}

void Rand_select(int a[], int p, int q)

{

int m;

if (p <= q)

{

m = partition( a, p, q );

if( k == m )

{

ans = a[m];

return;

}

else if( k > m )

Rand_select( a, m+1, q);

else

Rand_select( a, p, m-1 );

}

}

int partition(int a[], int p, int q)

{

int last, i;

if( q !=  p )

swap( a[rand()%(q-p)+p],  a[p] );

for( i = p+1, last = p; i <= q; i++ )

if( a[i] >= a[p] )

swap( a[i], a[++last] );

swap( a[last], a[p] );

return   last;

}

int swap(int &p, int &q)

{

int  temp = p;

p = q;

q = temp;

return  0;

}

可以先用快速排序进行排序,其中用另外一个进行地址查找 代码如下,在VC++6.0运行通过。    

  //快速排序

#include <iostream>       

  using namespace std;   

    

  int Partition (int *L,int low,int   high)   

  {   

  int temp = L[low];   

  int pt =  L[low];   

    

  while (low  <  high)   

  {   

  while (low < high && L[high] >= pt)   

      --high;   

  L[low]  =  L[high];   

  while (low < high && L[low] <= pt)   

      ++low;   

  L[low]  =  temp;   

  }   

  L[low]   =   temp;  

  return low;   

  }   

    

  void QSort (int *L,int low, int high)   

  {   

  if  (low < high)   

  {   

  int pl = Partition (L,low,high);       

  QSort (L, low, pl - 1);   

  QSort (L, pl + 1, high);   

  }   

  }   

    

  int main ()   

  {   

  int narry[100],addr[100];   

  int sum = 1, t;

    

  cout << "Input  number:" <<  endl;   

  cin >> t;   

    

  while   (t != -1)   

  {   

  narry[sum]  =  t;   

  addr[sum - 1]  =  t;   

  sum++;       

  cin >> t;   

  }   

    

  sum -= 1;   

  QSort (narry,1,sum);   

    

  for  (int   i = 1; i <= sum; i++)   

  cout  <<  narry[i]  <<   '/t';   

  cout   <<   endl;   

    

  int k;   

  cout  <<  "Please   input   place   you   want:"   <<   endl;   

  cin  >>  k;  

  int aa = 1;   

  int kk = 0;   

  for  (;;)   

  {   

  if  (aa == k)   

  break;   

  if  (narry[kk]  !=  narry[kk + 1])   

  {   

  aa  +=  1;   

  kk++;   

  }

}

cout   <<   "The   NO."   <<   k   <<   "number   is:" << narry[sum - kk] << endl;   

  cout   <<   "And   it's   place   is:"   ;   

  for   (i = 0;i  < sum;i++)   

  {   

  if  (addr[i] == narry[sum - kk])   

  cout   <<   i   <<   '/t';   

  }       

  return 0;

}

难得啊,居然在今天看到这个题。我去年笔试baidu的时候也作过,当时写的是这个答案,高手分析下:   

  #include   <math.h>   

  #include   <time.h>   

  #include   <string>   

  #include   <iostream>   

  #include   <vector>   

  using namespace std;      

  #define   n   10   

  #define   k   5      

  int main(int argc, char *argv[])   

  {   

  srand( (unsigned )time(NULL) );   

  if ( k > n )   

  {   

  cout << "error!"<< endl;   

  return  1;   

  }   

  vector<int>  src;   

  cout << "源" << n << "个数据如下:" << endl;   

  for   ( int i = 0; i < n; i++ )   

  {   

  src.push_back( rand() );   

  cout << src[i] << "   ";   

  }   

  vector<int>  maxNum; //顺序存入最大k个数,第一个为最大的,最后一个为第k大   

  for ( i =0; i < k; i++ )   

  {   

  maxNum.push_back(-999999); //初始化maxNum,k个-9999999   

  }   

  for ( i = 0; i < n; i++ )   

  {   

     for ( int j = 0; j < maxNum.size(); j++ )   

     {   

       if  ( src[i] >= maxNum[j]) //比当前的大,则放入当前位置,后面的数字依次后退   

       {   

         for  ( int i1  =  maxNum.size()-1;  i1 > j; i1-- )   

       {   

          maxNum[i1] = maxNum[i1-1];   

       }   

       maxNum[j] = src[i];   

       break;   

     }   

    }   

  }

cout << endl << “第” << k << “大的数字为:” << maxNum[k-1] << endl;

 return  0;   

  }   

  分析:算法对n个数字只访问一次,此部分的时间复杂度为O(n);但每访问一次,须与k个数字分别比较,所以总的时间渐复杂度为O(n*k)

思想:1.consider   if(k>n)   exit(0)   

        2.if  number  n  is  a big one, use pile/stack sort   

      3.if  number  n is a small one ,use quick sort;   

      4;find your k number and print in the screen;       

  find_orderk(const   int*   narry,const   int   n,const   int   k)     

  {   

  if(n>k)   exit   (0);   

  sort(*narry);   

  for(i=0;i<n;i++)   

    if(i=k)  return  narry[k];  /*the number of  the  k  is  similiar  to  point*/   

  }

===================================================================   函数功能:返回一个第K小的元素(采用快排思想)   

  参数:(T a[]目标数组 || int l左边界 || int r右边界 ||  int  k第几小元素)   

================================================================= template <class  T>   

T  select(T a[], int  l, int  r, int  k)   

  {   

  if(l >= r)   return  a[l]; //参数错误直接返回

  int   i  =  l;   

  int   j  =  r+1;   

  T   pivot  =  a[i];   

  while(true)     

  {   

  do   

  {   

  i = i + 1;   

  }while(a[i] > pivot);   

  do   

  {   

  j = j - 1;   

  }while(a[j] < pivot);   

  if(i >= j)   

  {   

  break;   

  }   

  Swap(a[i], a[j]);   

  }   

  if(j - l + 1 == k) //如果当前基准适合的位置刚好是K的话,则满足了条件 返回基准值   

  {   

  return  pivot;   

  }   

  a[l] =  a[j];   

  a[j] =  pivot;   

  if(j - l + 1 < k)   

  {   

  return  select(a, j+1, r, k-j+l-1); //如果基准当前位置在K的左边则对右进行快排   

  }   

  else   

  {   

  return select(a, l, j-1, k); //如果基准当前位置在K的右边则对左进行快排   

  }   

  }

分析程序:

#include<stdio.h>

class A

{

public:

static int numA;

A()

{

num++;

};

~A()

{

num--;

};

virtual void print(void)

{

printf("class A, mum:%d/n", num);

}

void test(void)

{

printf("class A test/n");

print();

}

};

class B:public A

{

public:

static int numB;

B()

{

num--;

};

~B()

{

};

virtual void print()

{

printf("class B, num:%d/n", num);

}

void test(void)

{

printf("class B test/n");

print();

}

};

class C

{

public:

virtual void print()

{

printf("class B/n");

}

};

int A::numA = 0;

int B::numB = 0;

void main()

{

B b;

b.print();

b.test();

printf("1/n");

A *a;

B *p= new(class B);

p->print();

p->test();

printf("1/n");

a = p;

a->print();

a->test();

delete(a);

printf("sizeof(C):%d/n", sizeof(C));

}

#include <stdio.h>

class A1

{

public:

A1(){ doSth(); }

virtual void doSth(){printf("I am A/n");}

void test() {doSth();}

};

class B1:public A1

{

public:

virtual void doSth(){ printf("I am B/n");}

};

void main()

{

B1 *b = new B1;

b->test();

}

1 用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。

class ClxBase

{

public:

    ClxBase() {};

    virtual ~ClxBase() {};



    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };

};



class ClxDerived : public ClxBase

{

public:

    ClxDerived() {};

    ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; 



    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };

};

void main()

{

ClxBase *pTest = new ClxDerived;

pTest->DoSomething();

delete pTest;

}

的输出结果是:

Do something in class ClxDerived!

Output from the destructor of class ClxDerived!

这个很简单,非常好理解。

    但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

Do something in class ClxDerived!

也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。

    所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。