C++:请问这题怎么做?

来看下我去年面「网易C++基础架构研发实习生」被问过的问题吧!

整整一个多小时,人都问傻了。。。。

我依稀记得是电话的另外一端是两个人的声音。。。他们还在商量问什么。

奇怪,为啥会有两个面试官?

也有可能是某个面试官在工位面,其它的在旁边凑热闹?

  • 你对哪方面是最熟的,是不是Linux C++ 或者说是最感兴趣?
    • 表达自己倾向基础方向开发
  • 问下项目经历吧,能不能详细介绍下这个项目里做了哪些事情,解决了什么问题啊?
    • 详细的介绍了项目和之前准备好的一个问题(socket方向的,自己通过 netstat 等监控工具排查问题经过,讲得很详细,感觉面试官比较满意)
  • 你中间有没有去提升或者改善性能啊,比如说改参数啊或者调整什么机制,有没有这方面的努力?
    • 也是简单介绍了下自己怎么优化的,达到了什么效果(QPS)
  • 蛮多和项目相关的问题就不细说了,反正就是大家准备项目的时候提前准备一些比如遇到的困难、如何解决的、性能如何、如何优化这样子的问题。
    • 哈哈哈问到这个问题我就笑了,然后就开始先说差别,比如select 有文件描述符限制,频繁的内核态和用户态拷贝、O(n)遍历这些,然后讲了 select 和epoll 都是基于文件系统中 file_operations 的 poll 调用,然后开始详细讲 epoll,大概讲到了内核用红黑树维护监听描述符,就绪队列,回调函数机制避免O(n)的遍历这些,答完面试官就说说得比较全面深入。
  • 刚才你说你用 netstat 命令去检查连接状态,你能不能说下这个命令是做什么,看到的链接状态会有哪些?
  • 如果是你在部署某一个程序服务的时候,看到大量的TIME_WAIT连接是怎么回事?
    • 分析了 TIME_WAIT 是主动关闭一方,所以服务器应该是有大量短连接请求
  • 那么大量的 TIME_WAIT 会导致什么问题呢?
    • 大概从端口占用 2 MSL 不能使用,可能导致后续没有端口接受新连接之类方向分析
  • 那我们怎么去避免这个问题,避免大量 TIME_WAIT
  • 平时用什么语言,做什么开发?
    • C++ 一般用来和网络 Linux 相关的开发, Java 的话是偏 Web 后端, Python一般是写脚本或者爬虫也有用后端框架
  • Python的话用到过装饰器吗?
    • 嗯,然后讲了装饰器来干嘛,比如无侵入的增加函数功能(比如计时),有点类似 Java 注解,支持 AOP 编程。乱扯了一堆...
  • 那 Java 你有哪些了解得常用设计模式?
    • 讲了装饰器模式和在 jdk IO 流中的运用,单例模式
  • 那单例我们一般用来做什么?
    • 只需要一个对象的场景,比如数据库连接池、文件系统这种。。。
  • 了解过 Java 里面的线程安全问题吗?
    • 感觉不妙引到 Java 上来了,赶紧给面试官说自己 Java 不是很熟悉,讲下 C++ 中的吧,然后开始 C++ 的问题
  • 讲下 C++ 里虚函数
    • 虚函数表 虚函数表指针 函数指针 动态绑定 基类指针指向派生类对象这些,还有接口设计方面
  • 在 C++ 里面结构体和类的区别
    • 默认访问权限 + 一点其它自己的使用感觉
  • 用过智能指针吗,能不能介绍下它解决的问题和你使用的经验?
    • 首先讲了裸指针生命周期管理的困难,内存泄漏、野指针这些
    • 然后讲了智能指针是如何利用 RAII 来解决的,然后顺便提了那几个智能指针区别
    • 讲了自己项目中如何利用 shared_ptr 的,还有如何用 weak_ptr 解决环形引用的
  • 刚才你提到内存泄漏,那你是如何在 debug 发现或者是定位内存泄漏的呢?
  • 那后面用了智能指针之后你再去跑内存泄漏有减少吗?
    • 嗯,工具检测没有内存泄漏发生了
  • 可以讲下树的深度遍历和广度遍历
    • 前 中 后 用栈或者递归
  • 那哈希表冲突怎么解决?
    • 线性探测和平方探测,说了这两个有主聚集和次聚集缺点
    • 大多数语言 map 用的是开链法
  • 如何判断链表是否有环?
    • 说了用 set 和快慢指针两种
  • OK,我问几个操作系统方面的问题哈
    • 详细讲了 fork 的COW, 锁定父子进程页表只读,任何一进程写时就分配页框复制之类,顺便还提了下 C++ 中 COW 在string 上的应用
    • 匿名管道 有名管道 共享内存 信号量 消息队列 socket, 然后强调自己偏向使用 socket 通信,因为方便将单机多进程扩展到多机多进程
  • 你单机开发和实验用的什么 Linux 开发版啊?
  • 了解一些运维命令吗,比如你在测试的时候怎么看负载啊
  • 后面详细问了 top, 比如问我知道 Load Avg 代表什么含义,进程的 CPU 利用率会超过 100% 吗,top 还能看什么性能指标?

