C C++ 常被人问的问题分析

正文  -  开始了, 直接扯淡

  以下都是自己面试中遇到的常见的问题.如有不妥的地方就当见笑了. 哈哈

 宝剑索引

1. 谈谈你们服务器的架构吧.

分析:

  假如这是第一个问题, 你可以走了. 可能各方面原因他不想要你. 或者其它意外已经有人更适合了. 

或者只是为了学一点东西.哈哈.一般面试游戏服务器开发的时候,这方面一定会问的. 关于游戏服务器架构,

需要自己努力积累是硬功夫.没有个100页doc难搞下来.且不同公司架构还是很不一样.

只是为了应对面试,可以参照

   MMORPG服务器架构  http://www.blogjava.net/landon/archive/2012/07/14/383092.html

   云风的 BLOG http://blog.codingnow.com/

至少可以简单扯一点, 对吧.通常这个问题决定你最终资格,极其重要, 也是咱们干程序的一定要积累的.

 

2. 有时候也会问,项目组正在开发中问题. 因公司而异.

例如怎么设计跨服对战的业务, 怎么设计一个棋牌的随机排序算法.

分析: 

  1)对于跨服对战, 当初是个卡牌战斗类, 简单些. 按照老套路

    a) 每个服前10名, 特定时间报名

    b) 按照服务器id,玩家id 构建一个新服

    c) 参照老套路了, 有了新服对战开始了...

  2) 对于棋牌的随机算法, 基本都是一个傻大哈方法

//
//    简单棋牌随机算法
//  chess    : 存放棋牌的数组
//    len        : 棋牌处理长度
//
void chess_rand(char chess[], int len) {
    if (!chess || len < 2)
        return;
    
    for (int i = 0; i < len; ++i) {
        int j = rand() % len;
        if (i != j) {
            char c = chess[i];
            chess[i] = chess[j];
            chess[j] = c;
        }
    }
}

具体就是你做过就按照你做过的思路说, 没做过就按照自己思路实诚一点说. 哈哈

 

3. 用过什么数据, 什么数据库引擎,优化什么的扯个淡.

分析:

  一般都是mysql, 问几个简单的sql查询.然后问innodb 和 myisam 区别.

  MyISAM和InnoDB的区别 

  Mysql几种索引类型的区别及适用情况

其实现在开发我觉得从C++ 软件开发层面. mysql没有mariadb优势大, 高级层面的优化交给数据库开发者. 业务层开发也就是索引等等.

到这里有时候会细问DB Server 设计. 缓存服务器设计等. 因公司业务不同, 说一说完全可以.

  高并发服务器的设计--缓存的设

  想在C++游戏服务器中实现热更,数据缓存要如何做呢?

也能扯个半天.

 

4. 那开始扯除了架构之外最重要的了, 多线程设计了.

分析:

  首先一般面试官会这样开头, 啊, 那线程和进程的异同是啥呀?这东西常问, 不管是应届菜鸟还是老油条.

因为面试官多数问自己以前被别人问的, 可以参照知乎上讨论, 基本都理解了, 可以来回扯了.

  线程和进程的区别是什么?

当然这只是个开头,有时候会让你现场写代码. 那就需要自己回顾 pthread POSIX 那套了. 当然遇到必须手写的话, 说明那个人也是为难你.

你也可以放心了. 后面愉快自然些. 他也许还没你懂得多. 详细的可以理解下面知识.

  [转]关于多线程并发:每个开发人员都应了解的内容

其实关于线程真实工作中, 实战经验为零. 最扯淡的是, 会说的不一定会写, 会写的难说. 仍然推荐可以看看 云风 的 github,

上面多线程代码不少. 还有就是POSIX 多线程那本书特别经典.很给力.

分享个多个线程顺序循环执行的代码, 哈哈如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

// 测试线程数量
#define _INT_THS    (3)

struct threadarg {
    pthread_t tids[_INT_THS];
    sem_t sids[_INT_THS];
};

// 简单运行函数
static void * _run(void * arg) {
    int i = -1, j = -1;
    struct threadarg * ths = arg;
    pthread_t tid = pthread_self();
    pthread_detach(tid);

    // 确定这是第几个线程
    while (++i < _INT_THS)
        if (pthread_equal(tid, ths->tids[i]))
            break;
    
    // 循环个特定遍数就结束吧
    while (++j < _INT_THS) {
        // 第 i 个线程, 等待 第 i - 1 个线程, 输出 'A' + i 
        sem_wait(ths->sids + (i - 1 + _INT_THS) % _INT_THS);
        putchar('A' + i);
        // 第 i 个线程, 激活 第 i 个信号量
        sem_post(ths->sids + i);
    }

    return NULL;
}

//
// 写个测试线程信号量代码
// 开启 _INT_THS 个线程, 顺序打印数据 A->B->C->...->A->B->....
//
void test_pthread_sem(void) {
    // 开始初始化了
    int i, j;
    struct threadarg targ;
    
    // 先初始化信号量,后初始化线程
    for (i = 0; i < _INT_THS; ++i) {
        // 0 : 表示局部信号量当前可用; 0 : 当前信号量值为0
        if (sem_init(targ.sids + i, 0, 0) < 0)
            goto __for_exit;
    }

    // 开启线程
    for (j = 0; j < _INT_THS; ++j) {
        // 开启三个线程
        if (pthread_create(targ.tids + j, NULL, _run, &targ) < 0)
            goto __for_exit;
    }

    // 激活第一个线程, 输出 'A' 开头
    sem_post(targ.sids + _INT_THS - 1);

    // 中间等待一些时间吧
    getchar();

__for_exit:
    // 注意的是, 假如信号量释放了, 线程还在跑, 会异常
    for (j = 0; j < i; ++j)
        sem_destroy(targ.sids + j);
#ifdef __GNUC__
    exit(EXIT_SUCCESS);
#endif
}

