内存指针与字符串

指针的内存表示

指针是C语言的核心特性之一,其本质是存储内存地址的变量

  • 指针的大小取决于机器的字长(而非指向的类型)
    • 32位机器:指针占4字节
    • 64位机器:指针占8字节
  • 指针的类型信息仅在编译时使用,运行时指针仅仅是一个地址值
  • NULL 指针通常用地址0表示,在大多数系统上访问会触发段错误(segmentation fault)

指针运算

指针运算与数组紧密关联:

int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;        // p 指向 arr[0]
 
p + 1;                // 地址增加 sizeof(int) 字节(通常为4)
*(p + 2) = 30;        // 等价于 arr[2] = 30
int *q = &arr[4];
int diff = q - p;     // diff = 4(指针差值为元素个数,而非字节数)

关键点:

  • 指针加1并非地址加1,而是加上其所指向类型的大小
  • 指针减法的结果是元素个数(而非字节数)
  • 数组名在大多数表达式中隐式转换为指向首元素的指针

字符串的存储

C语言中的字符串以null-terminated(以 \0 结尾)的方式存储:

"Hello" 的内存布局:
H | e | l | l | o | \0
  • 字符串字面量存储在只读数据段(如 .rodata 段)
  • 字符数组 char s[] = "Hello"; 在栈上分配可修改的副本
  • 指针 char *s = "Hello"; 指向只读区域,不能修改其内容

指针数组 vs 二维数组

char *strs[] = {"Hello", "World", "CSAPP"};
// strs[0] 是 char*,指向字符串 "Hello"
// 每个字符串长度可以不同
 
char strs2[3][6] = {"Hello", "World", "CSAPP"};
// 每行固定宽度6字节,所有字符串必须等宽存储
// 未使用的字节用0填充

指针数组更灵活(每个字符串长度可以不同),但需要额外的指针存储空间;二维数组更紧凑,但灵活性差。

相关笔记

链接到