前言

程序语言基础横跨操作系统存储管理、编程语言分类、编译原理、文法自动机、程序执行机制多个板块,知识点比较散。本文按知识模块拆解,用通俗语言梳理核心考点,不堆砌晦涩术语。

一、内存存储管理(程序运行底层核心)

内存管理的核心目的:让多个程序安全、高效共用内存,实现内存合理分配与回收、地址隔离,屏蔽硬件差异,提升内存利用率,支撑程序并发运行。

计算机主流三种内存管理方式,核心区别在于划分依据、地址结构、碎片类型。

1. 页式存储(硬件划分)

页式存储

  • 划分规则:将内存和程序逻辑空间划分为固定大小的页面
  • 地址结构:逻辑地址 = 页号 + 页内偏移
  • 工作逻辑:页号查询页表,获取物理块号;页内偏移固定不变,直接复用
  • 物理地址公式物理地址 = 物理块号 × 页面大小 + 页内偏移
  • 优缺点:无外部碎片,内存利用率高;会产生页内碎片(页面空间未占满浪费)
  • 补充:页表本身存放在内存中,每个程序运行时有页表基址寄存器(PTBR)指向当前进程的页表;分页对程序员完全透明,由操作系统和MMU(内存管理单元)自动完成地址转换

2. 段式存储(用户逻辑划分)

段式存储

  • 划分规则:根据程序逻辑模块划分(代码段、数据段、栈段),段长不固定
  • 地址结构:逻辑地址 = 段号 + 段内偏移
  • 工作逻辑:段号查询段表,获取段起始基地址
  • 物理地址公式物理地址 = 段基址 + 段内偏移
  • 优缺点:贴合编程逻辑,方便程序模块化管理;易产生外部碎片(内存零散空隙)
  • 补充:分段对程序员可见,编写底层代码时能直接感知代码段、数据段的划分;段表存放每个段的基址和段长,地址转换时会先校验段内偏移是否超出段长

3. 段页式存储(结合两者优点)

段页式存储

  • 核心逻辑:先分段、段内再分页
  • 地址结构:段号 + 页号 + 页内偏移
  • 工作逻辑:先根据段号找到对应段,再从该段的页表中根据页号找到物理块号,最后页内偏移直接拼入
  • 特点:兼顾段的逻辑性和分页的高利用率;缺点是需要查询段表、页表两次,地址转换速度较慢
  • 补充:现代操作系统多采用分页或段页式,纯段式存储已很少单独使用;硬件缓存TLB(快表)可加速地址转换,命中时无需多次查表

4. 虚拟内存与局部性原理(内存管理延伸)

虚拟内存
虚拟内存是现代内存管理的重要延伸,核心思路是把硬盘空间当作内存的"备用仓库":

  • 局部性原理:程序在任一时刻访问的地址趋于集中(时间局部性:刚访问的数据可能再次访问;空间局部性:刚访问地址附近的地址也可能被访问)
  • 换入换出:当内存不足时,将暂时不用的数据块换出到硬盘交换区,需要时再换入
  • 缺页中断:程序访问的页面不在内存时,CPU触发缺页中断,由操作系统从硬盘加载;频繁缺页会导致"抖动"(thrashing),系统性能急剧下降

通俗理解:虚拟内存就像厨房太小放不下所有餐具,把不常用的碗盘收进储物柜(硬盘),要用的时候再拿出来,不过拿取过程耗时较长。

高频考点专项记忆(存储管理)

易混坑点
  1. 页内偏移无需转换,是地址中唯一固定不变的部分
  2. 分页产生页内碎片,分段产生外部碎片
  3. 段页式地址转换需两次查表(先段表、后页表),比纯分页慢
  4. 快表(TLB)是硬件缓存,存放最近常用的页表项,命中后地址转换只需一次内存访问
记忆口诀

页固定,段可变;
页查块,段查基;
偏移不用去翻译,直接拿来用到底;
页内碎片页里剩,段外碎片到处生。

二、编程语言分类

1. 按层级划分:低级语言 & 高级语言

低高级语言

低级语言(贴近硬件)

包含机器语言、汇编语言。

  • 机器语言:纯二进制指令,CPU可直接执行,速度最快,但是可读性极差、完全依赖硬件、无移植性
  • 汇编语言:机器语言的符号化形式,需汇编器翻译为机器码
  • 整体特点:执行效率高、开发难度大、可移植性极差
  • 补充:汇编语言与机器语言基本一一对应(如 MOV AX, BX 对应某个特定机器码),因此汇编被视为"助记符"而非真正的高级语言;不同CPU架构(x86、ARM等)的汇编指令集各不相同
高级语言(贴近人类)

代表语言:Java、Python、C++、Go等

  • 特点:语法贴近自然语言,可读性强、开发效率高、屏蔽底层硬件差异、可移植性好
  • 短板:无法直接运行,必须经过编译或解释翻译后才能被CPU识别执行
  • 补充:C语言常被称为"中级语言"——既具备高级语言的结构化特性,又保留了指针、位运算等底层操作能力

2. 按类型检查划分:静态 & 动态类型语言