那么C++除了这些问题常考的集中在哪呢?

这里首先说下语言基础知识,一些关键字和实现原理等:

  • 指针、引用、数组、内存。
  • C++中引用与指针区别
  • 继承、虚继承、菱形继承等
  • C++虚机制:虚函数、虚函数表、纯虚函数
  • 多态: 动态绑定,静态多态
  • C++11 部分新特性,比如右值引用、完美转发等
  • 智能指针原理:引用计数、RAII(资源获取即初始化)思想
  • 模板特化、偏特化,萃取 traits 技巧
  • 程序编译链接机制、内存布局(memory layout)、对象模型

可以通过看这些书去学习:

  • 《C++ Primer》,这本书是基础,需要重点看前几部分。
  • 《STL 源码剖析》和《深度探索 C++ 对象模型》,这是了解STL容器底层实现和对象模型,面试常考

其它更多的C++相关学习路线可以看看这个回答:

说实话,大家看完这份面经,是不是觉得也没问什么特别难的问题?

但是这个面试我印象很深刻,因为还有一些问题没记下来,印象里就是面试官一直追问,然后各自问题轮番上阵。

从网络编程到 TCP 状态、从 C++ 虚机制到多线程、COW 这些话题,还有 Python、Java、C++ 这些语言都会问,跨度也很大。

但是我基本都能回答得上来,并且会刻意引导到我熟悉的方向。

比如问 TCP 状态的时候,我会刻意将 TIME_WAIT 回答到最后一个,然后果然面试官就顺着我,问部署服务是否遇到过大量这个状态之类....

比如我当时对 Java 多线程那块不是特别熟悉,面试官问我的时候,我直接让他问我 C++ 的,给讲 C++ 里多线程怎么做的。

这个面试官对我评价也很不错,后来网易二面这个面试官,也就没问我这个基础问题了,说一面问了很多,我的基础也很不错。

然后直接跟我聊云计算、K8s这些,但是恰好,虚拟化这块我了解不多,仅仅对 Docker 的原理有一些粗浅的认识。

