C++面试cc/c++

C++开发面经总结

2018-08-11  本文已影响13人  XDgbh

https://www.nowcoder.com/discuss/90907?type=2&order=0&pos=3&page=1

一、C语言基础

1、struct 的内存对齐和填充问题
其实只要记住一个概念和三个原则就可以了:

2、struct变量能进行比较吗?

3、运算符优先级问题

https://blog.csdn.net/u013630349/article/details/47444939

4、手写strcpy字符串拷贝函数?先问要C风格的还是C++风格的?

#include <assert.h>
#include <stdio.h>
char* strcpy(char* des, const char* src)  //注意const。C++风格的(char& des, const char &src)
{
    assert((des!=NULL) && (src!=NULL));   //注意输入合法性检查。
//但是对于C++可以有更好的解决方案,将输入参数指针改为引用&,就默认不能传入NULL,否则报错
    char *address = des;          //注意返回值是目的串首地址
    while((*des++ = *src++) != '\0')  
        ;  
    return address;
}

https://www.nowcoder.com/ta/review-c/review?tpId=22&tqId=21053&query=&asc=true&order=&page=4
另有strlen、strcmp、strcat函数的手写:https://blog.csdn.net/lisonglisonglisong/article/details/44278013
另外strncpy函数,复制完后des目标字符串的末尾不会有'\0'结束符,一种解决办法是自己加上一行 des[n]='\0';。更好的做法是给des字符数组初始化为全空字符串char des[100]="";或者memset(des, 0, 100);

5、手写一个memcpy函数?

void* Memcpy(void* dest, const void* src, size_t size)
{
    char *pdest, *psrc;
    if (NULL == dest || NULL == src)
    {
        return NULL;
    }
    //要考虑如果目标地址和源地址后面有重叠,则要防止源地址后面的原始数据被目标地址拷贝过来的数据覆盖
    //这种情况就需要从后往前拷贝
    if (dest>src && (char *)dest<(char *)src+size)
    {
        pdest = (char *)dest + size - 1;
        psrc = (char *)src + size - 1;
        while (size--)
        {
            *pdest-- = *psrc--;
        }
    }
    //从前往后正常拷贝赋值
    else
    {
        pdest = (char*)dest;
        psrc = (char*)src;
        while (size--)
        {
            *pdest++ = *psrc++;
        }
    }
    return dest;
}

6、main函数的返回值作用?如何捕获返回值?

7、进程间通信的方式有哪些?

8、线程间的通信

9、进程调度算法有哪些?Linux使用的什么进程调度方法?

Linux系统中,进程分为实时和非实时两种:

10、虚拟内存和物理内存?

1)每个进程都有自己的虚拟内存空间,所有进程共享物理内存空间。
2)虚拟内存大小和机器的位数有关,如32位的是4GB的地址总线(0~0xFFFFFFFF字节)其中每个进程都有自己的0~0xBFFFFFFF的3GB虚拟内存空间——用户空间,然后所有进程共用0xCFFFFFFF~0xFFFFFFFF这1GB的虚拟内存空间——内核空间。64位的有2^64字节的地址总线。


3)该图显示了两个 64 位进程的虚拟地址空间:Notepad.exe 和 MyApp.exe。每个进程都有其各自的虚拟地址空间,范围从 0x000'0000000 至 0x7FF'FFFFFFFF(8TB用户进程虚拟内存空间)。每个阴影框都表示虚拟内存或物理内存的一个页面(大小都为4KB)。注意,Notepad 进程使用从 0x7F7'93950000 开始的虚拟地址的三个相邻页面。但虚拟地址的这三个相邻页面会映射到物理内存中的非相邻页面。而且还注意,两个进程都使用从 0x7F7'93950000 开始的虚拟内存页面,但这些虚拟页面都映射到物理内存的不同页面,说明个进程间的虚拟内存互不影响。
4)这种虚拟内存一个页page(4KB)和物理内存一个页帧(4KB)之间的映射关系,由操作系统的一个页表来维护,页表中给各个页都有编号(页号和页帧号对应映射)。进程中虚拟内存页》页表中的页号—MMU内存管理单元—页表中的页帧号《物理内存中的页帧【由MMU的页表来维护映射关系】

