指针还没弄清楚?一篇文章搞定 “地址、指针、指针的指针、引用”,并附代码示例,建议收藏!
一个程序员对计算机底层原理的理解,决定了他职业生涯的上限。
在编程的世界里,尤其是C语言这一领域,指针无疑是最重要且最具特色的概念之一。它不仅揭示了内存操作的底层细节,还为高效编程提供了无限可能。
只有真正理解了指针,才算把握住了C语言的精髓,进而为学习高阶语言打下坚实的基础。
一、地址与指针
在 C 语言中,计算机的内存被划分为一个个存储单元,每个存储单元都有一个唯一的编号,这个编号就是内存地址。而指针则是一个变量,它存储的是内存地址。通过指针,我们可以直接访问内存中的数据,这也是 C 语言强大和灵活的一个重要原因。
只有理解了指针,才真正理解了 C 语言的精髓,才能对内存有更好的理解。因为指针允许我们直接操作内存,这使得我们可以更加高效地管理内存资源,实现各种复杂的数据结构和算法。
例如:
int num = 10;
int *ptr = #
printf("The value of num is %d\n", num);
printf("The value pointed by ptr is %d\n", *ptr);
在这个例子中,ptr是一个指向int类型的指针,它存储了变量num的地址。通过*ptr我们可以访问到num的值。
二、指针作为函数参数
指针可以作为函数的参数,实现改变参数对应的实际的值。在 C 语言中,函数的参数传递通常是值传递,即函数内部对参数的修改不会影响到函数外部的实际变量。但是,如果我们将指针作为参数传递,那么函数内部就可以通过指针间接修改外部变量的值。
例如,交换两个整数的函数:
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
printf("Before swap: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
在这个例子中,swap函数通过指针参数实现了交换两个整数的值。如果不使用指针,仅通过值传递是无法实现这个功能的。
三、指针的指针
指针的指针,即指向指针的指针,它存储的是另一个指针的地址。虽然指针的指针在一般情况用得比较少,但在某些特定场景下是必须使用的,比如在处理链表等动态数据结构时。
以下是一个使用指针的指针来处理链表的示例:
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构
struct Node {
int data;
struct Node* next;
};
// 创建新节点
struct Node* createNode(int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;
return newNode;
}
// 在链表头部插入节点
void insertAtHead(struct Node** headRef, int value) {
struct Node* newNode = createNode(value);
newNode->next = *headRef;
*headRef = newNode;
}
// 打印链表
void printList(struct Node* head) {
struct Node* current = head;
while (current!= NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// 释放链表内存
void freeList(struct Node** headRef) {
struct Node* current = *headRef;
struct Node* next;
while (current!= NULL) {
next = current->next;
free(current);
current = next;
}
*headRef = NULL;
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 3);
insertAtHead(&head, 2);
insertAtHead(&head, 1);
printList(head);
freeList(&head);
return 0;
}
在这个示例中,insertAtHead函数接受一个指针的指针struct Node** headRef作为参数。这是因为我们需要修改指向链表头部的指针,而在 C 语言中,函数参数是值传递,如果不使用指针的指针,就无法在函数内部修改外部的head指针。
通过这个示例可以看出,在处理链表这种动态数据结构时,指针的指针可以方便地修改链表的结构,实现插入、删除等操作。
四、引用
引用在 C++中被广泛使用,它是一个变量的别名。引用与指针有一些相似之处,但也有一些不同。引用在定义时必须初始化,并且一旦初始化就不能再指向其他变量。
例如:
void swapByRef(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
printf("Before swap: x = %d, y = %d\n", x, y);
swapByRef(x, y);
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
在这个例子中,swapByRef函数通过引用参数实现了交换两个整数的值,与使用指针的效果类似,但语法上更加简洁。
总之,地址、指针、指针的指针和引用是 C 语言和 C++中非常重要的概念。理解这些概念对于深入掌握这两种编程语言以及学习其他编程语言都有着至关重要的作用。