腾讯2013年实习生笔试题目

一、选择题

1、32位机上根据下面的代码,问哪些说法是正确的?()

signed char a = 0xe0;
unsigned int b = a;
unsigned char c = a;

A. a>0 && c>0 为真
B. a == c 为真
C. b 的十六进制表示是:0xffffffe0
D.上面都不对

考点:有符号数和无符号数之间的转换

解析:

  • 0xe0转换成二进制是1110 0000,因为0xe0的最高位是1,所以作为有符号数的时候就是负数,作为无符号数的时候就是正数,因此A选项是错的,同时B也是错误的。
  • 负数的高位用1补齐,正数的高位用0补齐,所以b(0xe0)的二进制表示形式是1111 1111 1111 1111 1111 1111 1110 0000,十六进制的表示形式是0xffffffe0

2、下面哪些选项能编译通过()?

int i;
char a[10]; 
string f(); 
string g(string &str);

A. if(!!i){f();}
B. g(f());
C. a=a+1;
D. g("abc");

考点:C++的细节掌握。

解析:

  • A是肯定对的,因为他有一个默认值。
  • B选项是错误的。因为f() 返回的是一个临时量,然后传给 g 函数,而 g 的参数不是const 引用,是不能引用临时量的。
  • C选项是错误的。因为a 是一个地址常量,不可能再被赋值。
  • D选项是错误的。因为"abc" 的类型可是 const char* 呢,是个常量指针(可以用来初始化 string)。

3、int a[10]; 问下面哪些不可以表示 a[1] 的地址?

A. a+sizeof(int)
B. &a[0]+1
C. (int*)&a+1
D. (int*)((char*)&a+sizeof(int))

考点:C++数组的指针表示形式的掌握

解析:

  • A. a+sizeof(int) 选项不正确,假设在32位机器上,sizeof(int)的值为4,而a+sizeof(int) 相当于指针运算 a + 4,也就是a[4]
  • B. &a[0]+1选项正确,因为 &a[0]的意思是取的数组首元素地址,而数组首元素地址加1(a + 1),根据指针运算就是a[1]的地址
  • C. (int*)&a+1选项正确,因为数组地址被强制类型转换为int*,然后加1,这样和B表示的一个意思
  • D.(int*)((char*)&a+sizeof(int))选项正确,因为数据地址先被转换为char*,然后加4,根据指针运算公式,向前移动4 * sizeof(char),之后被转换为int*,显然是a[1]的地址

4、问下面的数据都存放在哪些存储区?

int main()
{
    char *p = "hello,world";
    return 0;
}

A. 堆和静态数据区
B. 栈和静态数据区
C. 栈和常量区
D. 栈和堆

解析:其实,在做这一题的时候,我是当成Java来做的,呵呵

  • 根据C语言中的特性和定义p是一个局部变量,而C语言中局部变量存在于栈中,"hello wrold"是一个字符串字面常量,因此存储于程序的只读存储区中,p在这里其实只是指向了"hello wrold"在只读存储区中的地址而已

5、下面哪些说法正确?()
A. 数组和链表都可以随机访问
B. 数组的插入和删除可以 O(1)
C. 哈希表没有办法做范围检查
D. 以上说法都不正确

解析:

  • A选项是错误的,因为数组可以直接通过下标得到存储的值 因此支持随机;而访问链表是链式存储结构时无法支持随机访问,要访问一个指定位置的元素必须从头开始做指针移动
  • B选项是正确的,因为数组的插入如果位置在最后面的话可以为O(1),删除的时候,直接通过下标指定要删除哪个即可,所以也可以为O(1)
  • C选项是错误的,因为哈希表支持直接通过关键码得到值 其实数组就是一种哈希表 下标就是关键码 通过下标直接得到值 因此哈希表肯定需要做范围检查也有办法做范围检查的
  • D选项是错误的,这个不用解释啦

6、基于比较的排序的时间复杂度下限是多少?()
A. O(n)
B. O(n^2)
C. O(nlogn)
D. O(1)

