学习啦>创业指南>职场>笔试题>

程序员面试笔试宝典

时间: 护托1061 分享

  程序员(英文Programmer)是从事程序开发、维护的专业人员。一般将程序员分为程序设计人员和程序编码人员,但两者的界限并不非常清楚,特别是在中国。下面就由学习啦小编为大家介绍一下程序员面试笔试宝典的文章,欢迎阅读。

  程序员面试笔试宝典篇1

  1.extern的作用

  自己理解:应该需要区分extern在C语言中和C++语言中的作用,C语言中extern声明的函数和变量可以被该文件外部模块引用,C++语言中除了该作用还可以声明extern “C”声明一段代码编译连接的方法为C语言的方法。

  参考:其实extern的百度词条解释的很清楚,具体的也是跟我上面自己理解差别不是很大。

  (a) extern是C/C++语言中声明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量在本模块或其他模块中使用(通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。)

  (b) 被extern “C”修饰的变量和函数是按照C语言的方式编译和链接的。(C语言不支持函数重载,所以函数的C++和C的编译方式不同,这一句的作用就是实现C++和C及其他语言混合编程)

  2.strstr()函数的作用

  strstr()函数的原型一般为extern char * strstr(const char *src , const char *dest) , 其作用就是寻找目标字符串在源字符串中第一次出现的位置。

  3.windows线程优先级问题( 进程和线程的区别和联系 )

  我觉得这个概念可能面试、笔试的时候不是很适合,毕竟平台相关,大多数公司可能更多的倾向于linux开发,这个问题更换为进程和线程的区别更好,这个是笔试,面试常见的知识考查。

  (a) 通常一个进程可以包含若干个线程,它们可以利用进程所拥有的资源。进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈),线程可与同属于一个进程的其他线程共享进程所拥有的全部资源。

  线程和进程区别归纳:

  地址空间和其他资源:进程间互相独立,同一个进程的各线程共享。

  通信:进程间通信IPC,线程间可以直接读写进程序数据段(如全局变量)来进行通信-需要进行同步和互斥的辅助。

  调度和切换:线程上下文切换比进程上下文切换快速,高效。

  多线程的OS中,进程不是一个可执行的实体。

  4.多方法交换x与y的值

  5.指针的自加与引用

  6.前置++与后置++

  前置++和后置++我觉得一个比较重要的问题是C++中重载两个操作符的时候如何区别:区分前置和后置 函数的参数有一个 (函数重载),后置++有一个(int)参数。

  7.inline的作用

  inline函数不像正常函数在调用时存在压栈和call的操作,它会把程序代码直接嵌入到调用代码段中,也就是说使用inline函数会增大二进制程序的体积,但是会使执行速度加快。

  同时,编译期间可以对参数进行强类型的检查,这是inline优于宏的一个方面。

  8.二维数组的表示

  9.ifndef的作用

  条件编译的语法,一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。

  10.KMP算法

  字符串匹配的高级算法

  程序员面试笔试宝典篇2

  1.函数调用方式

  __cdecl 堆栈由调用者清除 参数从右至左的顺序压入堆栈内

  __stdcall 堆栈由被调用者清除 参数从右至左的顺序压入堆栈内

  __fastcall 堆栈由被调用者清除 部分参数保存在寄存器中,然后其他的压入堆栈内

  thiscall(非关键字) 堆栈由被调用者清除 参数压入堆栈内,this指针保存在ECX寄存器内

  2.重载函数

  函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。不能利用返回类型进行重载!类中函数const和非const可以进行重载,其实原理是利用this指针的类型是const和非const进行重载,其实原理就是参数类型不同,const指针orconst引用调用的为const版本的函数~更多函数重载的知识。

  3.构造函数和析构函数

  虚拟析构函数的使用场景是指向父类的指针实则为子类指针,调用delete的时候使用虚拟析构函数,防止部分内存泄露。

  构造函数不能声明为虚拟函数,因为对象的虚拟函数表的指针其实是在构造函数内编译器添加完成的代码,所以在构造函数执行之前无法访问到虚拟函数表的。

  4.合并两个有序链表

  类似归并排序,两个指针归并即可。

  5.100亿条记录的文本文件,取出重复数最多的前10条

  类似top k算法,无法全部读入内存的top k算法是利用容量为k的最大堆,达到线性时间的top k算法。

  首先利用hash table预处理每个元素出现的次数,然后利用次数执行top k算法。

  6.设计一个双向链表,并且提供一个可根据值删除元素的函数

  STL中的list底层及为双链表实现。

  7.二叉树的多种遍历算法实现

  8.有读和写的两个线程和一个队列,读线程从队列中读数据,写线程往队列中写数据

  生产者和消费者模型:

  使用信号灯和互斥量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
