C语言指针

C语言指针详解(最清晰、最完整的入门到进阶指南)

指针是 C 语言中最强大、最重要、也最容易出错的核心特性。
一句话总结:指针就是“地址的变量”,它存储的是另一个变量(或内存块)的内存地址,通过指针可以“间接访问”和“操作”那块内存。

下面从零基础到高级,一步步把指针讲透。

1. 指针最基础的概念(必须死记)

int a = 10;          // 普通变量,值是 10
int *p = &a;         // p 是一个指针变量,存的是 a 的地址

// 三行最核心的理解:
printf("%d\n", a);     // 输出 10     (变量的值)
printf("%p\n", &a);    // 输出地址,如 0x7ffdf1234568
printf("%p\n", p);     // 输出地址,和 &a 相同
printf("%d\n", *p);    // 输出 10     (通过指针“解引用”得到的值)

最关键的三个符号(每天默写 10 遍,直到刻进 DNA)

符号含义读法(中文)英文说法
&取地址运算符“取地址”address-of operator
*1. 定义指针类型 2. 解引用(取值)“指针类型” / “解引用”pointer declaration / dereference
*p通过指针 p 访问它指向的内存的值“p 指向的值”value pointed by p

一句话记忆口诀
& 是“去哪找”,* 是“找来干什么”

2. 指针变量的定义方式(最容易混淆的地方)

int a = 10;
int *p1 = &a;           // 推荐写法:* 紧跟变量名
int* p2 = &a;           // 也可以,但容易误导
int *p3, q;             // p3 是指针,q 是普通 int(最常出错!)
int *p4, *p5;           // p4 和 p5 都是指针(正确)

正确记忆* 是跟变量走的,不是跟类型走的
所以永远写成 int *p 而不是 int* p,这样定义多个变量时才不会出错。

3. 指针的各种常见类型(必须掌握)

指针类型定义写法指向的内容大小(步长)典型用途
指向基本类型int *psizeof(int) 通常 4操作单个 int 变量
指向数组int arr[10]; int *p = arr;同上遍历数组(最常见)
指针数组int *arr[10];每个元素都是指针
数组指针int (*p)[10];整个数组大小指向整个数组(多维数组常用)
指向函数的指针int (*func)(int,int);回调函数、函数表
void 指针void *p;无步长(不能 ++)通用指针(malloc 返回的就是 void*)

4. 指针的经典用法(面试 + 实战必会)

4.1 指针遍历数组(最常见写法)

int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;            // 数组名就是首元素地址

for (int i = 0; i < 5; i++) {
    printf("%d ", *(p + i));     // 方式1:指针 + 偏移
    // 或
    printf("%d ", p[i]);         // 方式2:像数组一样用 [](本质相同)
    // 或
    printf("%d ", *p++);         // 方式3:指针自增(最简洁,但注意顺序)
}

4.2 交换两个变量(不用第三变量)

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 调用
int x = 5, y = 10;
swap(&x, &y);   // 必须传地址

4.3 动态内存分配(malloc / calloc / realloc / free)

#include <stdlib.h>

// 分配一个 int 大小的内存
int *p = (int *)malloc(sizeof(int));
if (p == NULL) { /* 分配失败处理 */ }
*p = 100;

// 分配 10 个 int 的数组
int *arr = (int *)malloc(10 * sizeof(int));

// 分配并清零
int *arr2 = (int *)calloc(10, sizeof(int));  // 全初始化为 0

// 扩容(很重要!)
int *new_arr = (int *)realloc(arr, 20 * sizeof(int));
if (new_arr) arr = new_arr;

// 释放(必须成对!)
free(p);
free(arr);
p = arr = NULL;   // 防止野指针

现代推荐(C99+):用 sizeof(*p) 而不是 sizeof(int)

int *p = malloc(sizeof(*p));         // 更安全,类型改了也不用改代码

5. 指针最容易犯的致命错误(面试 + 生产必考)

  1. 解引用空指针(Segmentation fault)
   int *p = NULL;
   *p = 10;           // 崩溃!
  1. 使用后释放(Use After Free)
   int *p = malloc(sizeof(int));
   free(p);
   *p = 20;           // 未定义行为!
  1. 重复释放(Double Free)
   free(p);
   free(p);           // 崩溃或内存损坏
  1. 野指针
   int *p;            // 未初始化
   *p = 10;           // 随机地址,极度危险
  1. 数组越界
   int arr[5];
   *(arr + 10) = 999; // 越界写,破坏内存

防御式编程黄金准则

  • 所有指针初始化为 NULL
  • free 后立刻置 NULL
  • 使用前永远判断 !NULL
  • 永远用 sizeof(*p) 而不是硬编码类型

6. 面试最常考的指针笔试题(背熟这些基本能过指针关)

  1. 指针 + 1 到底加了多少?
   int *p;     // 加 4(int 4 字节)
   char *q;    // 加 1
   double *r;  // 加 8
  1. *p++(*p)++++*pp++ 区别
  2. 写一个函数返回两个数的最大值和最小值(用指针)
  3. 实现字符串复制(不调用 strcpy)
  4. 用指针实现二维数组动态分配
  5. const 指针 vs 指针 const 的四种写法

总结:指针的本质一句话

指针就是地址的变量,通过它可以“隔空操控”内存
C 语言把内存管理权完全交给程序员,所以指针强大,但也最容易出错。
现代 C 项目中,“指针不离手,但别裸奔” —— 能用数组用数组,能用结构体用结构体,指针主要用来做参数传递、动态内存、遍历和底层操作。

想继续深入哪个指针专题?
A. 指针面试经典 20 题详解
B. const 与指针的四种组合(const int、int const 等)
C. 指针数组 vs 数组指针完整对比 + 多维数组写法
D. 动态内存分配的完整案例(链表、哈希表)
E. 野指针、悬垂指针、内存泄漏的真实案例分析

告诉我字母,我们继续深挖!

文章已创建 4138

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部