"指针"是C语言中非常重要的一个特性,但我在第一次学习指针时感到非常难以理解,不光概念很抽象,也不知道学习它有什么用,这篇文章我会用我的理解讲述"指针"及其主要应用。
一.指针是什么?
指针就是存储内存地址的变量。让我们用一个生动的比喻:
把计算机内存想象成一个巨大的旅馆,每个房间都有唯一的门牌号(内存地址),而指针就是记录这些门牌号的便签
c
int *p; // 指向整数的指针
char *c; // 指向字符的指针
float *f; // 指向浮点数的指针
二.两个关键运算符
1.取地址运算符&
获取变量的内存地址
2.解引用运算符*
c
int main() {
int num = 10;
int *p = # // p存储num的地址
printf("num的值: %d\n", num); // 输出: 10
printf("num的地址: %p\n", &num); // 输出地址(eg:000000000065FE44)
printf("指针p的值: %p\n", p); // 输出地址(与&num相同)
printf("通过p访问的值: %d\n", *p); // 输出: 10
return 0;
}
三.指针与数组的紧密关系
c
int arr[3] = {10, 20, 30};
注意:数组名在大多数情况下会自动转换为指向首元素的指针
c
printf("arr: %p\n", arr); // 数组首元素地址
printf("&arr[0]: %p\n", &arr[0]); // 第一个元素的地址
// 输出结果:arr和&arr[0]的值相同
但要注意它们的类型不同
- arr 的类型是 int[3] (数组类型)
- &arr[0]的类型是int*(整型指针)
指针如何访问数组元素
c
int arr[3] = {10, 20, 30};
int *p = arr; // p指向数组首元素
printf("%d\n", arr[1]); // 20
printf("%d\n", *(p+1)); // 20
printf("%d\n", p[1]); // 20
我在学习时遇到的一些困惑
1.指针存储的是整个数组 吗?
不是,int p = arr;不是把整个数组赋给p,而是把数组的首元素的地址赋给指针p(再学习数组时有讲到,但我在第一次看到这行代码的时候混淆了,所以提一下)
2.为什么p[1]能输出第二个元素?
这是由于 指针的算术运算,在指针中 p[1]等价于 *(p+1),即p[1]不是访问p指向的内容,而是访问"从p开始第1个位置"的内容
详细分解:
- p+1:指针向前移动1个int大小的距离(通常时4个字节)
- *(p+1):取那个地址的值
- 得到arr[1]的值:20
四.为什么需要指针?
1.函数参数传递 - 修改原值
在调用函数时,函数内部为形参,在函数内部的操作并不会影响实参
c
//修改分数
#include <stdio.h>
// 错误:无法修改原值
void addScore_wrong(int score) {
score += 10;
}
// 正确:使用指针修改原值
void addScore_correct(int *score) {
*score += 10;
}
int main() {
int myScore = 80;
printf("原始分数: %d\n", myScore);
addScore_wrong(myScore);
printf("错误方法后: %d (没变化!)\n", myScore);
addScore_correct(&myScore);
printf("正确方法后: %d (加了10分!)\n", myScore);
return 0;
}
//输出:
//原始分数:80
//错误方法后:80(没变化)
//正确方法后:90(加了10分)
2.返回多个值
在调用函数时,如果仅仅使用return返回值,那么只能返回一个值,但利用指针,可以返回多个值
c
//计算长方形的面积和周长
#include <stdio.h>
// 通过指针返回多个值
void calculateRectangle(int length, int width, int *area, int *perimeter) {
*area = length * width; // 面积
*perimeter = 2 * (length + width); // 周长
}
int main() {
int len = 5, wid = 3;
int area, perimeter;
calculateRectangle(len, wid, &area, &perimeter);
printf("长方形: 长=%d, 宽=%d\n", len, wid);
printf("面积: %d\n", area);
printf("周长: %d\n", perimeter);
return 0;
}
//输出
//长方形:长=5,宽=3
//面积:15
//周长:16