5)但是问题来了,虚拟内存页的个数=3GB/4KB > 物理内存页帧的个数=256MB/4KB,岂不是有些虚拟内存页的地址永远没有对应的物理内存地址空间?不是的,操作系统是这样处理的。操作系统有个缺页中断(page fault)缺页异常功能。操作系统把暂时不访问的物理内存页帧,让他缺页失效,并把它的原内容写入磁盘转存起来——这个过程叫分页-分页是磁盘和内存间传输数据块的最小单位。,随后把当前需要访问的页放到页帧中,并修改页表中的映射,这样就保证所有的页都有被调度的可能了。当进程又要访问原转存的内容,会先访问原物理内存页但是引发缺页中断然后从磁盘中取出页内容到物理内存页,然后进程访问到数据继续执行。这就是处理虚拟内存地址到物理内存的步骤。

https://www.cnblogs.com/curtful/archive/2012/02/16/2354496.html

11、为什么需要虚拟内存?通过虚拟地址访问内存有哪些优势?

12、死锁产生的四个条件,死锁发生后怎么检测和恢复?

13、不用中间变量实现两个元素交换值。

void swap1(int &a, int &b)
{  //异或操作只适用于整型数,不能用于小数
    if (a != b)  //如果两个数地址相同,异或操作会清零
    {
        a ^= b;
        b ^= a;
        a ^= b;
    }
}
void swap2(double  &a, double &b)
{//用double型可以使适用的范围更大,防止加法和越界
    a = a + b;
    b = a - b;
    a = a - b;
}

14、一些常见的位操作

int my_abs(int a)
{
    int i = a >> 31;  //得到最高位符号位,a为正或0返回0,a为负数返回-1
    return i == 0 ? a : (~a + 1);  //正数返回本身,负数返回相反数
    //return (a^i)-i;  //a^0 ==a本身;a^(-1) == a取反,再减-1即加1得到相反数
}

二、C++基础

1、new表达式(new operator)和std::operator new标准库函数的区别

这里我们可以这么理解,new表达式(new operator)其实可以分解为两部,即先调用new操作符(operator new)申请内存,再调用placement new来初始化对象。即上面对new表达式的使用string * str = new string("hello");等价于下面两句。

void *buffer = ::operator new(sizeof(string));
buffer = new(buffer) string(“hello”);
 void* operator new(size_t sizt)
{
      return malloc(size);      
}

详见:https://www.jianshu.com/p/a07ba8f384da

2、new和malloc有哪些区别?


最重要的是要说到最下面一条。
详见:https://www.cnblogs.com/QG-whz/p/5140930.html

3、头文件防卫式编程,防止头文件多次嵌套导入。
比如要编写头文件mystring.h,就可以这样写。如果统一遵循这种规则,那么就不会出现mystring.h头文件内容在编译前预处理时被重复导入的情况。

#ifndef __MYSTRING__
#define __MYSTRING__

#include<string.h>    //用到C语言的字符串处理函数
class mystring
{
public:
        mystring();
        ~mystring();
private:
        char * head;
        int length;
};
#endif

4、const函数?——函数定义后面加const有什么作用?

5、C++内存分区?进程虚拟内存分布?共有5个分区

6、一个进程可用的内存大小、线程可用内存大小?堆内存多大?栈内存多大?

7、用vs编程时debug和release版本有啥区别?

8、面向对象的三大特性讲一下?

9、C++多态分几类?多态有几种实现方式?

10、C能直接用C++写的动态库吗?C++能直接用C写的动态库吗?

11、从源代码到可执行文件经历了那几步?

12、C和C++的区别

13、C++和java的区别

14、static_cast 和 dynamic_cast 的区别?两个操作符

15、说几个C++11的新特性。

