#include <stdio.h>
#include <stdlib.h>
// 定义结构体
typedef struct InnerStruct {
int data;
struct InnerStruct *next;
} InnerStruct;
typedef struct OuterStruct {
InnerStruct *listHead;
} OuterStruct;
// 创建链表函数
InnerStruct* createInnerList(int numNodes) {
InnerStruct *head = NULL;
InnerStruct *tail = NULL;
for (int i = 0; i < numNodes; i++) {
InnerStruct *newNode = (InnerStruct*)malloc(sizeof(InnerStruct));
newNode->data = i;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
}
return head;
}
// 遍历函数
void traverseList(const InnerStruct * const head) {
const InnerStruct *current = head;
while (current != NULL) {
printf("Data: %d\n", current->data);
current = current->next;
}
}
int main() {
OuterStruct outer;
outer.listHead = createInnerList(5);
const InnerStruct * const listHeadConst = outer.listHead;
traverseList(listHeadConst);
// 释放链表内存
InnerStruct *current = outer.listHead;
InnerStruct *next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
return 0;
}
指针常量在这种复杂场景下的特性
- 指针不可变:指针常量一旦初始化,其指向不能改变。在上述代码中
const InnerStruct * const head
,head
既不能指向其他 InnerStruct
节点,也不能被重新赋值。这确保了链表的遍历顺序不会被意外改变,维持了链表结构的完整性。
- 数据可访问性:虽然指针本身不可变,但如果指针指向的是可变数据类型(如
InnerStruct
中的 data
成员),只要没有将整个结构体声明为 const
,数据成员是可以被修改的。在遍历函数中,我们使用 const
修饰指针,使得链表结构不会被意外修改,但可以安全地访问节点数据。
如何确保数据结构的完整性和安全性
- 使用
const
修饰:通过 const InnerStruct * const head
这样的声明,限制了指针的可变性,防止误操作导致链表结构被破坏。例如,避免了将链表头指针错误地指向其他地方,保证链表从固定的头节点开始遍历。
- 内存管理:在创建链表时,正确分配内存,并在使用完链表后,通过遍历链表释放每一个节点的内存,避免内存泄漏。这有助于维持数据结构在整个生命周期内的完整性和安全性。