回望2022,拒绝间接性努力【面试题第一弹】

本文参与了 SegmentFault 思否年度征文「一名技术人的 2022」,欢迎正在阅读的你也加入。

前言

写这篇文章的时候已经是年初四,临近2023年的时候就已经看到了身边的同学陆续发出自己的年度总结,而自己虽是百感交集,但却迟迟下不了笔。直到今天才有了这篇删删减减的迟来的2022年度总结。

回望2022,拒绝间接性努力【面试题第一弹】_第1张图片

回望2022

说到2022年的关键词——行程码,健康码,核酸全员检测,阳了个阳...

但让我感触最深的是还是 “阳”,当朋友圈里满屏晒着自己的“阳过”图时,还有希望进入决赛圈的我一直心存着所谓“天选之子”的侥幸,但是不知为什么,却又想让自己被这个可怕的病毒盯上。当我真正感染上以后,才迷迷糊糊的知道自己为什么有“想要感染”的想法了————感染过后,原本都是早晨六点半起床开始新的学习计划的我硬是被闹钟叫到了七点半;原本是晚上十点半才结束一天的“知识更新”的安排也被打乱,不到九点就合上电脑打开手机刷起短视频来...就这样,将近一个月没有更新博客。

这种“光明正大”把自己放进舒适圈,然后竟少了那么多焦虑和负罪感,而我想要自己“阳”的真正目的其实是想要让自己有个能骗过自己的理由去松懈。

阳康后,真的发现自己有很长一段时间在间歇性努力,给自己创造“自我感动”的假象————想要考研,但备考计划却是断断续续的完成;想要更新技术博客,但更新一篇文章后,即使有了灵感也没有及时记录下来。偶然在逛论坛的时候发现一位博主写的年度总结中,就有一个词:间歇性努力。这让我有种被惊醒的感觉,我翻开自己的博客主页,发现最新的文章已经是一个月前,在草稿箱里面还存放着没有完善好的文章以及断断续续的经验总结。

间歇性努力往往比坚持带来的短暂快乐容易上瘾,并且自己努力的上限也会越来越低,而结果通常是恶性循环和事半功倍。

展望2023

2022年发现自己有了间歇性努力,2023年要让自己在该补充知识能量的时候跳出“舒适圈”。希望自己能够在新的一年“卯”足干劲,“兔”破困难。

面试第一弹

学习面试题,总结面试经验也是2023年的一个flag吧,这篇文章给大家带来的还有自己在学习上遇到的面试问题。

题目描述

对于堆和栈你是如何理解的,最好是用一个简单的程序描述一下。

问题剖析

堆和栈的问题可以说是在计算机的学习中很常见的了,特别是在数据结构中,“堆”,“栈”绝对是经常出现的字眼,首先我们来简单回顾一下堆和栈是什么,然后可以从两者的区别联系方面来回答这个问题,并利用一个简单的c++程序来描述一下:

,是动态分配内存的一种存储形式,随意读取且方便。
可以看成一组数组对象以二叉树的形态分布,运行时动态分配内存,对读取顺序无限制。

,是一种只能后进先出读取的线性表,读取顺序限制性强。并且仅能在表尾进行插入和删除操作的线性表,遵循后进先出的原则。

问题解答

堆和栈的区别与联系:

是一种动态的概念,它的大小是受动态变化的,取决于程序运行的那一刻所计算的数据,其访问速度相对于栈来说比较慢;堆是在进程中进行的,并且不是独立进程,因此所有的线程都可以对堆进行访问,从访问权限上来说堆是不安全的。

是一种静态概念,它的大小是在编译时由程序员确定好的;比如函数的调用就是在栈上进行的,当一个函数被调用后,里面的权限是无法被另一个栈访问的,也就是说不同函数之间的栈数据是无法共享的,那么在安全性上就要比堆安全

堆和栈的优缺点

说到这里,堆和栈的优缺点应该也能答出来一二了吧:


优点:堆申请的空间大;可以动态地分配内存大小
缺点:内存泄漏。如果由于某种原因程序没有释放,就会造成内存泄漏,出现内存浪费;比如在c++中,我们使用new来创建一个对象时,返回的是一个对象指针,这个指针指向本类刚创建的这个对象。在c++中分配给指针的只有存储指针值的空间,但对象所占用的空间分配在堆上,因此使用new来创建对象时,必须使用delete来释放内存。
易产生内存碎片。前面说到了堆的处理效率是比较低的,因此就会产生很多自定义的内存碎片;
线程不安全。因为堆不是独立进程,在程序运行过程中其他的进程可以对其进访问。


优点:线程独立安全性较高;栈数据是可以共享;内存可以及时得到回收,内存更好管理。
缺点:栈获得的空间较小,存在栈中的数据大小和生存期必须是确定的,数据的固定性也让栈缺乏灵活性。
栈溢出问题(stack overflow)由于栈的大小是有限的,当出现局部数组过大或递归调用层次过多,会超出栈的容量;并且栈上的buffer是大小固定的,如果指针或者是数组越界的话,就会影响到栈上原有的数据,造成栈溢出问题。

回望2022,拒绝间接性努力【面试题第一弹】_第2张图片

程序描述

这里用到了c++中的析构函数来简单解释一下堆和栈(当然在实际开发当中堆和栈远比这要复杂的多,举个简单的小例子比较容易懂):

using namespace std;
class A
{
  public:
    A()
  {  
    cout<<"A的构造函数"  <

运行结果:
图片.png

假如将“delete a;”注释掉,那么就会出现内存泄露的情况,而析构函数可以清理类中有指针、并且指向堆区空间的成员,释放指针指向的堆区空间,防止内存泄露。
回望2022,拒绝间接性努力【面试题第一弹】_第3张图片

假如我们要使用内存庞大的数据或者是数据大小不确定的时候可以使用堆;如果数据内存较小的话,我们可以使用栈。

简单补充:
在js的数据类型中,我们知道有基本数据类型和引用数据类型,其中
基本数据类型: Number、String、Boolean、Undefined、Null、Symbol(es6新增的原始数据类型)是存储在中的,基本数据类型大小固定,占据空间小,被频繁使用。它的赋值方式是深拷贝。
引用数据类型: object、 array、 function 存在中。当我们需要访问这三种引用类型的值时,首先得从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。它的数据类型是浅拷贝。

举个例子:

//基本数据类型(深拷贝,存放在栈)
var a=10;
var b=a;
console.log(b);//输出10
// 引用数据类型(浅拷贝,存放在堆)
var a=Object();//a的数据类型是object
var b=a;
b.num="20";//b的num属性添加到堆内存中,实际上a和b共同指向了一个堆内存对象
console.log(a.num);//输出20

总结

首先祝大家兔年快乐,新的一年越战越勇。也希望自己在2023年突破舒适圈拒绝间歇性努力

你可能感兴趣的:(后端程序员面试问题)