程序员面试准备

内存分配形式

(1)BSS:用来存放程序中未初始化的全局数据和静态数据的一块内存区域,BSS属于静态内存分配,程序结束后静态变量资源由系统自动释放。
(2)数据段:用来存放程序中已经初始化的全局变量的一块内存区域,数据段属于静态内存分配。包含static声明的变量。
(3)代码段:用来存放程序执行代码(包括类成员函数和全局函数以及其他函数代码)的一块内存区域。这部分区域的大小在程序运行前就已经确定。
(4)堆:存放进程运行中被动态分配的内存段,大小不固定,如用malloc和new分配的内存就在堆上。堆一般由程序员自己释放,若程序员不释放,程序结束时由操作系统回收。它跟数据结构中的堆不是一回事,分配方式类似于链表。
(5)栈:存放临时创建的局部变量,不包含static声明的变量。栈由编译器自动分配释放。
栈是向下增长的,堆是向上增长的。
【注意】申请的效率不同:
栈:栈由系统自动分配,速度快,但是程序员无法控制。
堆:堆是有程序员自己分配,速度较慢,容易产生碎片,不过用起来方便。
栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。

内存泄漏

valgrind用于查内存泄漏
堆是动态分配内存的,并且可以分配很大的内存,使用不当就会产生内存泄漏,频繁的使用malloc和new会产生内存碎片。所谓内存泄漏是由于疏忽或者错误造成程序未能释放已经不再使用的内存的情况。一般常说的内存泄漏是指堆内存泄漏,因为失去对该段内存的控制而造成的内存的浪费。一般用malloc或者是用new从堆中分配到一块内存,用完以后一定要用free或者new来释放掉,不然就会使得这块内存不能再被使用,造成内存泄漏。
内存泄漏会出现导致系统出现CPU资源耗尽的严重后果。

TCP和UDP

TCP和UDP

TCP拥塞控制

拥塞控制

ARP

ARP

写时复制

新建进程时,父进程和子进程共享内存,不进行复制,而且他们的访问权限是只读,如果父进程或者是子进程有其一想要修改这些区域,则为修改区域的那块内存制作一个副本。

僵尸进程

僵尸进程是当一个子进程在其父进程还没有调用wait()或waitpid()的情况就退出,以至于父进程没有回收子进程,去释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管去回收其占用的相关资源。
任何一个子进程(init除外)在exit()之后,并非马上就消失,而是留下一个称为僵尸进程的数据结构等待父进程处理。如果子进程在exit()之后,父进程没有来得及处理,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。

孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。孤儿进程没有什么危害。

进程与线程的区别

  1. 进程有自己独立的内存,线程共享所属进程的内存空间。
  2. 不同进程之间相互独立;同一个进程的不同线程之间共享该进程的所有资源。
  3. 启动一个进程要比启动一个线程慢。
  4. 进程是一次程序执行,线程是程序中某一片段的执行。
  5. 进程是系统进行资源分配的基本单元,线程是CPU调度的基本单位。
  6. 一个线程只属于一个进程,一个进程至少有一个线程。

fork和vfork

(1)fork是克隆一份父进程,包括数据段、堆和栈,代码段共享,fork后父进程先执行还是子进程先执行取决于调度算法。fork子进程可以用于和父进程执行一样的程序,也可以通过调用exec()执行新程序。
(2)vfork主要用于通过子进程执行新程序,所以并不会复制一份父进程,在调用exec()或者是exit()之前跟父进程共享内存,调用后用新程序资源。vfork后子进程先执行,然后父进程恢复执行。

进程间通信

进程间通信

线程同步有哪些机制

(1)临界区:通过对多线程的串行化来访问数据。
(2)互斥量:保证公共资源不会同时被多个线程访问。
(3)信号量:允许多个线程在同一时刻访问同一个资源。
(4)事件:用来通知线程事件已发生,通过设置标志位。

虚拟内存

虚拟内存是相对于物理内存而言的,它使得应用程序以为自己拥有连续可用的内存,其实它通常被分为多个物理内存碎片,还有的在外部磁盘存储器上,在需要时进行数据交换。
优点:
(1)扩大地址空间
(2)公平分配内存,每个进程都相当于有了同样大小的虚存空间。
(3)可以实现进程间通过共享虚存通信。

cache替换算法

(1)随机算法
(2)先进先出
(3)近期最少使用(LRU)Recently
(4)近期最少使用(LFU)Frequently
LRU关键是看页面最后一次被使用到发生调度的时间长短;而LFU关键是看一定时间段内页面被使用的频率。

哈希表的冲突解决方式

