指针是C语言的灵魂,也是初学者的"拦路虎"。本文将通过3个最经典的应用场景,配合通俗的代码示例,带你真正理解指针的使用价值。文末还会讲解指针常见错误,帮你避开深坑!
场景一:交换两个变量的值(突破传值限制)
1.1 错误示范:传值调用
// 无法真正交换值的函数
void swap_fail(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap_fail(x, y);
printf("x=%d, y=%d", x, y); // 输出仍然是x=10,y=20
}
1.2 正确解法:指针传递
// 通过指针操作实际内存
void swap(int *a, int *b) {
int temp = *a; // 获取a地址的值
*a = *b; // 把b的值写入a地址
*b = temp; // 把临时值写入b地址
}
int main() {
int x = 10, y = 20;
swap(&x, &y); // 传入地址
printf("x=%d, y=%d", x, y); // 成功交换,输出x=20,y=10
}
原理图示:
调用前内存:
x(地址1000): 10
y(地址2000): 20
调用swap时:
a指针 → 地址1000
b指针 → 地址2000
操作后:
地址1000的值变为20
地址2000的值变为10
场景二:函数返回多个值(突破单返回值限制)
2.1 需求分析
当需要函数返回多个计算结果时,可以通过指针参数带回结果。常见场景:
-
计算商和余数
-
解析字符串得到多个数值
-
获取坐标点的x/y分量
2.2 代码示例
// 计算两个数的和与差
void calc(int a, int b, int *sum, int *diff) {
*sum = a + b; // 将结果写入sum指针指向的内存
*diff = a - b; // 将结果写入diff指针指向的内存
}
int main() {
int num1 = 30, num2 = 12;
int s, d; // 用于接收结果的变量
calc(num1, num2, &s, &d); // 传入地址
printf("和:%d\n差:%d", s, d); // 输出:和42 差18
}
场景三:分离返回状态与结果(保证错误处理)
3.1 应用场景
当函数可能执行失败时,需要:
-
返回状态码表示成功/失败
-
通过指针返回实际计算结果
典型应用:
-
文件读取(可能失败)
-
内存分配(可能返回NULL)
-
数学运算(如除以零错误)
3.2 代码示例
// 安全除法函数
int safe_divide(int a, int b, float *result) {
if (b == 0) {
return -1; // 错误状态码
}
*result = (float)a / b;
return 0; // 成功状态码
}
int main() {
float res;
int status = safe_divide(10, 4, &res);
if (status == 0) {
printf("结果:%.2f", res); // 输出2.50
} else {
printf("除数不能为0!");
}
}
优势:
-
函数返回状态码(0成功,-1失败)
-
实际计算结果通过指针安全返回
-
有效区分正常结果和错误情况
延伸:指针常见错误——野指针陷阱
错误示例
int *p; // 只声明指针,未初始化
*p = 10; // 危险!指针指向未知内存区域
printf("%d", *p); // 可能崩溃或输出乱码
正确解决方法
// 方法1:初始化时指向有效内存
int value = 0;
int *p = &value;
// 方法2:动态分配内存
int *p = malloc(sizeof(int));
*p = 10;
// ...使用后
free(p);
野指针的三种常见来源
类型 | 示例 | 解决方案 |
---|---|---|
未初始化指针 | int *p; | 定义时初始化为NULL |
已释放的指针 | free(p); 后继续使用 | 释放后立即置为NULL |
越界访问指针 | 数组访问超出范围 | 严格检查索引范围 |