C 语言指针入门超详细笔记
2026/6/8 22:44:46 网站建设 项目流程

学习 C 语言绕不开指针,它也是很多初学者的难点。本篇结合实操代码、内存原理、易错点,从零带你吃透基础指针、指针运算、数组与指针联动,适合新手系统复习与收藏。

一、什么是指针 & 指针变量

1. 基础概念

内存中每一块空间都有地址,就像房间门牌号。

  • 指针:本质就是内存地址
  • 指针变量:专门用来存放地址的变量。

定义格式:数据类型 * 变量名

int a = 10; int* p; // 定义int类型指针变量p p = &a; // & 取地址符:取出变量a的地址,存入指针p

2. 两个核心操作符

  1. &取地址符取出变量首字节地址&变量名得到地址。
  2. *解引用操作符根据指针中存储的地址,找到对应内存空间,操作该空间的值。

示例演示:

#include<stdio.h> int main() { int c = 5; int* p = &c; printf("%d\n", *p); // 通过地址取值,输出 5 *p = 3; // 通过地址修改值 printf("%d\n", c); // 原变量被修改,输出 3 return 0; }

简单理解:指针相当于变量的 **“第二入口”**,可以绕过变量名直接读写内存。

二、指针变量的大小

指针存储的是内存地址,指针占用字节数只由编译环境决定,和指针类型无关

  • 32 位环境 (x86):地址占 32 位 → 所有指针统一占4 字节
  • 64 位环境 (x64):地址占 64 位 → 所有指针统一占8 字节

验证代码:

#include<stdio.h> int main() { printf("%zu\n", sizeof(char*)); printf("%zu\n", sizeof(int*)); printf("%zu\n", sizeof(double*)); return 0; }

三、指针类型的真正作用

既然指针大小和类型无关,那前面的char*int*有什么意义?指针类型决定两件事:解引用权限、指针 ± 整数时的偏移步长。

1. 解引用:决定一次能操作几个字节

  • int*:解引用一次访问4 字节
  • char*:解引用一次访问1 字节

示例:

#include<stdio.h> int main() { int a = 0x11223344; char* p = &a; *p = 0; // 仅修改低1个字节 return 0; }

调试可见:只有 1 字节数据被修改,这就是类型带来的访问权限差异

2. 指针 ± 整数:决定地址偏移步长

指针+1不是地址单纯 + 1,而是向后偏移一个「指向类型」的大小

  • int* + 1:地址向后偏移 4 字节
  • char* + 1:地址向后偏移 1 字节

四、特殊指针:void* 空指针

void*是通用空指针,特点:

  1. 可以接收任意类型变量的地址,常用于泛型场景;
  2. 不能直接解引用,也不能做±整数运算;
  3. 原因:void无具体类型,编译器不知道它一次该访问几个字节。

五、四大类指针运算(核心重点)

结合生活例子类比,方便记忆:

日期 + 天数 = 日期 | 日期 + 日期(无意义) 指针运算遵循相同逻辑:

  1. 指针 + 整数 = 指针(地址向后偏移)
  2. 指针 - 整数 = 指针(地址向前偏移)
  3. 指针 - 指针 = 整数(仅同一块连续内存有效,计算元素个数)
  4. 指针 + 指针:语法允许,但逻辑无意义,禁止使用

1. 指针 ± 整数:遍历数组(最常用)

数组是连续内存空间,配合指针遍历是 C 语言经典写法。

写法 1:指针不动,下标移动

#include<stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int sz = sizeof(arr) / sizeof(arr[0]); int* p = arr; // 数组名arr等价于 &arr[0] for (int i = 0; i < sz; i++) { printf("%d ", *(p + i)); } return 0; }

写法 2:指针自身移动(p++)

#include<stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int sz = sizeof(arr) / sizeof(arr[0]); int* p = arr; for (int i = 0; i < sz; i++) { printf("%d ", *p); p++; } return 0; }

写法 3:while 循环 + 地址比较(无额外循环变量)
利用指针可以比较大小的特性,终止条件:p < 数组末尾下一个地址

#include<stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int sz = sizeof(arr) / sizeof(arr[0]); int* p = arr; while (p < arr + sz) { printf("%d ", *p); p++; } return 0; }

易错提醒:arr[10] 是越界元素(取值),遍历判断必须用 &arr[10](取地址)。


2. 指针 - 指针:模拟实现 strlen 求字符串长度


规则:两个指针必须指向同一块连续内存,差值 = 中间元素个数。
自定义字符串长度函数

#include<stdio.h> int my_strlen(const char* a) { const char* p = a; // 字符串以 '\0' 作为结束标志 while (*p != '\0') { p++; } // 结束指针 - 起始指针 = 字符个数 return (int)(p - a); } int main() { char s[] = "abc"; printf("%d", my_strlen(s)); return 0; }

补充:C++ 环境建议参数加 const,匹配字符串常量 const char* 类型,避免编译警告。


六、高频易错点汇总


1.char s = "abc"; 错误
2.char 只能存单个字符(单引号 'a');字符串必须用 char[] 或 char*(双引号 "abc")。
正确写法:char s[] = "abc"; / char* s = "abc";
3.int* p = arr[0]; 错误
arr[0] 是数组元素值;指针需要存地址,正确:int* p = &arr[0]; / int* p = arr;
4.数组下标越界
int arr[10] 合法下标 0~9,arr[10] 是非法内存,严禁取值、解引用。
5.64 位环境指针相减警告
64 位下指针差值为 64 位整型,返回int会提示丢失数据,可加强制转换 (int)(p-a)。


七、学习总结


指针 = 内存地址,指针变量 = 存放地址的变量,核心操作 & 取地址、* 解引用;
指针大小由编译环境决定,类型决定访问字节数和偏移步长;
指针四大运算:±整数 遍历数组、-指针 求元素个数、指针可比较大小;
数组名本质是数组首元素地址,数组和指针可以灵活混用;
牢记边界问题:数组下标、字符串结束符 \0、内存越界是指针 bug 重灾区。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询