解析:其实大家记住这个结论就好,在当前计算机科学界对于基于比较的排序最快只是O(n*logn),例如快速排序,堆排序,归并排序

7、有两个线程,最初 n=0,一个线程执行 n++; n++; 另一个执行 n+=2; 问,最后可能的 n 值?()

A. 1
B. 2
C. 3
D. 4

解析:大家要知道 C语言中的 ++ 和 += 并不是原子操作,而是通过多条微程序组成的,因此 ++ 和 += 在执行过程中可能被中断的

  • 第一种可能情况:现在假设两个线程没有并行顺序执行的那么结果显然是 4。
  • 第二种可能情况:再假设现在第一个n++ 已经执行完了  但是结果还没有写回内存 这个时候 n+=2 已经全部执行完 2 写进了内存 结束 然后回到n++的写回操作 这个时候内存就从2被改回1了,后面再来一次n++  结果就为2。
  • 第三种可能情况: 第n+=2 先读取n的值到寄存器 即0入寄存器 这个时候被中断   第一个n++开始执行 并直到结束 内存被改成了1 ,然后 n+=2 继续执行 结束后内存变为2  第二个n++再执行 结果就是3了
  • 我个人看了网上的这个解析后也觉得,肯定不可能为1了。

8、下面哪些函数调用必须进入内核才能完成?()

A. fopen
B. exit
C. memcpy
D. strlen