动静态语言
核心区分标准:数据类型检查的执行时机

静态类型语言
  • 检查时机:编译阶段完成类型检查
  • 规则:变量声明时必须指定固定数据类型
  • 代表:C、C++、Java、Go
  • 优缺点:提前排查类型错误,程序运行稳定、速度快;代码书写相对繁琐
  • 补充:Java虽是静态类型,但具有类型推断var关键字,Java 10+),可在编译期自动推导类型,简化写法,但类型本身仍在编译期固定
动态类型语言
  • 检查时机:程序运行阶段才校验数据类型
  • 规则:变量无需预先声明类型,赋值即确定类型,且类型可在运行时改变
  • 代表:Python、JavaScript、PHP
  • 优缺点:编码灵活高效、调试方便;运行时易暴露类型错误,执行性能偏弱
  • 补充:Python 3.6+ 支持类型注解(Type Hints),如 def add(a: int, b: int) -> int:,但这仅是提示性质,运行时不会强制校验,本质仍是动态类型

3. 强类型 & 弱类型(独立维度)

  • 强类型:运算时不允许隐式类型转换(如Python:"1" + 2 直接报错)
  • 弱类型:运算时会自动进行隐式类型转换(如JavaScript:"1" + 2 得到字符串 "12"
  • 核心理解:静态/动态区分"何时检查",强/弱区分"检查多严格",两者独立——Java是静态+强类型,Python是动态+强类型,C是静态+弱类型,JavaScript是动态+弱类型

三、程序执行方式:编译器 & 解释器

所有高级语言,只有编译、解释两种核心执行方式,现代语言多为混合模式。
编译器和解释器

1. 编译器

  • 核心逻辑:全文一次性翻译,将完整源码编译为机器码/字节码,生成独立可执行文件
  • 执行流程:源码 → 编译 → 生成产物 → 脱离源码直接运行
  • 特点:一次编译、多次运行,运行速度快;代码修改后需重新编译
  • 代表语言:C、C++
  • 补充:编译型语言生成的可执行文件与操作系统及CPU架构强绑定,Windows上的 .exe 无法直接在Linux上运行,这是可移植性差的直接体现

2. 解释器

  • 核心逻辑:逐行翻译、边译边跑,不生成任何可执行文件
  • 特点:启动速度快、调试便捷;重复执行代码效率低(每次循环都要重新翻译)
  • 代表语言:Python、JavaScript
  • 补充:解释器省去了编译等待时间,尤其适合快速原型开发;但运行时多了一层翻译开销,CPU密集任务中性能明显弱于编译型语言

3. 混合模式

主流语言优化方案,例如Java:源码编译为字节码(.class文件),再由JVM虚拟机解释执行,兼顾编译的高效和解释的灵活性。

  • 补充:Java的JIT(即时编译器)会在运行时把热点字节码直接编译为本地机器码缓存起来,后续调用无需再解释,大幅提升长期运行性能;C#的CLR(公共语言运行时)也采用类似机制。Python的PyPy版本同样实现了JIT优化,执行速度远超标准CPython

四、完整编译六大流程(必考顺序)

完整编译流程
源码从编写到生成机器指令,必须经过固定六个阶段,顺序不可颠倒:

  1. 词法分析:拆解源码字符串,识别关键字、变量、运算符等基础单词(Token)
  2. 语法分析:校验代码语句结构合法性,生成抽象语法树(AST)
  3. 语义分析:核心做类型检查、作用域校验,排查逻辑语义错误
  4. 中间代码生成:生成与硬件无关的中间代码(三地址码),适配多平台
  5. 代码优化:等价改写中间代码,删减冗余运算,提升执行效率
  6. 目标代码生成:将优化后的中间代码,翻译为对应设备的机器指令/汇编指令

编译流程补充要点

  • 符号表:贯穿整个编译过程,记录所有标识符的类型、作用域、内存位置等信息,各阶段都需查询或更新
  • 出错处理:也贯穿全过程,遇到错误时需报告具体位置和类型(警告/错误),尽量继续编译以发现更多问题
  • 前端 vs 后端:词法分析→语法分析→语义分析→中间代码生成统称"前端"(与硬件无关),代码优化→目标代码生成统称"后端"(与硬件相关),前后端分离使同一编译器可支持多语言多平台(如GCC支持C/C++/Fortran,可输出x86/ARM等多种架构机器码)

高频考点专项记忆(编译原理)

易混坑点
  1. 语法分析只查结构,类型错误、语义错误由语义分析负责
  2. 代码优化针对中间代码,不修改原始源码
  3. 编译器的前端与硬件无关,后端与硬件相关;跨平台编译本质是替换后端
  4. 符号表贯穿全程,并非某一阶段独有
记忆口诀

编译一次出文件,解释逐行马上干;
词拆单,语造树,语义检查类型数;
中间生成再优化,最后产出机器码。

五、编译原理基础概念

1. 正规集、正规式、有限自动机

  • 正规集:符合规则的字符串集合,用于定义编程语言合法单词
  • 正规式(正则表达式):用来简洁表示正规集的公式,如标识符规则:[a-zA-Z][a-zA-Z0-9]*
  • 有限自动机:识别正规集的数学模型,分为DFA(确定)、NFA(非确定),是词法分析器的底层实现

通俗理解:正则定规则,自动机做识别。

确定有限自动化

  • DFA(确定有限自动机) :每个状态在某个输入下最多只有一个转移目标,识别效率高,实现简单
  • NFA(非确定有限自动机) :某个状态下同一输入可能有多个转移目标,更易构造,但需转换为DFA才能高效实现
  • 词法分析器生成工具(如Lex、Flex)本质就是读取正规式定义,自动构造对应的有限自动机代码

2. 后缀表达式(逆波兰表达式)

逆波兰表达式

  • 中缀表达式:日常书写格式(a+b*c),存在优先级、括号,计算机难以直接运算
  • 后缀表达式:运算符后置(a b c * +),无括号、无优先级问题
  • 运算逻辑:依托栈结构,数字入栈、运算符弹出两个操作数计算,结果压栈,极简高效
  • 应用场景:编译器表达式运算的标准中间格式

后缀表达式手动转换方法:按运算顺序加括号,将运算符移到对应右括号后面,再逐层去括号。

示例:a * (b + c) / d

  • 第一步:(a * (b + c)) / d

  • 第二步:(a (b c +) *) d /a b c + * d /

  • 表达式树:中缀对应二叉树的中序遍历,后缀对应后序遍历,前缀表达式(波兰表达式)对应先序遍历,三者本质是同一棵树的不同遍历方式

六、程序三大基础控制结构

所有复杂程序,均由三种基础结构组合而成,是结构化编程的核心:
三大结构

  1. 顺序结构:代码从上至下逐行依次执行
  2. 分支结构:if-else、switch,根据条件选择性执行代码
  3. 循环结构:for、while、do-while,重复执行指定代码块

结构化编程定理

  • 1966年Böhm-Jacopini定理证明:任何程序都可以只用顺序、分支、循环三种结构实现,无需goto语句
  • 单入口单出口:每个结构只有一个入口和一个出口,保证程序逻辑清晰、可验证
  • 滥用goto会导致"面条代码"(spaghetti code),逻辑混乱难以维护,现代编程语言已基本淘汰或限制goto使用

七、函数参数传递机制

编程语言两大参数传递方式,核心区别:是否操作原始数据内存
函数传递

1. 传值调用

  • 逻辑:复制实参的值,生成独立副本传给形参
  • 特性:函数内部修改形参,不会影响外部原始实参
  • 通俗理解:修改复印件,原件无变化

2. 传址(引用)调用

  • 逻辑:将实参的内存地址传递给形参,形参直接指向原始数据
  • 特性:函数内部修改数据,外部实参同步改变
  • 通俗理解:直接修改原件

传值和传址调用示例

传值和传址

参数传递机制补充(高频面试点)

  • Java:基本类型(int、char等)采用传值;对象类型传递的是引用的副本(即地址值的拷贝),形参和实参指向同一对象,修改对象属性会影响外部,但更换形参指向新对象不会影响外部引用
  • Python:统一采用"传对象引用"方式(类似Java的对象传递),重新赋值形参不会改变外部绑定

本质理解:一切传递本质上都是"值"——要么是数据本身的值(传值),要么是内存地址的值(传址)。“引用传递"传递的也是地址这个"值”,只是这个值被用来定位原始数据。

高频考点专项记忆(参数传递)

易混坑点
  1. C语言无原生引用传递,仅支持传值;需通过指针传递地址,模拟传址效果
  2. Java"引用传递"说法不严谨:正确说法是"传值,但值是对象引用的副本"
  3. 传址调用中,形参和实参指向同一块内存地址,改形参=改实参
记忆口诀

传值复制一份本,内部改动外部稳;
传址给到原地址,一改全都跟着移;
C无引用只有值,指针拿来做代替。

八、整体核心知识总结

  1. 内存存储:页固定、段可变,分页管内存、分段管逻辑,碎片类型各不同
  2. 代码执行:编译生成文件高速运行,解释逐行实时执行,六大编译步骤顺序固定
  3. 参数传递:传值不改原值,传址全局生效,C语言指针模拟引用
  4. 语言本质:高级语言需翻译、静态语言早校验、动态语言更灵活

所有枯燥的计算机语言基础,本质就是一套完整链路:内存承载程序运行 → 语言规范定义代码格式 → 编译/解释完成翻译 → 控制结构流转逻辑 → 参数传递实现数据交互
编译过程
把这套链路拆开细看:

程序员用高级语言写代码 → 编译器做词法/语法/语义分析确保代码正确 → 生成中间代码再做优化 → 最终输出机器指令 → CPU执行时需要内存管理(分页/分段)将指令和数据装入内存 → 函数调用时通过传值/传址完成数据传递 → 顺序/分支/循环控制代码执行流向 → 程序跑完释放内存空间。

整个链路环环相扣,任意环节出问题程序都无法正常运行。考试中无论考到哪个节点,都要能快速定位它在全链路中的位置和作用,这是理解而非死记硬背的核心优势。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