编译指令是

test_pthread_sem.exe:test_pthread_sem.c
    gcc -g -Wall --entry=$(basename $@) -nostartfiles -o $@ $^ -lpthread

后面也可以参照下面链接学习一下.

   信号量与条件变量的区别

 

5. 那再一次到语法基础部分了. C++各种语法妖魔来了. 哈哈

存在这样一个情况. 一个函数玩家new了个对象. 但是忘记delete了.直接return了,怎么搞别内存泄漏.

分析:

  其实这类C++问题, 在C++最经典的书籍中都有解释. 一般人会回答用智能指针. 这时候面试官和蔼的告诉你不行.

你sb了. 那怎么搞哈哈. 如果做过很简单,没做过就xxx了. 其实这时候面试官希望你自己实现个简单的智能指针. 其实这个

很好搞, 本质就是C++栈上变量在函数返回时候会退栈,执行变量析构函数.其实再扯一点,这种特性本质就是编译器在编译的时候

,帮我们插入了这些构建和清理的代码而以. 一个简单的代码如下:

template<typename T> class AutoPtr {
    T * _ptr;
public:
    explicit AutoPtr(T * ptr) {
        _ptr = ptr;
    }

    ~AutoPtr(void) {
        delete _ptr;
    }

    T & operator*() {
        return *_ptr;
    }

    T * operator->() {
        return _ptr;
    }
};

用法也特别简单

    class People { };
    AutoPtr<People> ptr(new People());

到这里就各种妖魔鬼怪出来. 例如会继续问placement new 的用法. 呵呵, 各种奇葩问题来了.

  C++ 中为什么没有placement delete

参照上面资料看的挺有意思.一般而言 placement new 用在指定对象分配上.

#define _INT_XX (108)
char
xx[_INT_XX]; T * p = new(xx) T;

当然还有更加奇葩的在构造函数和析构函数中抛出异常. 这种问题面试一问基本上基础部分就接近尾声了. 能扯个30min吧.

  构造函数、析构函数抛出异常的问题

  关于构造函数 和 析构函数 能否抛出异常的讨论

说白了, C++ 的 new 和 delete 还是很有搞头的 O(∩_∩)O哈哈~  ┻┳|・ω・)问我?

 

6. 又是最简单的虚函数了, 必问. 直接搞起吧.

  虚函数virtual可以说是C++面向对象的所有. 面试时必问的基础中的基础.(✪ω✪) 让我们来剖析其中的秘密吧.  

virutal虚函数围绕本质在于编译器帮我们在类中插入了 __vfptr 变量. 例如下面例子.

以上就是虚函数实现原理.通过汇编好实现.通过纯C++实现有点难搞, 需要记住类型.

 

7. 那到了STL部分了,也是常有的. 搞一搞吧.

  STL是必问的,其实问的都很简单. 多数是看看下面STL代码是够有问题. 奥, 常见的有各种容易的区别.

回答的时候需要抓住迭代器特点. 存储结构特点. 例如只有vector和deque是顺序存储并且支持随机迭代器的.

有的会问怎么删除vector中是偶数的迭代器. 手写代码.

    int i = 0;
    std::vector<int> vs;
    std::vector<int>::iterator it = vs.begin();
    while (it != vs.end()) {
        if (++i % 2 == 0)
            it = vs.erase(it);
        else
            ++it;
    }

主要是注意一下迭代器失效的情况.

  C++STL常见面试题

后面扯扯C++11方面知识. 其实哈哈, 都C++17了, 还11. 说白了高级程序员,

高级的地方不在于功底, 不在于能力, 最重要的是业务熟悉度, 和当前公司的业务匹配度.

 

8. TCP 和 epoll 出现了. 其实也很简单.

  网络这块也是逃不掉的.什么四次分手, 3次握手是必须的.

   TCP相关面试题总结

  TCP滑动窗口控制流量的原理

这里TCP搞完了, 那开始问select, epoll 什么的. 可以了开始考验你api 和 内核的理解了

  linux下epoll如何实现高效处理百万句柄的

   epoll 底层实现源码分析

  epoll实现机制分析

套路都差不多. 多总结总结, 这里面试官一问能扯个5-10min吧. 毕竟除了老一辈的程序员功底好些.

新的对于这些也只是 -->  "编程5min扯淡2h" ! O(∩_∩)O哈哈~  关于epoll 实际用法可以参照我的下面博文

  C高级 服务器内核分析和构建 (一)  

 

后记 - 新的开始, 哈哈

   以上就是老鸟找工作必问的问题, 深入的扯能够扯好久.... 错误是难免的, 欢迎指正, 共同提高~~~

   虚虚实实  http://music.163.com/#/m/song?id=189433&userid=16529894

  

                   人生没有重来, 贪婪有何不可  -|-  对不起我的兄弟和我的妹子

 

posted on 2017-04-09 11:52  喜ω欢  阅读(607)  评论(0编辑  收藏  举报