然后后面就建议我不要去他们那暑期实习,两个月的时候不太够,让我明确自己到底想做什么(传说中的好人卡?不过我感觉不至于,这个面试官是真的出于对候选人负责。

和这个面试官聊了一些无关面试的话题,然后我就决定去腾讯实习了,拒掉了后面头条这些约的面试。

当时面完还加了下好友,本来打算秋招就去那面的,不过世事难料,我留在微信这里了哈哈。

话说回来,刚才说了面试要引导到自己熟悉的方向,能引导的前提就是你了解得足够多,不然你怎么知道该往哪引导呢?

其次就是知识要系统,比如 Copy On Write 这个话题,能从 fork 联想到 C++ 中的应用。

另外就是知识面要尽可能宽一些,我以前是很爱看各种技术文档、博客的,所以了解也很多。

并且有了 C/C++ 基础,后面两门语言都很快的,而且你很快能掌握 Python 这些底层实现机制,如果你对 C++ 对象模型这一套了解的话,这些都是换汤不换药的。

在不涉及 Java 那些 Spring 全家桶的前提下,光是语言还是比较好学。

最后就是基础知识真的要好好刷书、刷视频,不要直接看面经,今天晚上我和一个同学电话了近 20 分钟,他讲了下他目前的学习路线:

基本是刷题 + 刷面经,并且是 数据结构、计算机网络、操作系统这些都没有系统的过一遍,这样肯定是不行的啊。

面经刷得多,可能面试也能过,但是很难系统化,面经上没有刷的点,你就漏掉了。

所以我给他的建议就是:

数据结构 + 计网 + 操作系统 都采用 刷视频 + 刷书的方式系统学习一遍,并且绕过非重点内容。

系统学习后,再去看面经,提炼高频问题。

在这举个例子吧,去年我学弟问了我一个面试题:

建立 TCP 连接后,主机挂了和 JVM 虚拟机挂了的区别

三次握手、四次挥手、TCP连接状态、主机? 这些连在一起的时候怎么分析?

其实这里就是看你对 TCP 面向连接 的理解到底是什么?

本质上就是双方记录一个状态嘛,互相通信同步状态,或者做状态转换。

那么如果主机直接断掉,比如直接扒掉电源,那么其实你的主机不会发出任何的数据包,对方也不会感知到,除非对方发了探测包,或者数据包过来,然后一直超时重试,直到上限。

那么 JVM 挂了呢?

那加入是主机断电后又重启呢?

这个 TCP 连接是什么状态?

大家可以思考下,也许这个问题没有标准答案,要以实验为准。

但是我觉得面试官想要考察的也是你对 TCP 连接的理解,以及在各种情况下的分析。

好了,希望对大家有帮助,记得帮我 点个赞吧!

}

问:C++内存模型是什么?如何理解自由存储区与堆的区别?

在C++中,内存区分为5个区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区。

malloc在堆上分配的内存,使用free释放内存,

而new所申请的内存则是在自由存储区上,使用delete来释放,不过这只是表象。

进一步来讲,基本上所有的C++编译器默认使用堆来实现自由存储,即缺省的全局运算符new和delete也会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。
所以,new所申请的内存区域在C++中称为自由存储区,如果是通过malloc实现的,那么他也是在堆上的。

问:多继承的优缺点(提问概率:★★★)

好处:简单来讲就是为了实现多个基类特有的功能

缺点:菱形继承;二义性

问:类的内存布局是什么样的?考虑有虚函数、多继承、虚继承几种情况。(提问概率:★★★★★)

简单总结一下就是类只有成员变量占用内存(静态成员不占类内部内存,函数不占内存)。如果有虚函数,每个类对象都会有一个虚函数指针Vptr(占用一个指针大小的内存),vptr指向一个虚函数表,表里面记录了各项标记virtual的函数,子类如果覆盖父类虚函数,对应虚表位置的虚函数会被子类的替换(虚表在运行时其位置与大小就被决定了,一个类只有一个虚表)

内存对齐与内存分配原则

shared_ptr作为一种智能指针,本质上一个模板类,表现上与指针相同,

是因为重载了&以及*这两个运算符(当然还有=等运算符)。

由于其本身的计数机制,防止资源泄露上面很有意义。

Shareptr在实现上有两个核心的成员,一个是指向资源对象的指针变量,另一个是指向引用计数的指针变量。

第一个参数不言而喻,第二个参数为什么也是指针?

因为多个shared_ptr对象指向同一资源时,其中一个shared_ptr对象析构了count = count -1,是不会影响到其他shared_ptr对象的,所以使用指针可以达到多个shared_ptr对象指向同一资源的能够共享count目的。

另外,原生的shared_ptr的读写在多线程当中是不安全的,因为读写不具有原子性,所以多线程使用shared_ptr一定要加锁。

具体参考陈硕先生的“为什么多线程读写 shared_ptr 要加锁?”。循环引用会造成内存泄露。

malloc:是从C语言移植过来的语义,表示申请一定大小的内存并返回void*指针,在堆上申请内存,申请失败会返回Null

