飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 编程基础概念

    • 冯·诺依曼体系结构
    • 数据在计算机中的表示
    • 编程语言的层次
    • C语言的起源与发展
    • C99标准的主要改进
    • 开发环境搭建
    • 第一个C程序
    • 编译与运行流程
    • 可移植性风险的三级体系
  • 第2章 数据类型与运算

    • 字符集与标识符
    • 关键字
    • 注释
    • char 类型
    • short 与 int
    • long 与 long long
    • 有符号与无符号
    • 取值范围与 limits.h
    • float 与 double
    • long double
    • _Bool 类型
    • 变量声明与定义
    • 常量
    • 转义序列
    • 算术运算符
    • 赋值运算符
    • 自增自减运算符
    • 关系与判等运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 逗号运算符
    • 运算符优先级
    • 隐式类型转换
    • 显式类型转换
  • 第3章 控制流

    • 表达式语句与空语句
    • 复合语句
    • if 语句
    • switch 语句
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
    • goto 语句
    • return 语句
  • 第4章 函数与模块化编程

    • 函数定义
    • 函数声明与原型
    • main 函数
    • 函数调用机制
    • 传值调用
    • 数组参数
    • 作用域
    • 存储期
    • 链接属性
    • static 与 extern
    • 递归
    • 头文件与源文件
    • 头文件保护
    • include 规则
  • 第5章 数组与字符串

    • 一维数组声明与初始化
    • 数组的存储模型
    • 数组访问与越界
    • 数组操作
    • 二维数组
    • 变长数组 VLA
    • 字符串基础
    • 字符串输入输出
    • 字符串处理函数
    • 字符串与数字转换
  • 第6章 指针

    • 指针的概念
    • 指针的声明与使用
    • 指针运算
    • const 与指针
    • 数组名与指针
    • 指针遍历数组
    • 指针与多维数组
    • 指针作为函数参数
    • 函数返回指针
    • 函数指针
    • 二级指针
    • 复杂声明解析
  • 第7章 结构体、联合体与枚举

    • 结构体定义与声明
    • 结构体初始化
    • 结构体成员访问
    • 结构体嵌套
    • 结构体指针
    • 结构体与函数
    • 联合体
    • 联合体与类型双关
    • 枚举类型
    • 位域
    • 内存对齐与填充
  • 第8章 动态内存管理

    • malloc 与 free
    • calloc 与 realloc
    • 内存泄漏
    • 悬垂指针
    • 内存分配策略
    • 自定义内存池
    • Valgrind 与内存检测
    • 内存碎片
    • 内存对齐分配
    • 常见内存错误
  • 第9章 文件输入输出

    • 文件打开与关闭
    • 文本读写
    • 格式化输入输出
    • 二进制读写
    • 文件定位
    • 错误处理
    • 标准流
    • 临时文件
    • 文件操作示例
  • 第10章 预处理器

    • 预处理器基础
    • 宏定义
    • 带参数的宏
    • 条件编译
    • 头文件包含
    • 预定义宏
    • 宏的高级技巧
    • 预处理器陷阱
    • 编译器特定扩展
  • 第11章 标准库概览

    • 标准库概述
    • assert.h
    • ctype.h
    • errno.h
    • float.h
    • limits.h
    • locale.h
    • math.h
    • setjmp.h
    • signal.h
    • stdarg.h
    • stddef.h
    • stdlib.h
  • 第12章 进阶主题

    • 内联函数
    • 变长数组 VLA
    • 复数类型
    • 布尔类型
    • stdint 与 inttypes
    • 灵活数组成员
    • 匿名结构体与联合体
    • 静态断言
    • 线程支持
    • 原子操作

冯·诺依曼体系结构

现代计算机的设计思想源于冯·诺依曼体系结构,它定义了计算机的五大基本组成部分。理解这一结构,有助于从底层把握程序的运行方式——代码和数据都以二进制形式存储在内存中,CPU 按顺序取指令、解码、执行,周而复始。

