记一次某公司iOS面试总结
昨天去了一公司面试,面试官问的都是些很基础的东西,觉得虽然基础,但却在工作中可能会有用到,所以特意记录下来。
结合面试问题然后展出的一些相关的知识点~
Q:"abcd"占多大空间,int类型占多大?
A:
"abcd" 占用5个字节,因为双引号括起的叫字符串,并含一个字符串结束符
字符串长度strlen( "abcd")-》 4
占内存 sizeof ("abcd") -》 5
延伸:
位:"位(bit)"是电子计算机中最小的数据单位。每一位的状态只能是0或1。
字节:8个二进制位构成1个"字节(Byte)",它是存储空间的基本计量单位。1个字节可以储存1个英文字母或者半个汉字,换句话说,1个汉字占据2个字节的存储空间
一般32位操作系统中 int占用4字节(Byte)/32位,char占1字节(Byte),short占2字节(Byte)
Q:内存栈和内存堆的区别
A:
- 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
- 堆区(heap):由程序员分配释放,若没有释放,程序结束后由系统回收;
- 全局区(全局区)(static):全局变量和静态变量的存储放在一块,初始化的全局变量和静态变量在一块区域,未初始化的在相邻的另一块区域,程序结束后由系统回收;
- 文字常量区:常量字符串放在这里,程序结束后由系统回收;
- 程序代码区:存放函数体的二进制代码
例子:
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main() {
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456/0 在常量区,p3在栈上。
static int c =0;全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456/0放在常量区,编译器可能会将它与 p3所指向的"123456"优化成一个地方。
}
Q:进程和线程的关系
A:
-
进程是资源分配的最小单位,线程是程序执行的最小单位。
-
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
-
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
-
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
-
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
-
资源分配给进程,同一进程的所有线程共享该进程的所有资源。
线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。 -
处理机分给线程,即真正在处理机上运行的是线程。
-
线程是指进程内的一个执行单元,也是进程内的可调度实体。
Q:进程、线程、堆、栈的关系
在一个进程中的线程中 共享堆区,而进程中的线程各自维持自己的堆栈
(感觉这块说的有点太简单了,如果你有好的见解,不妨在下面👇评论区,写上你的看法,我会及时更新的)
Q:HTTP在七层结构中的哪个层? HTTPS呢
A:
七层结构:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
TCP属于传输层,HTTP属于应用层
HTTPS加密在传输层,传输层的功能包括是否选择差错恢复协议还是无差错恢复协议,以及同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包重新排序
HTTPS在数据传输过程中采用非对称加密方式
对称加密:加密数据用的密钥,跟解密数据用的密钥是一样的
非对称加密:加密数据的密钥(公钥),跟解密数据使用的密钥(公钥)不一样
公钥放在客户端,密钥放在服务端,公钥加密的数据只有密钥能解开,私钥加密的数据也只有公钥能解开
可信任的证书颁发机构CA颁发的证书里面包含了公钥信息
HTTPS虽然用到了公开密钥加密,但同时也结合了其他手段,如对称加密,来确保授权、加密传输的效率、安全性
整个简化的加密通信的流程就是:
小明访问XX,XX将自己的证书给到小明(其实是给到浏览器,小明不会有感知)
浏览器从证书中拿到XX的公钥A
浏览器生成一个只有自己的对称密钥B,用公钥A加密,并传给XX(其实是有协商的过程,这里为了便于理解先简化)
XX通过私钥解密,拿到对称密钥B
浏览器、XX 之后的数据通信,都用密钥B进行加密
注意:对于每个访问XX的用户,生成的对称密钥B理论上来说都是不一样的。比如小明、小王、小光,可能生成的就是B1、B2、B3.
握手:证书下发,密钥协商
数据传输:使用握手阶段协商的密钥加密
参照 //www.ruanyifeng.com/blog/2014/02/ssl_tls.html
Q:多线程使用问题
A:
Critical Section(临界代码段)
指的是不能同时被两个线程访问的代码段,比如一个变量,被并发进程访问后可能会改变变量值,造成数据污染(数据共享问题)。
Race Condition (竞态条件)
当多个线程同时访问共享的数据时,会发生争用情形,第一个线程读取改变了一个变量的值,第二个线程也读取改变了这个变量的值,两个线程同时操作了该变量,此时他们会发生竞争来看哪个线程会最后写入这个变量,最后被写入的值将会被保留下来。
Deadlock (死锁)
两个(多个)线程都要等待对方完成某个操作才能进行下一步,这时就会发生死锁。
Thread Safe(线程安全)
一段线程安全的代码(对象),可以同时被多个线程或并发的任务调度,不会产生问题,非线程安全的只能按次序被访问。
所有Mutable对象都是非线程安全的,所有Immutable对象都是线程安全的,使用Mutable对象,一定要用同步锁来同步访问(@synchronized)。
互斥锁:能够防止多线程抢夺造成的数据安全问题,但是需要消耗大量的资源
原子属性(atomic)加锁
atomic: 原子属性,为setter方法加锁,将属性以atomic的形式来声明,该属性变量就能支持互斥锁了。
nonatomic: 非原子属性,不会为setter方法加锁,声明为该属性的变量,客户端应尽量避免多线程争夺同一资源。
Context Switch (上下文切换)
当一个进程中有多个线程来回切换时,context switch用来记录执行状态,这样的进程和一般的多线程进程没有太大差别,但会产生一些额外的开销。
Q:快速排序算法实现
A:
算法思路:基于递归实现
- 选定一个合适的值(理想情况中值最好,但一般使用数组第一个值),称为“枢轴”(pivot);
- 基于这个值,将数组分为两部分,较小的分在左边,较大的分在右边;
- 一轮循环后,这个枢轴的位置一定在最终的位置上;
- 对两个子数组分别重复上述过程,直到每个数组只有一个元素;
排序完成。
参考代码:
void quickSort(int *arr, int _left, int _right) {
if (_left >= _right) return; // 左边的索引大于等于右边索引,代表已经整理完成一组
int left = _left;
int right = _right;
int key = arr[left];
while (left < right) { // 当left!<right时说明一轮扫描结束
while (left < right && key <= arr[right]) {
// 结束循环的条件是:找到第一个比key小的元素位置 && left<right
right--; // 向左扫描
}
arr[left] = arr[right]; // 找到第一个比key小的元素,补key值的空缺位
while (left < right && key >= arr[left]) {
// 这是left在左侧组内向右扫描,同上,不过注意结束循环条件相反
left++;
}
arr[right] = arr[left];
}
arr[left] = key; // 当组内扫描一遍完成后,key值回归
quickSort(arr, _left, left-1);
quickSort(arr, right+1, _right);
}
以上是本篇文章的所有内容~ 希望会对你有所帮助🙏