1)auto类型推导:auto vData = vectors.begin();自动推导出vector中的数据类型
2)范围for循环:for( auto v:vectors) { cout<<v<<endl; }这样的v是只读的,也可以用到&引用,作为可修改的for(auto &v:vectors){ v=v+1; }
3)lambda表达式:是一个匿名函数,即没有函数名的函数。
4)override 和 final 关键字:两个继承控制关键字,override明确地表示一个函数是对基类中一个虚函数的重载,virtual void func(int) override;确保在派生类中声明的重载函数跟基类的虚函数有相同的签名。final阻止类的进一步派生class TaskManager {/*..*/} final;和虚函数的进一步重载virtual void func(int) override final;
5)空指针常量nullptr
6)线程支持、智能指针等:https://www.kancloud.cn/wangshubo1989/new-characteristics/99704

16、如何在一个不安全的环境中实现安全的数据通信?

首先 数据接收方 生成一对密钥,即私钥和公钥;
然后,数据接收方 将公钥发送给 数据发送方;
数据发送方用收到的公钥对数据加密,再发送给接收方;
接收方收到数据后,使用自己的私钥解密
》由于在非对称算法中,公钥加密的数据必须用对应的私钥才能解密,而私钥又只有接收方自己知道,这样就保证了数据传输的安全性。

17、面向对象思想主要如何体现?

18、类与类之间的各种关系?

【继承inheritance】A is-a B
类A继承类B,UML类图是实线加三角形由A指向B。A is-a B.
public继承:父类中的成员访问权限不变。
pretected继承:父类的访问权限中public权限降为protected,其他不变。
private继承:父类中public和protected权限的成员全变为private,权限降级,即子类只有类成员变量和友元函数能够访问这些。
【依赖dependency】A use-a B.
类A依赖类B,UML类图是虚线加箭头由A指向B。A use-a B.
一般来说,依赖是指A的某些方法功能要用到B,常表现为B作为A的成员方法的形参或局部变量或返回值,即只和类成员方法有关。
【关联association】A has-a B, B has-a A.
类A和类B双向关联,UML类图是A——B一根实线连接。A与B互相作为类的数据成员变量。
【组合composition】A has-a B 实例对象
类A组合了类B,UML类图是A实心菱形再实线和箭头指向B。类A中定义了类B作为数据成员,B在A中定义构造。A和B的对象生命周期一样。A拥有完整的B,强拥有关系。
【聚合aggregation】A has-a B 引用
类A聚合了类B,UML类图是A空心菱形再实线和箭头指向B。类A中定义了类B的指针作为数据成员,类B的实例化在其他地方。A和B的对象生命周期不一样。A拥有不完整的B,弱拥有。可以认为是 composition by reference == aggregation 或者也可以叫做委托delegation。

19、谈谈你了解的设计模式有哪些?

三、STL

1、STL的作用,为什么需要STL?(常用的是SGI版本的STL,被纳入GNU C++标准库)

2、STL六大组件之间的关系?

3、vector、map/multimap、unordered_map/unordered_multimap的底层数据结构,以及几种map容器如何选择?

4、type_traits<T>是什么作用?

5、STL的空间配置器实现原理?

union obj{
    union obj * free_list_link;    //保存着下一个空闲区块的地址
    char client_data;    //表示给用户申请使用后的数据存放首字节地址
};

四、数据结构和算法

1、求一串数字序列中的连续子串最大和,比如arr=1 -2 3 -1 2,连续子串最大和就是3 -1 2组成的max_sum=4。

int MaxSubSum(int *arr, int n)
{
    int sum=0, b=0;  //只用一个b记录dp[i],更节省内存
    for (int i=1;i<=n; i++)
    {
        if (b>0) b+=a[i];
        else b=a[i];
        if (b>sum) sum=b;
    }
    return sum;
}

2、寻找100范围内的素数的算法,对于找到的前面的每个素数的n倍都必然不是素数,都可以剔除检查

五、网络

1、TCP三次握手,四次挥手状态改变过程?

2、ping网络主机之间通不通用到什么协议?

六、操作系统

七、数据库

1、事务(transaction)是什么?

2、事务有几个特性?分别是什么?

其他

上一篇下一篇

猜你喜欢

热点阅读