• 常见问题总结


    C++

    1. 实现memcpy, strcpy

    如果目标地址大于源地址,先拷贝高位源地址;
    如果目标地址小于源地址,先拷贝低位源地址。
    memcpy基本原则
     1 void mymemcpy(void* dst, const void* src, size_t num) {
     2     assert(src != NULL && dst != NULL); 
     3     const char* psrc = (const char*)src; 
     4     char* pdst = (char*) dst;
     5     if (pdst > psrc && pdst < psrc + num) {
     6         psrc = psrc + num - 1;
     7         pdst = pdst + num - 1;
     8         while (num--)
     9             *pdst-- = *psrc--;
    10         }
    11     } else {
    12         while (num--) {
    13             *pdst++ = *psrc++;
    14         }
    15     }
    16 }
    17 
    18 /*
    19     易错点:
    20 1. 函数接口:用void*比较通用一些;而且,src要加上const。
    21 2. 判空是个很重要的考察点!这里用assert实现;
    22 3. 下面对指针从void*转换到char* 和const char*;
    23 4. 如果对size_t进行操作时一定要注意,size_t是unsigned,它降到0之后再减一就变成INT_MAX了,可不是-1!
    24 */
    mymemcpy

    follow up:如何优化?

    默认的memcpy是逐字节拷贝;
    优化方法是,不用一个字节一个字节的拷贝;
    可以多字节拷贝,或者整块的拷贝,也可以是用int指针拷贝(一个int占4字节)。
    如果用int指针拷贝,需要分别计算一下
    
    wordNum = num / 4; 
    slice = num % 4;
    优化

    拓展:strcpy等一系列经典函数实现   ref       ref2        ref3       ref4

    除了memcpy外,其他函数在实现时可以不用考虑内存覆盖问题。具体可以和interviewer沟通。

     1 char* strcpy(char* dst, const char* src) {
     2     assert(dst != NULL && src != NULL);
     3     char* pdst = dst;
     4     const char* psrc = src;
     5     while (*psrc != '') {
     6         *pdst++ = *psrc++;
     7     }
     8     *pdst = '';
     9     return dst;
    10 }
    strcpy(未考虑内存覆盖)
     1 char* mystrcpy(char* dst, const char* src) {
     2     assert(dst != NULL && src != NULL);
     3     int size = strlen(src) + 1; //
     4     const char* psrc = src;
     5     char* pdst = dst;
     6     if (psrc < pdst && psrc + size > pdst) {
     7         psrc += size - 1;
     8         pdst += size - 1;
     9         while (size--) {
    10             *pdst-- = *psrc--;
    11         }
    12     } else {
    13         while (size--)     {
    14             *pdst++ = *psrc++;
    15         }
    16     }
    17     return dst;
    18 }
    19 
    20 /*
    21     需要注意的是,计算size时应该在strlen(src)基础上+1,因为要把字符串末尾的''计算进去。
    22     有返回值的原因,是为了支持链式表达式,比如:
    23     int iLength=strlen(strcpy(strA,strB));
    24 
    25 http://www.cnblogs.com/kedebug/archive/2012/12/23/2829945.html
    26 */
    strcpy
     1 char* mystrncpy(char* dst, const char* src, size_t size) {
     2     assert(dst != NULL && src != NULL);
     3     char* pdst = dst;
     4     const char* psrc = src;
     5     size_t i = 0;
     6     while (i++ < size && (*pdst++ = *psrc++) != '');
     7     if (*pdst != '') {
     8         *pdst = '';
     9     }
    10     return dst;
    11 }
    strncpy
     1 char* strcat(char* dst, const char* src) {
     2     assert(dst != NULL && src != NULL);
     3     char* pdst = dst;
     4     const char* psrc = src;
     5     while (*pdst != '') {
     6         pdst++;
     7     }
     8     while (*psrc != '') {
     9         *pdst++ = *psrc++;
    10     }
    11     *pdst = '';
    12     return dst;
    13 }
    strcat
    1 int strcmp(const char* str1, const char* str2) {
    2     assert(str1 != NULL && str2 != NULL);
    3     while (*str1++ == *str2++) {
    4         if (*str1 == '') {
    5             return 0;
    6         }
    7     }
    8     return *str1 - *str2; 
    9 }
    strcmp

    2. STL中vector的实现及原理

      1 // Vector.h
      2  
      3 #ifndef VECTOR_H
      4 #define VECTOR_H
      5  
      6 template <typename Object>
      7 class Vector
      8 {
      9 public:
     10     explicit Vector(): objects(0), theSize(0),theCapacity(0) {}
     11  
     12     explicit Vector(int initSize)
     13         : theSize(initSize), theCapacity(initSize + SPARE_CAPACITY)
     14     {
     15         objects = new Object[theCapacity]; 
     16         for(int i=0; i<initSize; ++i)
     17             objects[i] = 0;
     18     }
     19  
     20     Vector(const Vector & rhs)   
     21     { operator=(rhs); }
     22  
     23     ~Vector()
     24     { delete [] objects; }
     25  
     26     const Vector & operator= (const Vector & rhs)
     27     {    
     28         if(this != &rhs)      // check for aliasing
     29         {
     30             delete [] objects;
     31             theSize= rhs.size();
     32             theCapacity = rhs.capacity();
     33  
     34             objects = new Object[ capacity() ];
     35             for(int k = 0; k < size(); ++k)
     36                 objects[k] = rhs.objects[k];
     37         }
     38         return *this;
     39     }
     40  
     41     void resize(int newSize)
     42     {
     43         if(newSize > theCapacity)
     44             reserve(newSize * 2 + 1);
     45         theSize = newSize;
     46     }
     47  
     48     void reserve(int newCapacity)
     49     {
     50         if(newCapacity < theSize)
     51             return;
     52  
     53         Object * oldArray = objects;
     54  
     55         objects = new Object[ newCapacity ];
     56         for(int k = 0; k < theSize; ++k)
     57             objects[k] = oldArray[k];
     58  
     59         theCapacity = newCapacity;
     60  
     61         delete [] oldArray;
     62     }
     63  
     64     Object & operator[] (int index)
     65     {
     66         return objects[index];
     67     }
     68     const Object & operator[] (int index) const
     69     {
     70         return objects[index];
     71     }
     72  
     73     bool empty() const
     74     {
     75         return size() == 0;
     76     }
     77     int size() const
     78     {
     79         return theSize;
     80     }
     81     int capacity() const
     82     {
     83         return theCapacity;
     84     }
     85  
     86     void push_back(const Object & x)
     87     {
     88         if(theSize == theCapacity)
     89             reserve(2 * theCapacity + 1);
     90         objects[ theSize++ ] = x;
     91     }
     92     void pop_back()
     93     {
     94         theSize--;
     95     }
     96  
     97     const Object & back() const
     98     {
     99         return objects[theSize-1];
    100     }
    101  
    102     typedef Object * iterator;
    103     typedef const Object * const_iterator;
    104  
    105     iterator begin()
    106     {     return &objects[0]; }
    107     const_iterator begin() const
    108     {     return &objects[0]; }
    109     iterator end()
    110     {     return &objects[size()]; }
    111     const_iterator end() const
    112     {     return &objects[size()]; }
    113  
    114     enum{ SPARE_CAPACITY = 16 };
    115 private:
    116     int theSize;
    117     int theCapacity;
    118     Object * objects;
    119 };
    120  
    121 #endif
    vector

    ref1        ref2:Weiss<Data Structure in C++> Ch3.4              ref3

    拓展:

    2.1 

    vector已经申请的内存空间并不会缩减,即使调用clear()函数,也只是清空vector的所有元素,真正占用的内存空间也不会减少。(因此,先在vector里插入1w个元素再挨个删去直到剩10个元素,vector占用的内存空间还是维持在1w个元素时的状态。)
    
    解决办法:
    vector<int>(nums).swap(nums);
    类似地,
    string(s).swap(s);
    
    原理:
    先创建一个临时拷贝并利用拷贝构造函数对其初始化,值得注意的是,使用拷贝构造函数时其容量是尽可能小的符合所需数据的。紧接着将该拷贝与原先的vector v进行交换(swap)。执行交换后,临时变量会被销毁,内存得到释放。此时的v即为原先的临时拷贝,而交换后的临时拷贝则为容量非常大的vector(不过已经被销毁)
    
    http://blog.jobbole.com/37700/
    《Effective STL》-Item17
    http://www.cnblogs.com/summerRQ/articles/2407974.html
    如何释放掉vector的多余内存

     map,set,deque... 

    3. 实现一个string类

    4. const的用法

    1. const用于指针时:
    
    const在星号左侧,则const修饰指针所指向的变量,即指针指向的是常量;
    
    const在星号右侧,则const修饰指针本身,即指针本身是常量。
    
    可参考ref1的例子。
    ref1: http://blog.csdn.net/wen294299195/article/details/6857395
    
    
    2. const用于函数时:
    
    若const在函数名之后,说明该函数不能修改对象中的数据。如果有特例需要让该函数修改的话,可以把类中的那几个特例成员变量用mutable修饰。ref
    
    若const在函数名之前,则作用于返回值,意味着该函数返回的值只能被读取,而不能被修改。
    
    参考ref2的例子。
    ref2: http://www.iteblog.com/archives/214
    const的用法

    拓展: 

    4.1 const,volatile,mutable对比

    5. 讲一下智能指针的原理,并实现一个智能指针。

     follow up: 垃圾回收机制。

    6. 运算符重载

    7. 实现一个单例模式类

    follow up: 如何定义只能在上生成的对象? 只能在上生成的呢?

    8. struct对齐问题

    对齐规则:

    1)在没有#pragma pack(n)的情况下,struct内各个成员的对齐系数自己的长度

    2)在有#pragma pack(n)的情况下,struct内各个成员的对齐系数为 min(n, 自己的长度) .

    3)struct整体的对齐系数为struct内各成员对齐系数的最大值。

    4)struct内每个成员相对于struct首地址的offset都是该成员自身对齐系数的整数倍(否则要补全);而且,struct整体也要保证占用的总大小是struct整体对齐系数的整数倍(末尾不够要补全)。

    9. C++易混淆概念

    10. C++虚函数原理及虚继承

    11. C++对象内存模型

    Q: 画一下有虚函数的情况下内存布局大概是什么样的?

     ref1    ref2(很详细!)

    12. C++ this指针,动态绑定和静态绑定,空指针调用成员函数

    看一下这几篇文章: ref1     ref2      ref3      ref4      ref5

    static关键字相关   看一下 ref

    静态成员函数不可以调用类的非静态成员,因为静态成员函数不含this指针。【注意:是的,不是随便一个非静态变量】

    局部静态变量的构造是线程安全的。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    C++零碎知识点汇总

    其他C++常见问题:

    何海涛总结5篇C++面试题: ref1   ref2   ref3   ref4   ref5

    http://wenku.baidu.com/view/ad50b2d765ce05087632138c.html

    http://blog.csdn.net/worldwindjp/article/details/18909079

    http://www.cnblogs.com/wuchanming/p/4367398.html

    http://blog.csdn.net/chhuach2005/article/details/40322895

     =======================================================================================================================

    概率题 reference

    1. 给N张扑克牌和一个随机函数,设计一个洗牌算法

    2. 如何等概率地从n个数中随机抽出m个数?

    follow up: 如果上题中n大小不确定,如何做?

    3. 给定一个能够生成0,1两个数的等概率随机数生成器”,如何生成⼀个产生0,1,2,3的等概率随机数生成器?

      3.1 如何用rand7生成rand9?

      3.2 有1枚硬币,以p的概率产生正面,以1-p的概率产生背面,如何利用它产生一个0.5概率的生成器?

    4. A,B,C三人轮流扔硬币,第一个扔到正面的人算赢,问三个人赢的概率分别为多大?

    5. A有n个硬币,B有n+1个硬币,谁丢的正面多谁赢,问A不输的概率?

    6. 一个机器人在原点,右边有一个距离为k的点,机器人以p的概率右移一步,1-p概率左移一步, 问经过M步机器人处于k点的概率?

    7. 扔硬币直到连续两次出现正面,求扔的期望次数

    ref1里面有一些概率题总结的不错。

    ref1: http://noalgo.info/414.html

    =======================================================================================================================

    操作系统  reference

     1 1. Linux中线程互斥/同步有哪几种方式?
     2 
     3 2. 同样可以实现互斥,互斥锁和信号量有什么区别?
     4 
     5 3. 请用普通的互斥锁编程实现一个读写锁
     6 
     7 4. 编程产生三个线程ABC,并让它们顺次打印ABC
     8 
     9 5. 死锁是怎么产生的?如何避免?
    10 
    11 6. Linux中进程通信有哪些方式?
    12 
    13 7. Linux中进程空间布局
    14 
    15 8. Linux内存分配原理
    16 
    17 9. malloc函数实现原理
    18 
    19 10. 使用mmap读写文件为什么比普通读写函数要快?
    20 
    21 11. 静态链接库、动态链接库原理
    22 
    23 12. Linux中signal实现原理
    View Code

    Linux常用命令/知识: ref

    1. 进程和线程有什么区别和联系

    2. 内存管理

    伙伴系统

    进程间通信

    实现malloc/ malloc原理   ref1     ref2      ref3

     键盘上敲击一下键/按一下鼠标,后面都有哪些操作?

    缓存,LRU算法,进程、线程的概念。

    进程调度算法、文件系统。

    <多线程编程>

     =======================================================================================================================

    海量数据

    1. 100亿个整数,如何找到中位数

    内存足够的情况: 可以使用类似quick sort的思想进行[QuickSelection算法],均摊复杂度为O(n),算法思想如下:
    • 随机选取一个元素,将比它小的元素放在它左边,比它大的元素放在右边
    • 如果它恰好在中位数的位置,那么它就是中位数,可以直接返回
    • 如果小于它的数超过一半,那么中位数一定在左半边,递归到左边处理
    • 否则,中位数一定在右半边,根据左半边的元素个数计算出中位数是右半边的第几大,然后递归到右半边处理
    内存不足的情况:
    方法一:二分法
    思路:一个重要的线索是,这些数都是整数。整数就有范围了,32位系统中就是[-2^32, 2^32- 1], 有了范围我们就可以对这个范围进行二分,然后找有多少个数小于Mid,多少数大于mid,然后递归,和基于quicksort思想的第k大方法类似【即QuickSelection算法】 
    方法二:分桶法

    思路:化大为小,把所有数划分到各个小区间,把每个数映射到对应的区间里,对每个区间中数的个数进行计数,数一遍各个区间,看看中位数落在哪个区间,若够小,使用基于内存的算法,否则继续划分。

     =======================================================================================================================

    网络

    TCP/IP协议相关

    TCP和UDP的区别? ref

     

    三次握手,四次挥手 ref

    为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

    因为tcp是全双工模式,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,但是己方的数据可能还没有发完,有可能在发送对FIN的ACK后再发送一会数据,然后才发FIN。所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

    关于tcp中time_wait状态的4个问题: ref    ref2    ref3   ref4

    http协议相关

     从输入 URL 到页面加载完的过程中都发生了什么事情

    拓展:参考下这篇文章,非常好。

    其他网络面试题

     

     

     

     

    http://www.nowcoder.com/discuss/1937?type=&order=0&pos=6&page=1?from=wb    【这个总结非常好!认真看一下!】

     http://www.cnblogs.com/obama/p/3292335.html

     

    <网络编程>

    IO复用 summarize

    epoll水平触发,边缘触发

    select与epoll

     用户态与内核态,以及如何切换

    ref0: 这个博主写的一系列网络编程文章都特别好(条件变量,epoll)。多看一下

    reference 这篇文章对网络编程的知识点总结的非常好!认真学习一下

    epoll面试相关

    http://blog.csdn.net/tom555cat/article/details/24870469

    http://www.cppblog.com/peakflys/archive/2012/08/26/188344.html

     http://blog.csdn.net/lianxiang_biancheng/article/details/9025881 【看一下这篇里面epoll源码,让人快速理解epoll流程】

    nginx入门   reference

    =======================================================================================================================

    智力题

    1. 25匹马,5个跑道,最少比多少次能找到前3名

    拓展:找前5名呢?   ref2     ref

    2. 

     =======================================================================================================================

    算法和数据结构

    1.常见排序算法复杂度、稳定性

    选择排序是每次遍历一遍剩余元素,从中选出最小的与前面已排好序的元素的下一位置进行swap。最优情况下复杂度是O(n^2), 平均和最坏复杂度也是O(n^2)。

    冒泡和插入排序的最优复杂度是O(n), 平均和最坏都是O(n^2)。

    归并排序和堆排序的最优、平均、最坏复杂度都是O(nlgn)。

    快速排序最坏情况下是O(n^2), 平均和最优都是O(nlgn).空间复杂度是O(lgN)(因为需要每次记录pivot的位置)。

    稳定性:

    不稳定:快速排序、堆排序、选择排序、希尔排序

    稳定:归并排序、基数排序、冒泡排序、插入排序。

    希尔排序是按照不同步长对元素进行插入排序。

    ref:  ref1   ref2

    =======================================================================================================================

    ref: http://www.nowcoder.com/ta/nine-chapter?page=1

  • 相关阅读:
    Solaris安装pkg
    JSP路径出现问题
    错误卸载软件导致Windows7系统中的软件无法播放视频
    蛋疼的Solaris设置
    SQL运行突然SESSION中断错误
    JAVA利用Zip4j解压缩
    java解压缩/压缩/加密压缩/加密解压缩 ZIP4J---ZIP文件压缩与解压缩学习
    未得冠军的运动员也有教练——Leo鉴书71
    VS2008 编译SQLite 3.8.4.3 + sqlcipher-3.1.0 + openssl-1.0.1g
    Android数据库安全解决方案,使用SQLCipher进行加解密
  • 原文地址:https://www.cnblogs.com/forcheryl/p/4695937.html
Copyright © 2020-2023  润新知