New:C++里的关键字,针对对象而言,申请一块内存的然后并在内存上构造对应的对象,最后返回该对象的指针。

深入:new是从自由存储区分配的内存,自由存储区可能不在堆上,在静态存储区(全局变量做的对象池)。申请失败会抛出异常。New可以通过new[]对数组进行内存申请与构造

New操作的第一步就是调用OperatorNew来执行内存的申请。

深入:operatornew可以基于malloc实现,一般也都是这么做的,可以被重载

placement new作用不太像new,或者说只是一个不完整的new,因为他不分配内存,只是在给定地址上调用构造函数,在c++里面,placement new实际上就是operator new的一种重载方式之一

一个普通的new可以拆分成两步,

第二步,在指定位置上构造对象(这个操作一般是编译器帮我们做了,但是并不是执行placement new,虽然功能上差不多,这里面有细微的差别)。

c++单独提供给我们一个placement new 来做第二步操作,因为有的时候我们可能想使用自己的内存申请方式(比如malloc),

但是你发现除了placement new以外你好像没有其他办法在指定位置上调用构造函数。

另外,想要使用placement new,底层系统并不告诉你这个地址上是否已经有对象了,如果你在已经构造的对象上面执行,那么前一个对象就会被销毁,理论上析构函数也不会执行。总之,要避免这种情况。

c++11新标准里面加入,他本身是一个类模板,功能上其实就是把new拆开,把内存申请和对象构造分成两个步骤,是不是很熟悉?这不就是operator new和placement new么?

为什么要这么做?举个例子,假如我要new一个长度为100的string数组,那我在申请内存的同时还要构造100个string对象,而实际上我整个程序从开始到结束可能只用了10个string。

那为了减小构造的开销,这里就将内存申请与对象构造分开,也就有了allocator。

当然,我们也可以使用operator new来做这个操作,只不过allocator帮我们做了一些简单的封装,类型检查等。

另外,说到allocator就不得不提一下stl里面的空间配置器alloc,他除了上面简单的封装外还还考虑到了以下三个方面:

每次CPU缺什么数据, 找内存拿了一次, 但是这被prefetcher记住了, 等一有空prefetcher就把页(Page)中其他相关数据都从内存里拿出来. 

这就等于把他街坊邻居全叫了出来, CPU提取数据一般是有范围的, 横竖不超过这么多, 所以CPU第二次再缺数据, 就不用去找内存了, 都在Cache里! 

实际上Cache可以同时监控很多个页, 这个过程反复几次, CPU就基本不再找内存要东西了.

问:vector的实现与增长

vector是stl提供的动态数组,想了解他就要从他的特性开始分析。

首先,他是一个模板类,意味着可以存放各种类型的元素,同时他也是一个数组,存储是连续的。

内存分配:常规的数组必须在定义的时候就分配好固定的大小,而vector可以动态的改变,也就说明他可以动态的申请与释放内存。

我们要知道,频繁的申请与释放内存对程序的效率影响是非常大的,因为如果当前地址空间不够用的话,就需要重新找一块更大的空间来装数据,再把数据全部都拷贝过去。

所以vector为了达到比较好的效果,在添加元素的时候会多申请一定大小的内存,从而减少内存分配的次数。capacity()返回的就是包括缓冲区在内的空间大小,而size()返回的就是当前实际使用的空间大小。

如果想主动的提前分配内存,可以使用reserve(n),会强制重新分配一次内存,超出实际使用的部分就会成为缓存区。

如果想直接构造出长度为n的动态数组可以使用resize(n),实际分配的空间肯定要比n大,不过如果n比当前size小的话,大于size的数据都会被清空,如果比capacity还大的话就会重新执行一次内存分配。

关于内存释放,如果只是简单的调用 clear()全部清空数据,erase()清空部分数据 都只是单纯的清空里面的数据并不会释放掉。

默认只会在调用vector的析构函数的时候才会真正释放空间,所以如果想强制释放那就新建一个空的vector,然后对这个vector使用swap讲内存交换,那么原来的vector就会释放,新的vector呢?
另外,由于涉及到模板,也就会涉及到迭代器,凡是重新申请过内存,插入删除数据的,迭代器都会失效,理解上也很容易就是指针可能指向的不是你原来的那个位置了。