哈希表:通过哈希函数把关键字和其位置一一对应
哈希函数的构造方法:
(1)直接定址法,根据k值确定位置。
(2)取余法,用关键字k除以不大于哈希表长度的一个数(一般是哈希表长度,或者是不大于其的最大质数)
(3)数字分析法,如果实现已经知道了关键字的每一位分布情况,并且关键字位数大于哈希表的地址位数(比如99就是两位),可以选取关键字中比较均匀的几位作为哈希地址。
(4)平方取中法,取关键字进行平方运算后的中间几位作为哈希地址,取几位由哈希表长度决定。
哈希解决冲突的办法:
(1)线性探测:
当发生冲突的时候,从发生冲突的位置开始,向后一次探测空闲位置,如果到最后还没有找到就从哈希表的第一个位置开始继续查找。

容易发生聚集现象,比如哈希地址不同的关键字试图占用同一个新的地址。
只要哈希表未满,一定能探测到空闲单元。

(2)平方探测:

避免了聚集
不一定能保证一定会探测到空间,因为只探测了哈希表一半的空间。

(3)拉链法:
将冲突地址存储在一个单链表中,哈希表的地址单元存储的不再是数据,而是各个单链表的头指针。

野指针

野指针是指向不可用内存指针,任何指针变量在创建时不会自动成为NULL(空)指针,其默认值是随机的,所以指针变量在创建的同时应该被初始化,或者将指针设置为NULL,或者是指向合法内存,否则就会变成野指针。
同时指针通过free或者是delect把指针所指的内存给释放掉了,但是并没有把指针本身释放掉,一般通过判断是否是NULL来防错,但是野指针既不是NULL又不指向合法内存。
第三种是指针操作超过了变量的作用范围。

空指针

空指针是一个特殊的指针,也是唯一一个对任何指针类型都合法的指针,指针变量具有空指针值表示它当时处于闲置状态,没有指向有意义的内容。
通用指针可以指向任何类型的变量,通用指针的类型用(void*)表示,因此也称为void指针。

引用和指针的区别与联系

  1. 引用是定义一个变量来共享另一个变量的内存空间,来提高程序的并发效率;指针是指向另一个内存空间的变量,自己本身也有内存空间。
  2. 引用只能在定义时被初始化一次,之后不能再改变,引用其实是别名;指针也最好初始化,可以初始化为NULL,但是它所指向的地址可以被改变。
  3. 引用时不需要解引用(*),指针需要。
  4. 对引用sizeof()得到的是所指向变量的大小;对指针sizeof()得到的是指针本身的大小。
  5. 指针和引用运用自增(++)不同,引用是值进行自增,而指针是地址进行自增。

malloc和new的区别

  1. malloc是库函数,new是运算符
  2. malloc需要手动计算申请内存大小,new可以自动计算。
  3. malloc返回的指针是任意类型,new返回的类型是定义时指定的类型。
  4. new分3步,第一步调用operator new分配指定大小的空间,返回类型为void*,其实质上是调用malloc实现的;第二步是强制类型转换;第三步是在已分配好的空间上构造对象。
  5. malloc如果申请内存失败,返回值是0;new实际上是在循环调用malloc,如果malloc返回为0,就抛出异常并尝试释放空间来满足需求,直到可以申请到空间。

局部变量、全局变量、静态变量

局部变量:局部变量也只有局部作用域,它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。在栈上。
全局变量:全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern关键字再次声明这个全局变量。在数据段。
静态局部变量:静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,静态局部变量只对定义自己的函数体始终可见。
静态全局变量:静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。在数据段。

C++ 中class和struct的区别:

  1. 如果不做权限说明,class默认是private,struct默认是public。
  2. class可以用于定义模板参数,struct不可以。

public、protected和private继承:

首先无论哪一种继承,子类只能访问基类的public和protected成员,不能访问private成员。

  1. public继承不改变基类的成员属性;
  2. protected继承将基类的public转换为protected;
  3. private继承将基类的public和protected转化为private。

gdb的基本命令

c 继续运行
n 单步运行(不进入函数)
s 如果有函数则进入函数执行
p 变量名 打印变量的值
b 函数名 设置断点
d 断点号 删除断点
q 退出
i b 输出所有断点
bt 查看调用栈

算法

第一个只出现一次的字符
快排
快排优化
删除排序数组中的重复项
二叉树的中序遍历
二叉树的层次遍历
二叉树的前序遍历
二叉树的后序遍历
反转链表
环形链表
环形链表 II
链表中倒数第k个结点
删除链表的倒数第N个节点
前K个高频单词
最大堆
两数之和
回文链表
二叉树的所有路径
相交链表
数组中的第K个最大元素
最大子序和
无重复字符的最长子串
合并两个有序链表
数据流中的中位数
对称二叉树
strcpy与strncpy函数的区别及其C语言实现过程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章