二级指针到底有什么用
在C语言编程中,指针是绕不开的话题。一级指针我们用得比较多,比如指向一个整型变量、字符串或者数组。但到了二级指针,很多人就开始犯迷糊了。其实,二级指针并不是什么高深莫测的东西,它只是指向指针的指针,关键在于它能解决一些一级指针搞不定的问题。
修改指针本身的值
最典型的场景就是函数需要修改传入的指针本身。我们知道,C语言是值传递,如果在一个函数里想让外部的指针指向新的内存地址,就必须通过二级指针来实现。
#include <stdio.h>
#include <stdlib.h>
void allocate_memory(int **p, int size) {
*p = (int *)malloc(size * sizeof(int));
if (*p != NULL) {
for (int i = 0; i < size; i++) {
(*p)[i] = i * i;
}
}
}
int main() {
int *ptr = NULL;
allocate_memory(&ptr, 5);
if (ptr != NULL) {
for (int i = 0; i < 5; i++) {
printf("%d ", ptr[i]);
}
free(ptr);
}
return 0;
}
在这个例子中,allocate_memory 函数接收一个二级指针 int **p,这样它就能修改 main 函数里的 ptr 指向一块新分配的内存。如果只传一级指针,函数内部的修改对外部毫无影响。
处理指针数组
另一个常见用途是操作指针数组,比如字符串数组。假设你要写一个函数来动态创建多个字符串并返回整个数组,这时候二级指针就派上用场了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int create_strings(char ***str_array, int count) {
*str_array = (char **)malloc(count * sizeof(char *));
if (*str_array == NULL) return -1;
for (int i = 0; i < count; i++) {
int len = snprintf(NULL, 0, "String %d", i);
(*str_array)[i] = (char *)malloc((len + 1) * sizeof(char));
sprintf((*str_array)[i], "String %d", i);
}
return 0;
}
int main() {
char **strings = NULL;
create_strings(&strings, 3);
for (int i = 0; i < 3; i++) {
printf("%s\n", strings[i]);
free(strings[i]);
}
free(strings);
return 0;
}
这里 char ***str_array 是个三级指针,但核心还是靠二级指针 char ** 来管理一组字符串。你可以把它想象成“一排门牌号”,每个门牌号对应一个字符串的地址。
模拟多维动态数组
二维数组如果大小在运行时才能确定,就不能用固定维度声明。这时候可以用二级指针来动态申请。
int **create_2d_array(int rows, int cols) {
int **arr = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
arr[i] = (int *)malloc(cols * sizeof(int));
for (int j = 0; j < cols; j++) {
arr[i][j] = i * cols + j;
}
}
return arr;
}
每一行都是一个独立分配的内存块,通过二级指针统一管理。释放时也要逐行释放,避免内存泄漏。
命令行参数的体现
其实你早就见过二级指针了——main 函数的 argv 参数:char *argv[] 或等价的 char **argv。它就是一个字符串数组,每个元素指向一个命令行参数字符串。这也是二级指针在实际程序入口处的直接应用。