详解C语言二级指针
众所周知,指针实际上是一个数,类比int类型,在处理指针的一些操作时我们就会遇到一些问题。比如下面这个知名的程序:
#include<stdlib.h>
#include<stdio.h>
void change(int a) { a = 2021;}
int main() {
int a = -1;
change(a);
printf("%d\n",a);
}
运行结果是-1而不是2021。原因在于函数通过传值方式进行传参时,会先在另外一个地方(空间)拷贝该值供函数使用。例如在上一个例子中,在main函数中将a传给函数change时,会重新开辟一个空间存储a的值,在函数体内直接操作的都只是一个拷贝(复印件)而不是main函数中的a(原件)。我们可以写下面这么一个简单的程序进行验证:
#include<stdlib.h>
#include<stdio.h>
void change(int a) {
printf("change函数中a的地址:%p\n",&a);
a = 2021;
}
int main() {
int a = -1;
printf("main函数中a的地址:%p\n",&a);
change(a);
printf("%d\n",a);
}
在我的PC上的运行结果如下所示:
main函数中a的地址:0x7ffee2f3d9cc
change函数中a的地址:0x7ffee2f3d9ac
-1
那么我们如何在change函数中改变main函数中a的值呢?传指针!!传值的时候我在函数里面摸不到你,但是通过传指针我可以通过指针(也就是一级指针,可以理解成只有一个*)找到其存储位置从而对其更改:
#include<stdlib.h>
#include<stdio.h>
void change(int *a) { *a = 2021;}
int main() {
int a = -1;
change(&a);
printf("%d\n",a);
}
这样子运行结果就是2021了。
到此,总结一下,原值在函数内需要借助一级指针进行更改,前面提到指针实际上就是一个数,所以我们传一级指针本身给函数我们只能修改这个指针指向的空间的值,而不能修改一级指针本身。 验证代码如下所示:
#include<stdlib.h>
#include<stdio.h>
void change(int *a, int *b)
{
a = b;
}
int main() {
int a = 1921, b = 2021;
change(&a, &b);
printf("%d\n",a);
}
运行结果是1921而不是2021。可以看到main好书中的指针a 并没有更改成指针b,原因在于传指针给函数时同样会对指针进行拷贝使用
那么如何在函数内更改一级指针呢? 答案是二级指针。
上面代码改成这样就可以了:
#include<stdlib.h>
#include<stdio.h>
void change(int **a, int **b)
{
*a = *b; //更改一级指针
}
int main() {
int a = 1921, b = 2021;
int *c = &a, *d = &b;
change(&c, &d);
printf("%d\n",*c);
}
运行结果是2021,一级指针c成功改成了指针d。这也就是二级指针的用处,举个特别实际的例子:链表,向链表末尾添加元素的代码如下所示:
#include<stdlib.h>
#include<stdio.h>
typedef struct node{
int value;
struct node *next;
}link;
void insert(link **head, int v) { //使用二级指针,为了方便修改头节点指针
if(*head == NULL) {
*head = (link *)malloc(sizeof(link));
(*head) -> value = v;
(*head) -> next = NULL;
}else{
link *cur = *head;
while(cur -> next != NULL) cur = cur -> next;
cur -> next = (link*)malloc(sizeof(link));
cur -> next -> value = v;
cur -> next -> next = NULL;
}
}
void print(link *head) { //输出链表内容
while(head != NULL) {
printf("%d ",head -> value);
head = head -> next;
}
printf("\n");
}
int main() {
link *head = NULL;
insert(&head, 1921);
insert(&head, 2021);
print(head);
}