semaphore mutex = 1;
semaphore fillCount = 0;
semaphore emptyCount = BUFFER_SIZE;
 
procedure producer() {
    while(true) {
        item = produceItem();
        down(emptyCount);
            down(mutex);
                putItemIntoBuffer(item);
            up(mutex);
        up(fillCount);
    }
}
procedure consumer() {
    while(true) {
        down(fillCount);
            down(mutex);
                item = removeItemFromBuffer();
            up(mutex);
        up(emptyCount);
        consumeItem(item);
    }
}

  不使用信号灯和互斥量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
volatile unsigned int produceCount, consumeCount;
TokenType buffer[BUFFER_SIZE];
 
void producer(void) {
    while (1) {
        while (produceCount - consumeCount == BUFFER_SIZE)
            sched_yield(); // 缓冲区满
 
        buffer[produceCount % BUFFER_SIZE] = produceToken();
        produceCount += 1;
    }
}
 
void consumer(void) {
    while (1) {
        while (produceCount - consumeCount == 0)
           sched_yield(); // 缓冲区空
 
        consumeToken( buffer[consumeCount % BUFFER_SIZE]);
        consumeCount += 1;
    }
}

  9.stack,heap,memory-pool

  10.TCP的流量控制和拥塞控制机制

  TCP的流量控制就是让发送方的发送速率不要太快,让接收方来得及接收。利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。TCP的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。

  所谓的拥塞控制为防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制索要做的都有一个前提,就是网络能承受现有的网络负荷。流量控制往往指点对点通信量的控制,是一个端到端的问题。因特网建议标准RFC2581定义了进行拥塞控制的四种算法,即慢开始(Slow-start),拥塞避免(Congestion Avoidance)快重传(Fast Restrangsmit)和快回复(Fast Recovery)。

  程序员面试笔试宝典篇3

  1.写一个函数,返回一个字符串中只出现一次的第一个字符

  目前想到的方法就是利用hash表记录每个字符出现的次数,然后两次遍历即可找到只出现一次的第一个字符。

  2.求一个数组中第k大的数的位置

  3.面向对象继承,多态问题,如多态的实现机制

  虚拟函数,指针and引用

  4.内联函数什么时候不展开

  在内联函数内不允许用循环语句和开关语句。 如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。

  5.成员函数初始化列表有什么作用?什么必须在成员初始化列表中进行初始化?

  类的static变量在类的构造函数前已进行初始化!

  类对象的构造顺序:

  (a)分配内存,调用构造函数时,隐式/显式的初始化各数据成员(顺序和类中声明对象一致)。如果无成员初始化列表。隐式初始化阶段按照声明的顺序依次调用所有基类的缺省构造函数,然后所有成员类对象的缺省构造函数。

  (b)进入构造函数执行函数体内语句,函数体内的数据成员的设置被认为赋值,而不是初始化。

  所以,使用初始化列表的两个情况:

  1)必须使用初始化列表进行初始化![1]数据成员为类对象并且该类对象仅提供带参数的构造函数[2]const修饰的数据成员[3]引用数据成员;

  2)考虑效率的时候!因为未利用初始化列表而是在构造函数体内进行赋值,则调用了缺省构造函数和赋值运算符操作。如果数据成员为自定义的类对象,则效率比直接利用构造函数初始化低很多。

  6.指针与引用的区别

  相同点:

  都是地址的概念;指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

  不同点:

  指针是一个实体,而引用仅是个别名

  引用只能并且必须在定义时被初始化一次,之后不可变(类似常量指针,引用自带常量指针属性);指针可变;

  引用没有const,指针有const,const的指针不能够改变;(int & const refer 不存在,因为引用本身就初始化一次不可变,但是const int &refer是存在的,指引用所指向的值不可改变)

  引用不能为空,指针可以为空

  sizeof针对指针得到的是指针的大小,针对引用得到的是指向对象的大小;

  指针的++操作和引用的++操作完全不同,指针为移动指针地址,引用++操作作用于指向的对象;

  引用是类型安全的,而指针不是类型安全的。

  7.创建空类时,哪些成员函数是系统默认的?

  构造函数,拷贝构造,赋值函数,析构函数,取址运算符,const取址运算符

  8.有10W个IP段,这些IP段之间都不重合,随便给定一个IP,求出属于哪个IP段

  9.网络编程(网络编程范式,非阻塞connect)

  常见的IO模型有阻塞、非阻塞、IO多路复用、异步。

3172086