五大组成部分

运算器(Arithmetic Logic Unit, ALU)

运算器负责执行所有的算术和逻辑运算。当你写下 a + b 时,最终就是运算器完成了加法操作。它只能处理二进制数据,所以无论整数、浮点数还是字符,进入运算器之前都必须转换为二进制形式。

int a = 5, b = 3;
int c = a + b;      /* ALU 执行二进制加法:101 + 011 = 1000(即 8) */

控制器(Control Unit)

控制器是计算机的指挥中心,负责从内存中取出指令、解码,并协调其他部件执行。它并不直接处理数据,而是决定"什么时候做什么"。程序计数器(PC)记录着下一条要执行的指令地址,每执行完一条就自动递增。

存储器(Memory)

存储器用于存放程序指令和数据。冯·诺依曼体系的核心特征之一就是"存储程序"——程序指令和数据以同等地位存放在同一存储器中,CPU 按地址访问。内存可以看作一个巨大的字节数组,每个字节都有唯一的地址编号。

int x = 42;         /* 变量 x 的值 42 以 0x0000002A 的形式存入某段内存 */

输入设备(Input Devices)

键盘、鼠标、磁盘、网络接口等都属于输入设备,它们将外部信息转换为计算机能处理的二进制数据,送入存储器。

输出设备(Output Devices)

显示器、打印机、磁盘、网络接口等负责将处理结果从计算机内部输出到外部世界。printf 的最终目的,就是把内存中的数据通过输出设备呈现给你。

CPU 与内存的工作原理

CPU 和内存之间通过总线(Bus)连接,总线分为三类:

  • 地址总线:CPU 发出要访问的内存地址
  • 数据总线:在 CPU 和内存之间传输实际数据
  • 控制总线:传递读写控制信号

程序执行时,CPU 不断重复"取指-解码-执行"的循环:

  1. 根据程序计数器中的地址,从内存读取一条指令
  2. 解码指令,确定要执行的操作
  3. 执行操作(可能涉及运算器、读写内存、跳转地址)
  4. 更新程序计数器,指向下一条指令
/* 这段简单的 C 代码,最终会变成一系列机器指令存储在内存中 */
int main(void)
{
    int sum = 0;        /* 指令:分配内存空间,写入 0 */
    sum = sum + 1;      /* 指令:读取 sum,加 1,写回 sum */
    return 0;           /* 指令:将 0 放入返回寄存器 */
}

内存的分层结构

计算机使用多级存储体系平衡速度和容量:

层级典型容量访问速度特点
寄存器几十个纳秒级CPU 内部,速度最快
高速缓存(Cache)KB~MB 级几纳秒分 L1/L2/L3
主内存(RAM)GB 级几十纳秒程序运行时活跃区域
磁盘/SSDTB 级毫秒级持久存储

C 语言中的变量通常存放在主内存中,频繁使用的数据会被自动缓存到高速缓存。寄存器变量(register 关键字)建议编译器将变量放入寄存器,但现代编译器优化已足够智能,这个关键字更多是历史遗留。

程序在内存中的布局

一个运行中的 C 程序,其内存空间通常分为几个区域:

  • 代码段(Text Segment):存放编译后的机器指令,只读
  • 数据段(Data Segment):存放全局变量和静态变量
  • 堆(Heap):动态分配内存的区域(malloc 从这里申请)
  • 栈(Stack):存放局部变量、函数参数、返回地址,自动管理
int global = 10;            /* 数据段 */

int main(void)
{
    int local = 20;         /* 栈 */
    int *heap = malloc(4);  /* 堆 */
    free(heap);
    return 0;
}

栈向低地址增长,堆向高地址增长,两者相向而行。栈溢出(Stack Overflow)通常是因为递归太深或局部数组太大;堆溢出则是动态分配了过多内存。

下一页
数据在计算机中的表示