完结】【CS50精翻·中文语音】哈佛大学《计算机科学导论》(2023)
🔗资源链接
✍我的笔记
一、内存的本质
- 所有变量都存储在内存中,每个字节对应唯一地址(如房间号)
%p格式化符专门用于打印地址值,如:int n = 42; printf("n 的地址:%p\n", &n); // 输出类似 0x7ffee3a5c78c- 十六进制表示(0 x 前缀)是内存地址的标准格式,如 0 x 1 A 3 F 对应十进制 6719
- %p,&n 可以打印出内存地址
二、指针的哲学
-
指针即地址
int *p = &n; // p 存储n的地址- 指针变量大小固定(32 位系统 4 字节,64 位系统 8 字节)
- 类型声明
int*告知编译器如何解析内存内容
-
解引用操作
*p = 100; // 通过指针修改原始变量 printf("%d", *p); // 读取指针指向的值 -
多级指针
int **pp = &p; // 指向指针的指针
三、数组与指针的量子纠缠
-
数组名本质
int arr[5] = {1,2,3,4,5}; printf("%p\n", arr); // 输出首元素地址arr[i]等价于*(arr + i)(编译器自动转换)
-
关键区别
特性 数组 指针 sizeof 返回总字节数 返回指针大小 赋值操作 不可整体赋值 可修改指向 地址常量 是(无法改变) 否
四、字符串的真相
-
存储本质
char *str = "Hello"; // 实际内存:H e l l o \0- 空字符
\0(ASCII 0)作为终止符 - 字符串字面量存储在只读段,修改会导致段错误
- 空字符
-
字符访问
printf("%c %c", str[0], *(str+1)); // 输出 H e -
动态字符串示例
char arr[] = {'W','o','r','l','d','\0'}; // 可修改的字符数组
五、内存操作的危险性
-
越界访问示例
int arr[3] = {1,2,3}; printf("%d", arr[5]); // 访问未分配内存 -
缓冲区溢出攻击原理
char buffer[4]; gets(buffer); // 输入超过3字符将覆盖其他内存区域
六、高级类型操作
-
typedef 创建类型别名
typedef unsigned char byte; // 定义新类型 typedef int (*Comparator)(int, int); // 函数指针类型 -
结构体指针
typedef struct { int x; int y; } Point; Point p = {3,4}; Point *ptr = &p; printf("坐标:(%d,%d)", ptr->x, (*ptr).y);
七、安全编程实践
-
指针初始化原则
int *p = NULL; // 未使用时初始化为空 if(p != NULL) { *p = 42; // 安全访问检查 } -
现代替代方案
- 使用 C++的智能指针(unique_ptr 等)
- 优先使用标准库安全函数(如 strncpy 代替 strcpy)
八、内存布局可视化
高地址
┌─────────────┐
│ 栈区 │ ← 局部变量(自动管理)
├─────────────┤
│ 堆区 │ ← malloc分配(手动管理)
├─────────────┤
│ 全局/静态数据区 │
├─────────────┤
│ 代码区 │ ← 字符串字面量(只读)
低地址
理解指针是掌握 C 语言的核心关键。这种直接操作内存的能力既是 C 语言强大性能的源泉,也是其危险性的根本。现代编程中,建议在需要底层控制时才使用指针,其他情况优先考虑更安全的抽象机制。 知道了指针后,可以探索所有计算机中的内存,也是黑客所利用的计数,通过计算机来运行代码,私处查看(这也是 C 语言的恐怖之处)