问:map的实现 unordered_map的原理;如果从空的table开始一直增加元素,会出现什么情况?

map分为有序map和无序map,实现的基本数据结构分别是红黑树与哈希表。

红黑树作为一种二叉搜索树,具有log(n)的查找效率,不过前提是数据具有足够的随机性。!!!

hashmap理想上则是具有常数平均时间的效率,或者说一次或几次就可以查到,当然如果数据量过大,散列表空间就不能和数据量保持1:1,这时候就要靠hash函数来处理数据,将数据尽可能的分散在不同的桶bucket里面。

sgi stl的hash使用的是开链操作来避免hash表空间过大又想保持一定效率的问题,

开链就是在一个位置用链表来存储所有冲突项。

其实hashmap里面常说的桶bucket就是vector数组的一个元素,每个桶里面的数据是以链表(开链)的形式存储,进一步来说这些操作与定义都是通过一个基本的数据结构hashtable来实现的,所有的无序关联容器都是。

hashtable里面的hash函数就是常说的取模函数,根据存储数据key值(注意,是对key而不是value)对桶的长度取余数来存放。

默认提供的hash函数无法处理常见内置类型以外的数据,如各种自定义类,其实string本身也算是特殊类型,但是语言内部可以转为const char*处理,他经过函数处理也会得到一个size类型(一般对字符串的哈希函数比较特别,参考各种字符串Hash函数比较)。

什么时候需要rehash?

当你的桶里面的平均数量(Map大小/桶的数量)大于max(这个可以自己设置),就需要rehash。

也可以主动调用rehash(n),保证桶的数量大于n,注意n是桶的数量。 

改变桶的数量就相当于改变Vector的长度,如果超过vector的capacity就会调用Vector的扩容机制(但是实际上他每次hash的时候都会直接调用vector的reserve进行扩容)。

注意reserve与vector的reserve不一样,他的目的并不是扩容,而是希望当前哈希表里面可以容纳n个元素。

如果n>桶的数量*负载因子 的时候就会触发rehash,否则不会触发。rehash有可能进一步触发vector的扩容。

不过我发现 VC的STL里面的处理方式好像不太一样,

他是自动先检测是否满足当前负载因子>最大负载因子,满足就会先触发重新设置桶的数量,如果桶的数量小于512就直接乘以8,否则如果小于Vector容量的一半的话就乘以2。

这个过程我们看到他直接设置桶的数量并没有调用rehash函数,如果是主动调用rehash的话是直接翻倍的。

而且不论是手动还是自动调整桶的数量,他都会触发Vector的扩容函数。

问:stl里面各个容器的基础数据结构是?

常问的是优先级队列,hashmap,map底层的数据结构是什么。

具体细节大家可以仔细看一下关于容器的这两章内容。

图截自STL源码分析一书

问:了解静态库与动态库么?说说静态链接与动态链接的实现思路(提问概率:★★★)

静态库:任意个.o文件的集合,程序link时,被复制到output文件。这个静态库文件是静态编译出来的,索引和实现都在其中,可以直接加到内存里面执行。

对于Windows上的静态库.lib有两种,一种和上面描述的一样,是任意个.o文件的集合。

程序link时,随程序直接加载到内存里面。另一种是辅助动态链接的实现,包含函数的描述和在DLL中的位置。

也就是说,它为存放函数实现的dll提供索引功能,为了找到dll中的函数实现的入口点,程序link时,根据函数的位置生成函数调用的jump指令。(Linux下.a为后缀)

动态库:包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。(Linux下.so为后缀)

参考书籍与资料:《深入理解计算机系统》

问:用过或很熟悉的设计模式有哪些?(提问概率:★★★★)

这个问题看好书写写代码就可以自由发挥了,下面给几个例子。

工厂模式,通过简单工厂生成NPC对象,简单处理的话可通过“字符串匹配”动态创建对象。

如果有“反射机制”就可以直接传class来实现。当然可以进一步使用抽象工厂,处理不同的生产对象。

