今天本是清明放假,但是,但是微软就是在今天下午组织了笔试考试,据说是全国统考。75分钟,20 道选择题,问题是,问题是神马?先看下简单的评分:
1-8 3 2 -2 0 9-18 5 3 -3 0 19-20 13 7 -7 0
1-8 每题 3 分,完全正确 3 分,不完全正确但是没有错误 2 分,有错误 -2 分,不做 0 分;19、20 题,完全正确 13 分,有错就是 -7 分,不做 0 分。是的,么有看错,有负分!做错了,不仅意味着本道题的分不得,而且要倒扣,简单滴说,最后一题做错了,就会从 100 分中扣去 20 分,因为本题得分 -7 分!如果题目全部都错做了,估计是 -50 多分!
题目给 me 的赶脚是,非大牛不能得高分,像 me 们这些半斤八两的,还不敢轻易选择,估计多数都是半对,实际上得一半的分。废话不多说,上题(题目是 me 翻译过来的,无碍大局的地方有所修改,所以不算原模原样的题)。me 会将 me 认为的正确答案标注为蓝颜色,而 me 选的答案标注为红颜色(me 没有标准和正确答案),后面加上题目分析。
分析:关于上面的函数修饰符的详细说明,可以看看百度百科。这里也简单说明,cdecl 是 C 语言的调用方式,函数参数从右到左求值,然后入栈,参数由调用方负责清理,传多少参数其实都无所谓的,于是就支持所谓的可变长度的参数;stdcall 是 C++ 的调用方式,参数从右到左求值,入栈,由被调用方处理参数,所以参数个数类型都必须匹配;pascal 是对 PASCAL 函数的调用方式,参数自左向右求值,其他类似于 stdcall;而 fastcall 的情况忽略。
A. B::f() B::f() const
B. B::f() A::f() const
C. A::f() B::f() const
D. A::f() A::f() const
分析:用 const 来修饰函数和没用 const 是不同的重载,const 修饰函数表明,函数不能修改对象的状态/值。对于非 const 对象调用非 const 函数,当然也可以调用 const 函数(优先前者);然而 const 对象只能调用 const 函数。其次,A 中的 void f() 标注为 virtual ,那么子类 B 中跟它原模原样声明即使米有标注为 virtual 的函数依然是 virtual 函数。virtual 函数就是通常所谓的实现多态的方法了,比如,上面的 p->f(); p 虽然是 A 类型指针,但是实际上指向 B 对象,调用的时候调用的是 B 的 f() 方法。为嘛 a->f() 不调用 B 的 f() const 方法呢?c++ 除非标注为 virtual,否则不进行多态,也就是说 a 是 A 类型的指针,就调用 A 对应的 f() const 方法。
问题并没有到此结束,上面的代码就是有 bug 的,试问,delete p; 的时候删除对象,是作为 A 对象删呢,还是 B 对象删呢?p 的类型是 A*,但是指向的是 B 对象丫,好吧,这里应该使用多态,正确的做法应该将 A 的析构函数标注为 virtual,否则,程序就有 undefinde behaviour(未定义的行为)。继续讨论,看下面的 code :
这里的结果会和上面的一样么?!——,实际情况是神马呢,——,不一样!这个时候的结果选 D,理由:多态只能通过指针和引用使用,对象不能使用。说到引用,将上面的代码修改为 A& base = B(); 会怎么样呢?编译错误!引用不能引用临时对象!所以代码只能改为 B b; A& base = b; 比如下面的:
这个时候程序的结果还是 B。定义 b 的时候,使用上面注释掉的行不行呢?不行,因为那样,编译器会认为 b 是一个函数!!what?!!默认构造对象的时候,() 是不能加的??!!好吧,就是这样。再进一步说,会不会赶脚上面的代码有点“蹩脚”?如果 A a = B(); 就是可以的,然而 A& a = B(); 不可以,而要首先去定义一个 B对象,然后去引用,麻烦!好吧,c++11给 me 们带来了新希望(如果 u 不认为是灾难的话):
这里的结果的答案还是 B。A&& 是右值引用,使得 me 们可以引用到一个临时量 B(); 自此以后那个临时量就归右值引用管了,不再算是临时量。基本到此为止,有点混乱,有点O__O"…。再最后补充一句,少用指针,多用对象和引用!(使用引用的时候,析构函数貌似不需要显式地标注为 virtual,这一点细节有点不清楚,至少编译器对此没有提示。)
分析:ABC 是明显的,有序的情况下数组可以二分查找,而链表不可以;插入和删除,数组不如链表灵活;链表不如数组可以随机访问。D 选项,不敢选,me 数据结构感觉跟存储类型么有必然关系,如果说存储类型指的是栈 (stack) 或是堆 (heap) 的话,数组也可以在堆上分配,链表也可以是静态链表(栈上的空间)。
分析:最初 me 不确定有些说法,因为题目强调说的是 Windows 下的进程和线程,不过后来翻看了下书,基本确定了某些说法。Windows 中的进程和线程的概念和一般操作系统书中的说法是一致的,进程是资源分配的基本单位,而线程是 CPU 调度的基本单位;一个线程从属于一个进程,当然一个进程可以创建多个线程,一个进程中的多个线程共享进程的栈空间(当然也有其他一些资源);但是每一个线程也可以有自己的栈空间,叫 TLS(线程本地存储);如果一个进程中没有显式地创建一个线程,那么就是所谓的单线程进程,其实也就是 main 执行流对应的线程。这样的话,A、B 是错的,C 是对的,而线程可以更改所属进程,太扯了,错误!补充一点,记得以前看 UNIX 高级编程,貌似有这样的说法:UNIX 系统的进程和线程和前面的说法也基本一致,但是 Linux 却特殊一点,特殊到哪一点呢?似乎没有进程和线程的明确划分,都是线程,只不过有些线程就是共享一些数据(类似于线程共享进程的数据),给人的赶脚就是同属于一个进程;有些线程不同享数据,就如同进程一般有所区分。(这里的说法不一定准确,所以,O__O"…)
A. 10 10 B. 10 11 C. 11 10 D. 11 11
分析:神奇的题目有木有丫!按标准的说法,像 x=x++; 这样的表达式,是 undefined !就是标准中没有定义的。因为 x++ 表达式的值是 10 ,后来要赋值给 x,其次 x 还要自加 1,问题是,先赋值呢,还是先自加呢?这里没有统一的说法!虽然 y = ++y; 不管怎么说结果都一样,me 认为这样的表达式也不是很合理!在一个表达式中对同一个变量多次赋值和多次使用,结果很难把握。
说说运行结果:多数人在 vc++ 和 gcc 下运行结果都是 D,但是 me 的运行结果是 B,me 的系统,win7 64位,使用 Mingw-w64 gcc 4.8.0 编译器。
array[2][2] 返回神马 ?
A. 9 B. 6 C. 2 D. 溢出
分析:介个,貌似不用多说,跟 C 中的数组有所区分,C 中的二维数组就是相同一维数组的数组,结构比较整齐,而 Java/C# 中的二维数组仅仅是一维数组的数组而已,所以 array[2][2] 这个元素其实不存在,在 Java 中运行会抛出越界异常。(实际上面的代码段不是合法的 Java 代码段,不过意思是那样的。)
分析:关于 const 和 static 貌似永远有说不完的话题,O__O"…。A、B、C 都是正确的,D 和 E 都是指向常量的指针,const 放置到 int 前面还是后面不是问题所在,而 int * const a; 才是常量指针,可以修改指向的值,但是不能修改指向。实际话题还可以再深入些,比如 A 的声明是合法的 C++ 声明吗?是合法的 C 声明吗?在 C++ 中 A 的写法肯定是 error,因为没有初始化!而在 C 中,A 只是声明而已,就是说明它是一个 const int,maybe 在其他处定义了。下面的代码段:
c 程序上面是合法程序,c++ 是错误程序!如果 typedef int *PtrInt; 这种情况下 const PtrInt a; a 是常量指针呢,还是指向常量呢?—— 可以自己去尝试一下。(答案:常量指针。)
A. 11111111 B. 12121212 C. 11112222 D. 21212121
分析:程序的运行结果是 22221111,这里没有答案!至于答案的分析,应该涉及到 c/c++ 内存对象的布局问题,虽然 me 不大懂,但是还是可以“想当然”滴班门弄斧一下。像上面的类 A,和 c 中的结构体是兼容的,在 c++ 中叫做 POD,结构体中数据布置,应该是按照声明的顺序放置的(中间可能有空隙),所谓名字的访问其实也是根据顺序访问的,看个下面的例子:
int 是 4 个字节,long long 是 8 个字节,强制将 long long 的 test 当做结构体 struct Test 处理,.a 访问的是低 4 个字节的内容,.b 访问的是高 4 个字节的内容。有了这点基础,再来看原来的题目,A 是一个类(结构体),里面只容纳一个 long,(me 电脑上 4 个字节),B 继承了 A,又多容纳了一个 long,实际就是俩 long。data 的 B 类型数组 4 个对象,本来是 8 个 long,不看 seta 函数的话,全部是 1,而在函数 seta 中处理的时候,数组变成 A 类型的了,一个 A 元素是一个 long,所以在函数 seta 内部,访问 data[0] - data[3] 实际是访问的 8 个 long 的前 4 个 long,也就是将前 4 个 long 置为 2,前 4 个 long 在 main 函数中对应的就是 B 类型数组的 data[0].a、data[0].b、data[1].a、data[1].b,于是乎 main 函数输出 B 数组对象,结果是 22221111。
分析:当初图样图森破,图拿衣服。老鼠吃过药不会立马死,当时 me 这个重点么抓到,其次,要测出来这瓶毒药至少几只老鼠,me 当时傻×:最少一只吧,比如正好碰巧测出来!~~~~(>_<)~~~~好吧,网上这个题目有很多人已经回答了,10 只老鼠,因为每只老鼠的死亡状态可能有 2 种,10 只的话,可以拼凑出 2 ^ 10 = 1024 种状态,也就是 1024 只瓶子的情况都可以测出来,至于细节,下面叙述。
0 - 1023 的话,用二进制表示正好是 10 位,每一位都是 0 或是 1。如果第一位表示第一只老鼠吃不吃的情况,第二位表示第二只老鼠吃不吃的情况,第 n 位表示第 n 只老鼠吃不吃的情况,首先说,这 1024 个瓶子,正好可以给老鼠们一种吃法,现在的问题是,比如第 k 瓶有毒,老鼠们肯定有一种状态吧,比如有些死了,有些没有死,我们希望第 k 瓶有毒就对应一种状态,这样的话,根据状态就可以反推是第 k 瓶。现在就看是不是有这么个一一对应关系。
比如第 1 瓶有毒,0000...0001,第一只老鼠吃了,其他的老鼠都没有吃,如果有毒的话,第一只老鼠就死了,其他老鼠都没事(注:其他瓶没有毒,所以即使第一只老鼠吃了其他瓶,其他老鼠也吃了其他的瓶,但是它们的命运却不改变,就因为第 1 瓶有毒!);再比如第 3 瓶有毒,0000...0011,第一、二只老鼠吃了,其他老鼠没有吃,结果第一和第二只老鼠死了,其他老鼠没事(注:它们有没有吃其他的瓶子也不影响它们的命运,因为第 3 瓶有毒!)。由此可见,第 k 瓶有毒,就是 k 对应的二进制数的二进制位为 1 的老鼠死掉,这是必然的。一瓶毒药的方法,比如第 k 瓶,对应一个二进制数,对应一种老鼠死法,所以,一种老鼠死法,就对应一瓶毒药的方法,也就是根据老鼠的死法,就能判断出是第多少瓶:
将第 i 只老鼠死了,记二进制的第 i 位为 1,然后看看这个二进制是多少,就可以了。(前提,根据瓶子的编号,分配老鼠吃药,二进制位上为 1 表示吃。)
方法是不是唯一的呢?对称的还有一种,根据瓶子的编号,还是给老鼠喂药,对应编号为 1 的不喂,对应编号为 0 的反而喂药,最终判断方法如何呢?
将第 i 只老鼠死了,记二进制的第 i 位为 0,然后看看这个二进制是多少,就可以了。(前提,根据瓶子的编号,分配老鼠吃药,二进制位上为 1 表示不吃。)
分析:A 一定是错的,C/C++ main 函数正常结束,返回 0;B 一定是对的,C 和 D 呢?标准 C 规定是,同样两个字符串字面量,比如 "hello",内存是放一份还是两份,由编译器决定!所以,C 和 D 的结果,一般的编译器应该会有警告提示,说明是 undefined behaviour !(前面第 2 题和第 5 题,也有遇到过!) 所以,C 和 D 只能说很可能是对的,但是却不一定!
分析:前面第 5 题和第 10 题都出现了 undefined behavior 的行为!不幸的是,这里又出现了一个!~~~~(>_<)~~~~ 这是 Microsoft 的错,这种题就根本就不应该出!
A 肯定是错的,C 肯定是对的,因为正数和0,一定不会出现 /2 和 >>1 不相等的情况。然后 B 和 D 呢?如同上一题,几乎可以肯定滴说,B 和 D 也是对的,为神马是几乎肯定?因为负数的右移,多数都是实现为“算术移位”,如果是“逻辑移位”的话,一个负数移位之后变成了一个正数,B 和 D 都不对。
现在说,“算术移位”,B 是对的。算术移位,最高位填 1,对于负偶数来说,/2 和 >>1 结果还是一样,跟正数类似,所以,结果不一样,一定是奇数!其次,其次!!欲哭无泪丫……5/2 == 2,5%2 == 1,这个结果是绝对的!但是对于 -5/2 == ? -5%2 == ? 上,标准是没有规定的,于是又出现一个 undefined behaviour! 一般的实现是,模运算的结果要和被除数一致,然后保证 (a/b)*b + (a%b) == a,所以-5%2 == -1,-5/2 == -2,同时 -5 >> 1 == -3,于是乎 F-G = 1。me 死的心都有了,O__O"…
分析:高中数学题目,O__O"…(本来想解释一下的,但是赶脚么必要丫,公式 C(2,4) * C(2,5) = 6*10 = 60,横向取 2 条线,纵向取 2 条线,就是一个长方形。)
分析:小学数学题目,O__O"…(公式:1+1+2+3+4+...+n=1+(n+1)n/2 = 1+5050 = 5051)
分析:略。
分析:MVC 貌似就是 ABC 的说法。
分析:至少要一个中序遍历,前序+后序遍历不中。
分析:介个,貌似也简单,长度为 1 的字符串 n 个,长度为 2 的 n-1 个,长度为 3 的 n-2 个,...,长度为 n 的 1 个,然后 n+(n-1)+(n-2)+...+1 = ?。
sql 语句: update Books set NumberOfCopies = NumberOfCopies + 1 where AuthorID in select AuthorID from Books group by AuthorID having sum(NumberOfCopies) <= 8 表中数据: BookID Tittle Category NumberOfCopies AuthorID 1 SQL Server 2008 MS 3 1 2 SharePoint 2007 MS 2 2 3 SharePoint 2010 MS 4 2 5 DB2 IBM 10 3 7 SQL Server 2012 MS 6 1
A. 1 B. 2 C. 3 D. 4 E. 5
分析:不多说,SQL 语句执行。
A. 17
B. 18
C. 19
D. 20
E. 21
分析:从前向后找最短路径,先是 A1、A2、A3,然后 B1、B2,其次 C1、C2,最后 T 。
分析:3 个一次可以测出来,3*3 = 9 个以内 2 次,3*3*3 = 27 个以内,3次!所以,有个公式:n 次可以测出来 3^n 以内的假冒伪劣,至于怎么测,方法都一样,平均分成三墩,然后,略。
下面是 me 的分值估计,最佳估计,就是将那些比较肯定的暂时米有发现有问题的,就看成是“完全正确”;大致估计,将有些拿不准的但是现在没有发现错误的,化作“半对”;最坏估计,将某些可能错的(和其他人想法有出入),就化为“错误”,但是比较肯定的还是算做“完全正确”。分值列出来,原来自己的水平就是那样丫!希望尽可能滴接近实际情况:
最佳估计:0 + 3 + 3 + 2 - 2 + 3 + 3 + 0 - 3 + 5 + 3 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 13 + 7 = 72 大致估计:0 + 3 + 2 + 2 - 2 + 3 + 3 + 0 - 3 + 3 + 3 + 5 + 5 + 5 + 3 + 5 + 5 + 5 + 13 + 7 = 67 最差估计:0 + 3 - 2 + 2 - 2 + 3 + 3 + 0 - 3 + 3 - 3 + 5 + 5 + 5 - 3 + 5 + 5 + 5 + 13 + 7 = 51