指针与基本类型:从整型到多级指针
大家好,我是你们的老朋友。今天我们来聊聊指针与基本类型的关系。说实话,指针这东西,刚学的时候觉得挺玄乎的,用久了就会发现——其实它就是地址的化身。你想想看,计算机里所有的数据都存在内存里,而内存就像一排带编号的柜子。指针,就是那个写着柜子编号的小纸条。
指向整型的指针
先来个最基础的。整型指针,说白了就是指向存放整数的那个柜子。
int a = 42;
int *p = &a; // p 里存的是 a 的地址
*p = 100; // 通过 p 修改 a 的值
我个人习惯在定义指针时,把星号紧贴着变量名写:int *p。这样读起来就是「p 是一个指针,指向 int」。当然也有人喜欢写成 int* p,语法上没问题,但容易让人误解成 int* 是一种类型。其实 C 语言里,int* p, q 这种写法会坑到你——q 只是个 int,不是指针。
int* p, q 当成两个指针用,结果调试了一下午。所以我的建议是:要么一行只定义一个变量,要么星号紧贴变量名。
指向字符型的指针
字符指针就更有意思了。它既可以指向单个字符,也可以指向字符串常量。
char ch = 'A';
char *cp = &ch;
char *str = "Hello, world!"; // 指向字符串常量
printf("%c\n", str[0]); // 输出 H
这里有个坑,我当年就踩过。字符串常量存在只读区,你试图通过 str[0] = 'h' 去修改它?程序直接崩溃。所以如果你需要修改字符串,请用字符数组:
char buf[] = "Hello";
buf[0] = 'h'; // 没问题
指向浮点型的指针
浮点指针和整型指针在用法上几乎一样,但有个细节要注意:指针的步长取决于它指向的类型。
float f = 3.14f;
float *fp = &f;
printf("%f\n", *fp); // 3.140000
// 指针加 1,地址实际增加 sizeof(float) = 4 字节
printf("%p\n", fp); // 假设是 0x1000
printf("%p\n", fp+1); // 0x1004
嗯,这里要记住:指针的加减运算,是以它指向的类型大小为单位的。不是简单的地址加 1。
void* 泛型指针
void* 是个特殊的存在。它就像一个「万能容器」,可以存放任何类型的地址。但你不能直接解引用它,因为编译器不知道它指向的是什么类型。
int a = 10;
float b = 2.5f;
void *vp;
vp = &a; // 可以
vp = &b; // 也可以
// printf("%d\n", *vp); // 错误!不能直接解引用
printf("%d\n", *(int*)vp); // 先转成 int*,再解引用
const 与指针
const 和指针的组合,是面试题里的常客,也是实际项目中容易搞混的地方。其实就两种情况:
| 写法 | 含义 | 能否修改指向 | 能否修改值 |
|---|---|---|---|
const int *p |
常量指针(指向常量的指针) | 可以 | 不可以 |
int *const p |
指针常量(指针本身是常量) | 不可以 | 可以 |
const int *const p |
两者都不可变 | 不可以 | 不可以 |
怎么记?我有个土办法:看 const 和星号的位置。const 在星号左边,修饰的是「指向的内容」;const 在星号右边,修饰的是「指针本身」。
int a = 10, b = 20;
const int *p1 = &a;
p1 = &b; // 可以
// *p1 = 30; // 不行
int *const p2 = &a;
// p2 = &b; // 不行
*p2 = 30; // 可以
多级指针(指向指针的指针)
多级指针,说白了就是「指向指针的指针」。最常见的场景是:你想在一个函数里修改传入的指针本身。
void alloc_memory(int **pp, int size) {
*pp = (int*)malloc(size * sizeof(int));
// 这里修改了 *pp,也就是调用者传入的指针变量
}
int main() {
int *p = NULL;
alloc_memory(&p, 10); // 传入指针的地址
// 现在 p 指向了一块堆内存
free(p);
return 0;
}
你看,如果只传 int *p,函数里修改 p 的值不会影响到外面的 p。但传了 int **pp,就能通过 *pp 修改外面的 p。这就是多级指针的核心用途。
再比如二维数组的动态分配:
int **matrix = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix[i] = (int*)malloc(cols * sizeof(int));
}
这里 matrix 就是一个二级指针,它指向一个指针数组,每个指针又指向一行数据。
知识体系总览
下面这张图,把本章的核心知识点串了起来。你可以把它当作一个快速索引。
好了,这一章的内容就到这里。指针这东西,光看是学不会的,一定要动手写代码。我建议你打开编辑器,把上面的例子都跑一遍,然后试着改一改,看看会发生什么。遇到段错误别慌——那是你进步最快的时候。
公众号:蓝海资料掘金营,微信deep3321