解析:

  • fopen是打开文件的函数,文件也可以看成是一个设备,打开一个设备将导致给设备所属的驱动程序发送一个IRP,而与真实硬件相关的驱动程序都运行于内核
  • exit函数是结束进程的函数,结束进程需要访问PCB(进程控制块)和TCB(线程控制块)等等一些数据结构,而这些数据都存在于内核中
  • memcpy 和 strlen 我们可以直接不调用任意函数写出来这种函数肯定不会实现在内核的
  • 关于memcpy函数,详情可以查看百度百科的解释(地址是:http://baike.baidu.com/view/736225.htm)

9、死锁发生的必要条件?()

A. 互斥条件
B. 请求和保持
C. 不可剥夺
D. 循环等待

考点:操作系统

解析:互斥条件,请求和保持,不可剥夺 ,循环等待,这些都可能导致发生死锁,所以以后大家在做多线程程序时一定要注意了。

10、内存管理中的 LRU 方法是用来管理什么的?()

A. 虚拟内存的分配
B. 虚拟内存的释放
C. 物理内存的分配
D. 物理内存的释放

考点:操作系统

解析:大家自己看书,我大概说下基本的。

1.页面调入:是给页面调入内存中,给它分配物理内存

2.页面置换,就是将内存中的页面置换出来,放到虚拟内存中,让物理内存空闲出来,让给需要使用的页面。

3.LRU:全称是:Least Recently Used(最近最久未使用)置换算法,所以这个算法涉及到了虚拟内存的分配和物理内存的释放。所以答案是AD。

11、求N个数中的最大值和最小值,最小比较次数是多少?

A 4n/3
B 2n-2
C n-1
D 3n/2

分析:解析:在编程之美上看过,利用分治思想

 12、一棵二叉树的先序遍历是 f b a c d e g h,中序遍历是 a b d c e f g h,问后序遍历是什么

答案:adecbhgf

解析:根据先序遍历和中序遍历,我们可以构建一颗二叉树:

13、在32位little endian机器上运行该程序,得到结果是什么? 

#include <stdio.h>
int main()
{
    long long a = 1, b = 2, c = 3;
    printf("%d %d %d 
", a, b, c);
    return 0;
}

A.1 2 3
B 1 0 2
C ......
D 3 2 1

解析:因为long long 是8个字节的,%d是4个字节的,溢出覆盖了后面,然后又是小端规则的。

【传入参数,由右往左,栈空间内存从高往低,little endian, 栈空间如下:
内存高位->
00000000       00000011
00000000      [00000010](c)
[00000000](b) [00000001](a)
<-内存低位

14、关于访问,下面哪些是后台绝对不会执行的?

A. 本地查查 DNS,是否有 sinaapp.com 的 ip;
B. 通过 cn. 查找 ip;
C. 通过 com. 查找 ip;
D. 浏览器发送 http get 请求;
E. 服务器回送 xxx.jpg;

15、高内聚和低耦合,下面哪个耦合度最高?
A. 通过函数参数传递...
B. 一个函数修改另外一个函数中的数据;
C. 通过全局变量...
D. 通过指示器...

解析:

  • 内聚就是一个模块内各个元素彼此结合的紧密程度,高内聚就是一个模块内各个元素彼此结合的紧密程度高。所谓高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则。
  • 耦合:一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。) 对于低耦合,粗浅的理解是:一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。模块与模块之间的接口,尽量的少而简单。如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。这样有利于修改和组合.

16、TCP协议栈的定时器有哪些()
A....
B....
C....
D....

解析:百度了一下,TCP协议栈的定时器有延时定时器,重传定时器,坚持定时器,保活定时器

17、网卡,交换机,路由器和UDP分别工作网络的哪些层?

答案:依次是:物理层,链路层,传输层

二、填空题

1、在一个 big endian 的 32 位的计算机上,b 的结果是______

unsigned int a = 0x1234;
char b = *((char*)&a);

答案:0

解析:unsigned int是 4 个字节,0x1234 的完整表示是 0x 00 00 12 34,因为是 big endian,所以,所以 &(取地址) 的话,如果当字节看的话,取到了最左边 00 字节的地址,一定要转换成 char 看的话,值就是 0。

2、一个有 800 个结点的完全二叉树,问有_____个叶子结点?

答案:400

解析:画图举例子很容易就可以推导出规律,通过这个公式即可计算得400

3、下面 get 是求一个二维数组元素的函数,请补全.

#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 4
 
int get(int *a, int i, int j)
{

   _______ // 此处一个空

} 
int main() 
{
    int a[M][N] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    int v; 
    v = get(a, 2, 1); 
    printf("a[2][1] == %d
", v ); 
    return 0; 
}

答案:return *(a+i*N+j);

解析:大家注意原型中的指针是int* a,所以必须用二维数组在内存中是一维排布这个知识点来做,直接 return *(a+i*N+j);而不是 return *(*(a+i)+j);

4、补全插入排序:

#include <stdio.h>
#include <stdlib.h>
int insert_sort(int *p, int count)
{
    int i, j, tmp;
    if(p == NULL || count < 0) return 0;    //
    for(i=1; i<count; i++){
        tmp = p[i];
        j = i-1;
        while(__________){ // 此处一个空
            p[j+1] = p[j];
            --j;
        }
       ___________;   // 此处一个空
    }
    return 1;
}
int main()
{
    int i, a[10 = {3, 2, 1, 7, 8, 10, 4, 5, 6, 9};
    insert_sort(a, 10);
    for(i=0; i<10; i++)
        printf("%d ", a[i);
    printf("
");
    return 0;
}

答案:第一个空: j>=0 && p[j]>tmp  第二个空:p[j+1] = tmp;

5、使用 FIFO 管理页面请求,如果分配的物理块 M = 3 或是 4,请求顺序如下:4 3 2 4 4 3 5 4 5 3 1 5 1 5 1 5 4,问两种情况下页面失效的次数各是________和__________?

答案是9和6,

考点:操作系统
解析:M=3时:一开始是空的,所以4,3,2都页面失效。失效三次,然后4,4,3都有效,5失效一次,4先进来的所以先出去,变为3,2,5,然后4又失效一次,3出去,变为2,5,4,以此类推。就是先进来的先出去。最后加起来一共9次。M=4的也一样。只是能多存一个页。

6、软件可靠性评估的两个指标是___________和_____________?

答案:无错运行概率,平均故障时间

原文地址:https://www.cnblogs.com/sooner/p/3253105.html