前言
首先祝大家兔年快乐,2023年技术“兔”飞猛进!
无论你是已经步入工作岗位的技术人er,还是在校学生,面试总会是一段不可缺少的经历,那么这篇文章就给大家介绍一下我在学习过程中发现的面试问题吧。
对于面试
大二计算机小白一枚,已经在入手面试题目了,刚开始很基础的面试题目也能把我整的云里雾里的,根本无从下手,才知道自己的水平是多么的不好,不过每一次的程序bug都能给我不小的收获,在网上查了查大部分公司的面试流程,并把一些已经在计算机岗位上实习的学长学姐给出的一些意见做了做汇总,大致上是了解了,但是万变不离其宗,无论怎样的面试,岗位相关的专业知识肯定是会问的,这篇文章总结了两个计算机岗位面试经常问道的题目,持续学习积累中,这篇文章涉及到的知识一定不仅限于此。
面试题
面试题一:
对于堆和栈你是如何理解的,最好是用一个简单的程序描述一下。
问题剖析:
堆和栈的问题可以说是在计算机的学习中很常见的了,特别是在数据结构中,“堆”,“栈”绝对是经常出现的字眼,首先我们来简单回顾一下堆和栈是什么,然后可以从两者的区别联系方面来回答这个问题,并利用一个简单的c++程序来描述一下:
堆,是动态分配内存的一种存储形式,随意读取且方便。
可以看成一组数组对象以二叉树的形态分布,运行时动态分配内存,对读取顺序无限制。
栈,是一种只能后进先出读取的线性表,读取顺序限制性强。并且仅能在表尾进行插入和删除操作的线性表,遵循后进先出的原则。
问题解答:
堆和栈的区别与联系:
堆 是一种动态的概念,它的大小是受动态变化的,取决于程序运行的那一刻所计算的数据,其访问速度相对于栈来说比较慢;堆是在进程中进行的,并且不是独立进程,因此所有的线程都可以对堆进行访问,从访问权限上来说堆是不安全的。
栈 是一种静态概念,它的大小是在编译时由程序员确定好的;比如函数的调用就是在栈上进行的,当一个函数被调用后,里面的权限是无法被另一个栈访问的,也就是说不同函数之间的栈数据是无法共享的,那么在安全性上就要比堆安全;
堆和栈的优缺点:
说到这里,堆和栈的优缺点应该也能答出来一二了吧:
堆
优点:堆申请的空间大;可以动态地分配内存大小。
缺点:内存泄漏。如果由于某种原因程序没有释放,就会造成内存泄漏,出现内存浪费;比如在c++中,我们使用new来创建一个对象时,返回的是一个对象指针,这个指针指向本类刚创建的这个对象。在c++中分配给指针的只有存储指针值的空间,但对象所占用的空间分配在堆上,因此使用new来创建对象时,必须使用delete来释放内存。
易产生内存碎片。前面说到了堆的处理效率是比较低的,因此就会产生很多自定义的内存碎片;
线程不安全。因为堆不是独立进程,在程序运行过程中其他的进程可以对其进访问。
栈
优点:线程独立,安全性较高;栈数据是可以共享;内存可以及时得到回收,内存更好管理。
缺点:栈获得的空间较小,存在栈中的数据大小和生存期必须是确定的,数据的固定性也让栈缺乏灵活性。
栈溢出问题(stack overflow);由于栈的大小是有限的,当出现局部数组过大或递归调用层次过多,会超出栈的容量;并且栈上的buffer是大小固定的,如果指针或者是数组越界的话,就会影响到栈上原有的数据,造成栈溢出问题。
程序描述
这里用到了c++中的析构函数来简单解释一下堆和栈(当然在实际开发当中堆和栈远比这要复杂的多,举个简单的小例子比较容易懂):
usingnamespacestd; classA{ public: A() { cout<<"A的构造函数"<<endl; } ~A() { cout<<"A的析构函数"<<endl; } }; classB{ A*a;//在B中定义一个指针 public: B() { cout<<"B的构造函数"<<endl; a=newA;//指针指向堆区空间 ,使用new生成对象指针时,自动调用本类的构造函数 } ~B() { cout<<"B的析构函数"<<endl; deletea;//使用关键字new 创建的对象,用delete来撤销 ;使用delete删除这个对象时,首先调用本类的析构函数,再释放占用的内存。 } }; intmain() { Bb;//B的对象b定义在栈区,出栈之后自动调用本类的析构函数 return0; }
运行结果:
假如将“delete a;”注释掉,那么就会出现内存泄露的情况,而析构函数可以清理类中有指针、并且指向堆区空间的成员,释放指针指向的堆区空间,防止内存泄露。
假如我们要使用内存庞大的数据或者是数据大小不确定的时候可以使用堆;如果数据内存较小的话,我们可以使用栈。
简单补充:
在js的数据类型中,我们知道有基本数据类型和引用数据类型,其中
基本数据类型: Number、String、Boolean、Undefined、Null、Symbol(es6新增的原始数据类型)是存储在栈中的,基本数据类型大小固定,占据空间小,被频繁使用。它的赋值方式是深拷贝。
引用数据类型: object、 array、 function 存在堆中。当我们需要访问这三种引用类型的值时,首先得从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。它的数据类型是浅拷贝。
举个例子:
//基本数据类型(深拷贝,存放在栈)vara=10; varb=a; console.log(b);//输出10
// 引用数据类型(浅拷贝,存放在堆)vara=Object();//a的数据类型是objectvarb=a; b.num="20";//b的num属性添加到堆内存中,实际上a和b共同指向了一个堆内存对象console.log(a.num);//输出20
最后
这篇文章就到这了,后期还会更新更多学习分享,期待和大家的交流!
如有不足,感谢指正!