单例,实现全局唯一的一个对象。构造函数、静态指针都是私有的,使用前提前初始化或者加锁来保证线程安全。

Adaptor适配器,代码适配原来的相机移动最后调用的是原来的移动,现在加了适配器继承里面放了当前引擎的摄像机,然后覆盖原来摄像机的移动逻辑。

Observer,一个对象绑定多个观察者,然后这个对象一旦有消息就立刻公布给所有的观察者,观察者可以动态添加或删除。

在UE4里面,行为树任务节点请求任务后进入执行状态,然后会立刻注册一个观察者observer到行为树(行为树本身就相当于前面提到的那个对象)的observer数组里面同时绑定一个代理函数。行为树tick检测消息发送给所有观察者,观察者收到消息执行代理函数。

参考书籍与资料:《Head First设计模式》《设计模式:可复用面向对象软件的基础》

原文来自大佬博客 /

}

虽然都是基础,却是比较重要的部分.

6.C/C++编译器中虚表是如何完成的?
7.谈谈COM的线程模型。然后讨论进程内/外组件的差别。
8.谈谈IA32下的分页机制
小页(4K)两级分页模式,大页(4M)一级
9.给两个变量,如何找出一个带环单链表中是什么地方出现环的?
一个递增一,一个递增二,他们指向同一个接点时就是环出现的地方
10.在IA32中一共有多少种办法从用户态跳到内核态?
11.如果只想让程序有一个实例运行,不能运行两个。像winamp一样,只能开一个窗口,
用内存映射或全局原子(互斥变量)、查找窗口句柄..
FindWindow,互斥,写标志到文件或注册表,共享内存。.  
12.如何截取键盘的响应,让所有的‘a’变成‘b’?
 13.Apartment在COM中有什么用?为什么要引入?
 14.存储过程是什么?有什么用?有什么优点?
我的理解就是一堆sql的集合,可以建立非常复杂的查询,编译运行,所以运行一次后,以
后再运行速度比单独执行SQL快很多
 15.Template有什么特点?什么时候用?

网络编程中设计并发服务器的问题

网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?
1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他
线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
两者都可以提高程序的并发度,提高程序运行效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正
相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

什么是预编译,何时需要预编译:
1、总是使用不经常改动的大型代码体。
2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这
种情况下,可以将所有包含文件预编译为一个预编译头。

答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,
无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为
4.函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因
此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。

一个32位的机器,该机器的指针是多少位
指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指
针的位数就是4个字节了。

"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
然后又因为是常量,所以对是s[0]的赋值操作是不合法的。
6、写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
7、嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
8、关键字static的作用是什么?
9、关键字const有什么含意?
表示常量不可以修改的变量。
10、关键字volatile有什么含意?并举出三个不同的例子?
提示编译器对象的值可能在编译器未监测到的情况下改变。

17.进程之间通信的途径
管道:以文件系统为基础
资源竞争及进程推进顺序非法
19.死锁的4个必要条件
互斥、请求保持、不可剥夺、环路
鸵鸟策略、预防策略、避免策略、检测与解除死锁
FCFS(先来先服务),优先级,时间片轮转,多级反馈
22.类的静态成员和非静态成员有何区别?
类的静态成员每个类只有一个,非静态成员每个对象一个
23.纯虚函数如何定义?使用时应注意什么?
是接口,子类必须要实现
24.数组和链表的区别
数组:数据顺序存储,固定大小
连表:数据可以随机存储,大小可动态改变

25.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?
TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于
UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。
tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好

面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?

进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候
操作系统就帮你创建了一个主线程。

每个线程有自己的堆栈。
DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL
中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调
用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创
建的线程所执行,那么是不是说DLL有独立的堆栈?

以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的
内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中
删除,很有可能导致程序崩溃

第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是12
30,所以输出-128。
这两道题都是在考察二进制向int或uint转换时的最高位处理。

当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些
),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用
内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你
是可以继续访问这块地址的。

sizeof()和初不初始化,没有关系;

}

我要回帖

更多关于 请问找规律的题怎么做 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信