1-8 3 2 -2 09-18 5 3 -3 019-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 没有标准和正确答案),后面加上题目分析。
- 下面哪些调用转换支持可变长度参数:( 3 分 )
A. cdecl B. stdcall C. pascal D. fastcall
注:me 表示丫梨很大,第一题不会,~~~~(>_<>分析:关于上面的函数修饰符的详细说明,可以看看百度百科。这里也简单说明,cdecl 是 C 语言的调用方式,函数参数从右到左求值,然后入栈,参数由调用方负责清理,传多少参数其实都无所谓的,于是就支持所谓的可变长度的参数;stdcall 是 C++ 的调用方式,参数从右到左求值,入栈,由被调用方处理参数,所以参数个数类型都必须匹配;pascal 是对 PASCAL 函数的调用方式,参数自左向右求值,其他类似于 stdcall;而 fastcall 的情况忽略。
- 下面程序执行结果:( 3 分 )
#include
using namespace std;
class A{
public:
virtual void f() { cout 'A::f() '; }
void f() const { cout 'A::f() const '; }
};
class B : public A
{
public:
void f() { cout 'B::f() '; }
void f() const { cout 'B::f() const '; }
};
void g(const A* a)
{
a->f();
}
int main(int argc, char *argv[])
{
A* p = new B();
p->f();
g(p);
delete(p);
return 0;
}
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 :
int main(int argc, char *argv[])
{
A base = B();
base.f();
g(&base);
return 0;
}
这里的结果会和上面的一样么?!——,实际情况是神马呢,——,不一样!这个时候的结果选 D,理由:多态只能通过指针和引用使用,对象不能使用。说到引用,将上面的代码修改为 A& base = B(); 会怎么样呢?编译错误!引用不能引用临时对象!所以代码只能改为 B b; A& base = b; 比如下面的:
int main(int argc, char *argv[])
{
B b; // B b();
A& base = b;
base.f();
g(&base);
return 0;
}
这个时候程序的结果还是 B。定义 b 的时候,使用上面注释掉的行不行呢?不行,因为那样,编译器会认为 b 是一个函数!!what?!!默认构造对象的时候,() 是不能加的??!!好吧,就是这样。再进一步说,会不会赶脚上面的代码有点“蹩脚”?如果 A a = B(); 就是可以的,然而 A& a = B(); 不可以,而要首先去定义一个 B对象,然后去引用,麻烦!好吧,c++11给 me 们带来了新希望(如果 u 不认为是灾难的话):
int main(int argc, char *argv[])
{
A&& base = B();
base.f();
g(&base);
return 0;
}
这里的结果的答案还是 B。A&& 是右值引用,使得 me 们可以引用到一个临时量 B(); 自此以后那个临时量就归右值引用管了,不再算是临时量。基本到此为止,有点混乱,有点O__O'…。再最后补充一句,少用指针,多用对象和引用!(使用引用的时候,析构函数貌似不需要显式地标注为 virtual,这一点细节有点不清楚,至少编译器对此没有提示。)
- 链表和数组的区别: ( 3 分 )
A. 在有序的情况下搜索
B. 插入和删除
C. 随机访问
D. 数据存储类型分析:ABC 是明显的,有序的情况下数组可以二分查找,而链表不可以;插入和删除,数组不如链表灵活;链表不如数组可以随机访问。D 选项,不敢选,me 数据结构感觉跟存储类型么有必然关系,如果说存储类型指的是栈 (stack) 或是堆 (heap) 的话,数组也可以在堆上分配,链表也可以是静态链表(栈上的空间)。
- Windows 下进程和线程的描述,哪些是对的:( 3 分 )
A. 操作系统的一个程序必须有一个进程,但是不必须有一个线程
B. 进程有自己的栈空间,而线程只共享父进程的栈空间
C. 线程必从属于一个进程
D. 线程可以更改从属的进程分析:最初 me 不确定有些说法,因为题目强调说的是 Windows 下的进程和线程,不过后来翻看了下书,基本确定了某些说法。Windows 中的进程和线程的概念和一般操作系统书中的说法是一致的,进程是资源分配的基本单位,而线程是 CPU 调度的基本单位;一个线程从属于一个进程,当然一个进程可以创建多个线程,一个进程中的多个线程共享进程的栈空间(当然也有其他一些资源);但是每一个线程也可以有自己的栈空间,叫 TLS(线程本地存储);如果一个进程中没有显式地创建一个线程,那么就是所谓的单线程进程,其实也就是 main 执行流对应的线程。这样的话,A、B 是错的,C 是对的,而线程可以更改所属进程,太扯了,错误!补充一点,记得以前看 UNIX 高级编程,貌似有这样的说法:UNIX 系统的进程和线程和前面的说法也基本一致,但是 Linux 却特殊一点,特殊到哪一点呢?似乎没有进程和线程的明确划分,都是线程,只不过有些线程就是共享一些数据(类似于线程共享进程的数据),给人的赶脚就是同属于一个进程;有些线程不同享数据,就如同进程一般有所区分。(这里的说法不一定准确,所以,O__O'…)
- 下面代码段的运行结果:( 3 分 )
#include
int main()
{
int x = 10;
int y = 10;
x = x++;
y = ++y;
printf('%d %d', x, y);
return 0;
}
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 编译器。
- C# 或是 Java 程序段的结果:( 3 分 )
int[][] array
= new int[3][]{ };
array[2][2] 返回神马 ?
A. 9 B. 6 C. 2 D. 溢出
分析:介个,貌似不用多说,跟 C 中的数组有所区分,C 中的二维数组就是相同一维数组的数组,结构比较整齐,而 Java/C# 中的二维数组仅仅是一维数组的数组而已,所以 array[2][2] 这个元素其实不存在,在 Java 中运行会抛出越界异常。(实际上面的代码段不是合法的 Java 代码段,不过意思是那样的。)
- 下面说法哪些正确?( 3 分 )
A. const int a; // a 是常数
B. int const a; // a 是常数
C. int const *a; // a 指向常数的指针
D. const int *a; // a 是常指针
E. int const *a; // a 是常指针分析:关于 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 在其他处定义了。下面的代码段:
int const a = 3;
int const a;
int main(int argc, char *argv[])
{
return 0;
}
c 程序上面是合法程序,c++ 是错误程序!如果 typedef int *PtrInt; 这种情况下 const PtrInt a; a 是常量指针呢,还是指向常量呢?—— 可以自己去尝试一下。(答案:常量指针。)
- 下面程序的执行结果:( 3 分 )
#include
class A{
public:
long a;
};
class B : public A
{
public:
long b;
};
void seta(A* data, int idx)
{
data[idx].a = 2;
}
int main(int argc, char *argv[])
{
B data[4];
for(int i=0; i4; ++i){
data[i].a = 1;
data[i].b = 1;
seta(data, i);
}
for(int i=0; i4; ++i){
std::cout data[i].a data[i].b;
}
return 0;
}
A. 11111111 B. 12121212 C. 11112222 D. 21212121
分析:程序的运行结果是 22221111,这里没有答案!至于答案的分析,应该涉及到 c/c++ 内存对象的布局问题,虽然 me 不大懂,但是还是可以“想当然”滴班门弄斧一下。像上面的类 A,和 c 中的结构体是兼容的,在 c++ 中叫做 POD,结构体中数据布置,应该是按照声明的顺序放置的(中间可能有空隙),所谓名字的访问其实也是根据顺序访问的,看个下面的例子:
#include
struct Test{
int a;
int b;
};
int main(int argc, char *argv[])
{
long long test = 0x1234567887654321;
printf('%x %x', (*(struct Test*)&test).a, (*(struct Test*)&test).b); // 87654321 12345678
return 0;
}
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。
- 1000 个瓶子中有一瓶毒药,一只老鼠吃到毒药一周之内会死,如果要在一周之内检测出有毒药的一瓶,问至少需要几只老鼠?( 5 分 )
A. 9 B. 10 C. 32 D. 999 E. 上面答案都不对分析:当初图样图森破,图拿衣服。老鼠吃过药不会立马死,当时 me 这个重点么抓到,其次,要测出来这瓶毒药至少几只老鼠,me 当时傻×:最少一只吧,比如正好碰巧测出来!~~~~(>_<)~~~~好吧,网上这个题目有很多人已经回答了,10 只老鼠,因为每只老鼠的死亡状态可能有="" 2="" 种,10="" 只的话,可以拼凑出="" 2="" ^="" 10="1024" 种状态,也就是="" 1024="">)~~~~好吧,网上这个题目有很多人已经回答了,10>
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 表示不吃。)
- 在 C 语言中下面那个语句的结果是 1 ?( 5 分 )
A. main 函数正常结束的返回值
B. return 7&1;
C. char *p='hello'; return p == 'hello';
D. return 'hello' == 'hello';
E. 上面都不对分析:A 一定是错的,C/C++ main 函数正常结束,返回 0;B 一定是对的,C 和 D 呢?标准 C 规定是,同样两个字符串字面量,比如 'hello',内存是放一份还是两份,由编译器决定!所以,C 和 D 的结果,一般的编译器应该会有警告提示,说明是 undefined behaviour !(前面第 2 题和第 5 题,也有遇到过!) 所以,C 和 D 只能说很可能是对的,但是却不一定!
- F、G、X 都是32位有符号整数,F=X/2,G=X>>1,如果 F != G,那么:( 5 分 )
A. 编译错误
B. X 是奇数
C. X 是负数
D. F-G=1
E. G-F=1分析:前面第 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'…
- 3*4 的方格,有多少个长方形?( 5 分 )
A. 18
B. 20
C. 40
D. 60
E. 上面都不对分析:高中数学题目,O__O'…(本来想解释一下的,但是赶脚么必要丫,公式 C(2,4) * C(2,5) = 6*10 = 60,横向取 2 条线,纵向取 2 条线,就是一个长方形。)
- 一个直线将一个平面分成 2 部分,两条直线分成 4 部分,如果直线不平行,多条直线不共一点,问 100 条直线将平面分成几部分?( 5 分 )
A. 5051
B. 5053
C. 5510
D. 5511分析:小学数学题目,O__O'…(公式:1+1+2+3+4+...+n=1+(n+1)n/2 = 1+5050 = 5051)
- 下面哪些是稳定排序:( 5 分 )
A. 冒泡儿排序
B. 快速排序
C. 堆排序
D. 归并排序
E. 选择排序分析:略。
- Web 应用程序中常使用 MVC 模式,关于说法下面哪些是对的?( 5 分 )
A. 模型 ( Model )表示数据以及处理数据的业务逻辑
B. 视图 ( View ) 是对模型的(可视化)展示,它渲染模型的结果,典型的是一个用户接口元素(user interface element)
C. 控制器介于用户和系统之间,它接受用户的输入,指挥着模型和视图来完成输入对应的任务
D. MVC 的常用实践是,模型从用户接收 GET 和 POST 的请求,然后决定做神马,通过移交给控制器和视图
E. 上面都不对分析:MVC 貌似就是 ABC 的说法。
- 根据下面哪些可以确定一棵二叉树?( 5 分 )
A. 前序遍历和中序遍历
B. 前序遍历和后序遍历
C. 中序遍历和后序遍历
D. 后序遍历分析:至少要一个中序遍历,前序+后序遍历不中。
- n 个字符构成的字符串,假设每个字符都不一样,问有多少个子串?( 5 分 )
A. n+1
B. n^2
C. n(n+1)/2
D. 2^n-1
E. n!分析:介个,貌似也简单,长度为 1 的字符串 n 个,长度为 2 的 n-1 个,长度为 3 的 n-2 个,...,长度为 n 的 1 个,然后 n+(n-1)+(n-2)+...+1 = ?。
- 根据下面给的表和 SQL 语句,问执行 SQL 语句更新多少条数据?( 5 分 )
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="" authorid1="" sql="" server="" 2008="" ms="" 3="" 12="" sharepoint="" 2007="" ms="" 2="" 23="" sharepoint="" 2010="" ms="" 4="" 25="" db2="" ibm="" 10="" 37="" sql="" server="" 2012="" ms="" 6="">=>
A. 1 B. 2 C. 3 D. 4 E. 5
分析:不多说,SQL 语句执行。
- 下图中从 S 到 T 的最短路径是多少?(边上是连接点的长度):( 13 分 )
A. 17
B. 18
C. 19
D. 20
E. 21
分析:从前向后找最短路径,先是 A1、A2、A3,然后 B1、B2,其次 C1、C2,最后 T 。
- N个球中有一个假冒伪劣(重量不足),如果给你一个天平允许你测 3 次找出那个假冒伪劣,问 N 可能的值?( 13 分 )
A. 12
B. 16.
C. 20
D. 24
E. 28分析: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