C 指针
🔍 C 语言学习:指针(Pointer)
🎯 学习目标
- 理解指针的基本概念与作用,掌握其在内存访问中的核心地位。
- 掌握指针的定义、赋值、取地址和间接访问操作符
*的使用。 - 能够使用指针完成数组遍历、函数参数传递、动态内存管理等常见任务。
🔑 核心重点
- 指针是变量的地址,通过指针可以访问或修改变量的值。
- 指针类型决定了访问的数据大小和解释方式,如
int*指向的是一个int类型数据。 - 指针运算要符合类型对齐规则,不能随意对空指针或无效地址进行操作。
📚 详细讲解

一、什么是指针?
指针是一种特殊的变量,它存储的是另一个变量的内存地址。你可以通过这个地址来访问或修改那个变量的内容。
✅ 基本语法:
数据类型 *指针变量名;
示例:基本指针操作
#include <stdio.h>
int main() {
int a = 42;
int *p = &a; // p 是指向整数 a 的指针
printf("a 的值:%d\n", a); // 输出:42
printf("a 的地址:%p\n", &a); // 输出类似:0x7ffee...
printf("p 的值(a 的地址):%p\n", p); // 同上
printf("*p 的值(a 的内容):%d\n", *p); // 输出:42
return 0;
}
📌 解释:
&:取地址运算符*:间接访问运算符(也叫“解引用”)
⚠️ 注意事项:
- 使用未初始化的指针会导致未定义行为(Undefined Behavior)。
- 不要对
NULL或非法地址进行解引用操作。
二、指针与数组的关系
在 C 语言中,数组名本质上是一个常量指针,指向数组第一个元素的地址。
示例:用指针遍历数组
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *p = arr; // 等价于 &arr[0]
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, *(p + i)); // 通过指针访问数组元素
}
return 0;
}
📌 小技巧:
arr[i] == *(arr + i)- 指针比数组下标更快(因为不需要计算偏移)
三、指针与函数参数传递
C 语言中函数参数默认是值传递,使用指针可以实现模拟引用传递,让函数修改外部变量。
示例:交换两个整数
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Before: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("After: x = %d, y = %d\n", x, y);
return 0;
}
📌 输出:
Before: x = 10, y = 20
After: x = 20, y = 10
⚠️ 注意事项:
- 函数内部不要返回局部变量的地址(栈空间已释放)。
- 多级指针可用于传递二维数组或修改指针本身。
四、指针与字符串
字符串本质是一个字符数组,可以用字符指针指向字符串字面量。
示例:使用字符指针处理字符串
#include <stdio.h>
int main() {
char *str = "Hello, World!"; // str 指向字符串常量
while (*str != '\0') {
putchar(*str++);
}
putchar('\n');
return 0;
}
📌 注意:
- 字符串常量不能被修改(尝试写入会崩溃),如:
str[0] = 'h'❌ - 如果需要修改字符串,应使用字符数组:
char str[] = "Hello";
五、指针与动态内存分配(C23 支持良好)
使用 malloc / calloc / realloc 和 free 可以在堆上动态申请内存,并通过指针访问。
示例:动态创建一个整型数组
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 5;
int *arr = malloc(n * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
free(arr); // 释放内存
return 0;
}
📌 输出:
0 10 20 30 40
⚠️ 注意事项:
- 动态内存必须手动释放(否则造成内存泄漏)
- 分配失败时一定要检查是否为
NULL
六、多级指针(pointer to pointer)
多级指针用于指向另一个指针,常见于函数中需要修改指针本身的场景。
示例:二级指针修改一级指针指向
#include <stdio.h>
void change_ptr(int **p) {
static int value = 99;
*p = &value;
}
int main() {
int a = 10;
int *ptr = &a;
printf("Before: %d\n", *ptr);
change_ptr(&ptr);
printf("After: %d\n", *ptr);
return 0;
}
📌 输出:
Before: 10
After: 99
📌 应用场景:
- 修改指针本身(例如动态分配内存后传回)
- 二维数组传参
- 字符串数组(如命令行参数
char *argv[])
🧩 拓展练习(动手实践题)
-
练习一:指针交换
- 编写函数
swap_float(float *a, float *b),交换两个浮点数的值。
- 编写函数
-
练习二:字符串反转
- 使用指针编写函数
reverse_string(char *str),将输入字符串原地反转。
- 使用指针编写函数
-
练习三:查找最大值
- 给定一个整型数组,使用指针找出其中的最大值及其索引。
-
挑战练习:动态二维数组
- 使用
malloc创建一个 M x N 的二维数组,并用指针访问每个元素。
- 使用
-
项目实战:简易链表
- 定义结构体节点
struct Node { int data; struct Node *next; }; - 使用指针实现链表的插入与打印功能。
- 定义结构体节点
📝 小结
| 特点 | 说明 |
|---|---|
| 指针是 C 语言的灵魂 | 直接操作内存,提高效率与灵活性 |
| 指针可指向任何变量、数组、函数、结构体 | 实现复杂数据结构的关键 |
| 指针支持动态内存管理 | 配合 malloc/free 实现灵活内存控制 |
| 指针操作需谨慎 | 避免野指针、空指针、越界访问等问题 |
📚 推荐阅读 & 工具建议
- 《C Primer Plus》第6版
- 《C和指针》Pointers on C
- CLion 2025.1.1 中启用 C23 支持的方法
- MinGW-w64 编译器配置指南(支持
-std=c23) - GDB 调试指针与内存的实用命令
- Visual Assist 插件(适用于 VS)增强指针补全提示
如果你希望我为你提供:
- 指针使用陷阱与避坑指南 PDF
- 更多实战项目(如内存池、链表、树结构、文件读写等)
- 指针 vs 数组、const 指针、函数指针详解
- 指针命名规范与代码风格建议
- 视频教学资源推荐(中文讲解)
欢迎随时告诉我 😊
二级标题:NULL 指针详解
在 C 语言中,NULL 是一个非常重要的概念,它表示一个“空指针”或“无效地址”。虽然 NULL 看起来只是一个简单的宏定义,但它在程序的安全性、健壮性和可读性方面起着关键作用。
什么是 NULL?
在标准头文件(如 <stdio.h> 或 <stddef.h>)中,NULL 通常被定义为:
#define NULL ((void *)0)
或者简化为:
#define NULL 0
也就是说,NULL 实际上是一个值为 0 的指针常量。它用来表示某个指针变量当前没有指向任何有效的内存地址。
为什么使用 NULL?
-
初始化指针变量
在声明指针时,如果没有立即赋值,建议将其初始化为NULL,避免成为“野指针”。int *p = NULL; -
判断指针是否有效
使用前通过判断指针是否为NULL,可以防止对无效地址进行解引用,从而避免段错误。if (p != NULL) { printf("%d\n", *p); } -
作为函数返回值
常用于表示函数执行失败或无结果。例如动态内存分配失败时,malloc返回NULL。int *arr = malloc(100 * sizeof(int)); if (arr == NULL) { printf("内存分配失败!\n"); return -1; } -
作为链表、树等结构的终止标志
在数据结构中,NULL常用来表示链表尾部、树的叶子节点等。struct Node { int data; struct Node *next; }; // 遍历链表 struct Node *current = head; while (current != NULL) { printf("%d ", current->data); current = current->next; }
NULL 指针与野指针的区别
| 类型 | 含义 | 是否安全 |
|---|---|---|
NULL 指针 |
明确不指向任何地址 | ✅ 安全(可判断) |
| 野指针 | 未初始化,内容随机(可能指向非法地址) | ❌ 不安全(不可控) |
⚠️ 对野指针进行解引用会导致未定义行为;而
NULL指针可以通过判断避免访问。
注意事项
-
不要对
NULL指针解引用
会引发段错误(Segmentation Fault)或崩溃。int *p = NULL; printf("%d\n", *p); // ❌ 错误!不能解引用 NULL 指针 -
释放后的指针应置为 NULL
防止“悬挂指针”问题(即指针仍保留旧地址,但内存已被释放)。int *p = malloc(sizeof(int)); free(p); p = NULL; // 避免后续误用 -
不要混淆
NULL和'\0'
NULL是指针常量,表示无效地址;\0是字符串结束符,表示字符数组的结尾。 -
不要直接使用
0替代NULL
虽然它们本质上是等价的,但使用NULL更具语义清晰性,提升代码可读性。
总结
NULL 是 C 语言中非常基础但也非常关键的概念。它不仅帮助我们写出更安全、更可靠的代码,还能提高程序的可维护性。掌握 NULL 的使用方式和背后的原理,是每个 C 语言开发者必须具备的基本功之一。

浙公网安备 33010602011771号