指针是 C 语言的灵魂,也是很多初学者最头疼的概念。本文将通过大量实例,带你彻底理解 C 语言指针的核心用法。
什么是指针?
简单来说,指针就是一个变量,它存储的是另一个变量的内存地址。想象一下,你家的地址就是一个”指针”,通过这个地址可以找到你家。
#include <stdio.h>
int main() {
int age = 25; // 定义一个整型变量
int *p = &age; // p 是指针,存储 age 的地址
printf("age 的值:%d\n", age);
printf("age 的地址:%p\n", &age);
printf("指针 p 的值:%p\n", p);
printf("指针 p 指向的值:%d\n", *p);
return 0;
}
输出结果:
age 的值:25
age 的地址:0x7fff5fbff6ac
指针 p 的值:0x7fff5fbff6ac
指针 p 指向的值:25
指针的核心运算符
1. 取地址运算符 &
int a = 10;
int *ptr = &a; // &a 获取变量 a 的地址
2. 解引用运算符 *
int a = 10;
int *ptr = &a;
printf("%d", *ptr); // *ptr 获取 ptr 指向的值,输出 10
指针与数组
指针和数组有着密切的关系,数组名本质上就是一个常量指针。
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr 指向数组第一个元素
// 两种访问方式等价
printf("arr[0] = %d\n", arr[0]);
printf("*ptr = %d\n", *ptr);
// 指针算术运算
for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, *(ptr + i));
}
return 0;
}
指针与函数
1. 指针作为函数参数
通过指针可以实现”传地址调用”,在函数内部修改外部变量的值。
#include <stdio.h>
// 交换两个数的值
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("x = %d, y = %d\n", x, y); // 输出:x = 20, y = 10
return 0;
}
2. 返回指针的函数
// 返回数组中最大值的指针
int* findMax(int arr[], int size) {
int *maxPtr = &arr[0];
for(int i = 1; i *maxPtr) {
maxPtr = &arr[i];
}
}
return maxPtr;
}
二级指针
指针本身也是变量,也有地址,指向指针的指针就是二级指针。
#include <stdio.h>
int main() {
int a = 100;
int *p1 = &a; // 一级指针
int **p2 = &p1; // 二级指针
printf("a = %d\n", a);
printf("*p1 = %d\n", *p1);
printf("**p2 = %d\n", **p2);
return 0;
}
动态内存分配
指针最重要的应用之一就是动态内存管理。
#include <stdio.h>
#include <stdlib.h>
int main() {
// 动态分配数组
int n = 5;
int *arr = (int*)malloc(n * sizeof(int));
// 使用动态数组
for(int i = 0; i < n; i++) {
arr[i] = (i + 1) * 10;
}
// 打印结果
for(int i = 0; i < n; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// 释放内存
free(arr);
arr = NULL; // 避免野指针
return 0;
}
常见指针错误
1. 野指针
// 错误示例
int *ptr; // 未初始化的指针
*ptr = 10; // 危险!ptr 指向未知地址
// 正确做法
int *ptr = NULL; // 初始化为 NULL
int a = 10;
ptr = &a; // 再赋值有效地址
2. 内存泄漏
// 错误示例
int *ptr = (int*)malloc(sizeof(int));
*ptr = 10;
// 忘记 free(ptr),导致内存泄漏
// 正确做法
int *ptr = (int*)malloc(sizeof(int));
*ptr = 10;
// 使用完毕后
free(ptr);
ptr = NULL;
3. 悬空指针
// 错误示例
int *getPointer() {
int local = 100;
return &local; // 错误!返回局部变量地址
}
// 正确做法
int *getPointer() {
int *ptr = (int*)malloc(sizeof(int));
*ptr = 100;
return ptr; // 返回动态分配的内存
}
实战练习
题目 1:字符串反转
#include <stdio.h>
#include <string.h>
void reverseString(char *str) {
char *start = str;
char *end = str + strlen(str) - 1;
char temp;
while(start < end) {
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
int main() {
char str[] = "Hello, World!";
printf("原字符串:%s\n", str);
reverseString(str);
printf("反转后:%s\n", str);
return 0;
}
题目 2:冒泡排序(指针实现)
#include <stdio.h>
void bubbleSort(int *arr, int n) {
for(int i = 0; i < n - 1; i++) {
for(int j = 0; j *(arr + j + 1)) {
int temp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = temp;
}
}
}
}
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
printf("排序后:");
for(int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
总结
指针是 C 语言的核心,掌握指针需要大量实践。以下是学习建议:
- 理解概念:指针就是地址,*和&是核心运算符
- 多画图:画出内存图帮助理解指针指向
- 多练习:通过实际编程加深理解
- 注意内存管理:malloc 和 free 配对使用
- 避免常见错误:野指针、内存泄漏、悬空指针
指针虽然难,但一旦掌握,你的 C 语言水平会有质的飞跃。加油!💪
下节预告:《数据结构基础:链表与指针的完美结合》
如果你觉得本文有帮助,欢迎收藏、转发,让更多人看到!
