首页 5G技术

C 语言数据结构基石:指针、结构体与链表深度解析

分类:5G技术
字数: (7619)
阅读: (2069)
内容摘要:C 语言数据结构基石:指针、结构体与链表深度解析,

C 语言之所以强大,指针是其核心特性之一。理解指针对于掌握 C 语言,进而学习更高级的数据结构至关重要。很多初学者在学习数据结构时,往往会被指针搞得晕头转向。今天我们就来彻底搞懂 C 语言中的指针,为后续学习链表打下坚实的基础。

什么是指针?

简单来说,指针就是一个存储内存地址的变量。这个内存地址指向另一个变量,我们可以通过指针来访问和修改该变量的值。

int num = 10; // 定义一个整型变量 num,赋值为 10
int *ptr = # // 定义一个整型指针 ptr,指向 num 的地址

printf("num 的值:%d\n", num); // 输出 num 的值:10
printf("num 的地址:%p\n", &num); // 输出 num 的地址,例如:0x7ffee1a23b68
printf("ptr 的值:%p\n", ptr); // 输出 ptr 的值,即 num 的地址:0x7ffee1a23b68
printf("ptr 指向的值:%d\n", *ptr); // 输出 ptr 指向的值,即 num 的值:10

& 符号用于获取变量的地址,* 符号用于解引用指针,即访问指针指向的变量的值。理解这两个符号的含义是理解指针的关键。

C 语言数据结构基石:指针、结构体与链表深度解析

指针的用途

指针主要用于以下几个方面:

  • 动态内存分配: 使用 malloccalloc 等函数动态分配内存,返回的是指向分配内存的指针。
  • 函数参数传递: 通过指针可以在函数内部修改函数外部的变量的值。
  • 数据结构: 在链表、树等数据结构中,指针用于连接各个节点。

指针易错点

  • 空指针: 未初始化的指针或者指向 NULL 的指针。访问空指针会导致程序崩溃。
  • 野指针: 指向已经被释放的内存的指针。访问野指针的结果是未定义的,可能导致程序崩溃或者数据错误。
  • 内存泄漏: 动态分配的内存没有及时释放,导致内存占用越来越大。尤其是在长时间运行的程序中,内存泄漏会导致系统资源耗尽。

结构体:自定义数据类型

结构体允许我们将多个不同类型的数据组合成一个整体,从而方便我们表示复杂的数据结构。类似于 Java 中的 Class,但是功能相对弱一些,没有继承、多态等特性。

C 语言数据结构基石:指针、结构体与链表深度解析

定义结构体

struct Student {
 char name[20]; // 姓名
 int age; // 年龄
 float score; // 分数
};

// 使用 typedef 简化结构体的使用
typedef struct Student Student;

int main() {
 Student stu1 = {"张三", 18, 90.5};
 Student stu2 = {"李四", 19, 85.0};

 printf("姓名:%s, 年龄:%d, 分数:%.2f\n", stu1.name, stu1.age, stu1.score);
 printf("姓名:%s, 年龄:%d, 分数:%.2f\n", stu2.name, stu2.age, stu2.score);

 return 0;
}

结构体指针

结构体指针是指向结构体变量的指针。通过结构体指针可以方便地访问和修改结构体成员。

Student *pstu = &stu1; // 定义一个结构体指针 pstu,指向 stu1

printf("姓名:%s, 年龄:%d, 分数:%.2f\n", pstu->name, pstu->age, pstu->score); // 使用 -> 访问结构体成员

使用 -> 运算符可以通过结构体指针访问结构体成员。

C 语言数据结构基石:指针、结构体与链表深度解析

链表:动态数据结构

链表是一种动态数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表可以动态地添加和删除节点,因此非常灵活。

单链表

单链表的每个节点只有一个指向下一个节点的指针。

C 语言数据结构基石:指针、结构体与链表深度解析
// 定义链表节点结构体
typedef struct Node {
 int data; // 数据
 struct Node *next; // 指向下一个节点的指针
} Node;

// 创建链表
Node* createList() {
 Node *head = NULL; // 初始化头指针为空
 Node *tail = NULL; // 初始化尾指针为空
 int data;
 printf("请输入链表数据(输入-1结束):\n");
 while (scanf("%d", &data) == 1 && data != -1) {
 Node *newNode = (Node*)malloc(sizeof(Node)); // 创建新节点
 if (newNode == NULL) {
 printf("内存分配失败!\n");
 exit(1);
 }
 newNode->data = data; // 设置节点数据
 newNode->next = NULL; // 初始化 next 指针为空
 if (head == NULL) {
 head = newNode; // 如果链表为空,则新节点为头节点
 tail = newNode; // 同时也是尾节点
 } else {
 tail->next = newNode; // 将新节点添加到链表尾部
 tail = newNode; // 更新尾节点
 }
 }
 return head; // 返回头指针
}

// 打印链表
void printList(Node *head) {
 Node *current = head; // 从头节点开始遍历
 printf("链表数据:\n");
 while (current != NULL) {
 printf("%d ", current->data); // 打印节点数据
 current = current->next; // 移动到下一个节点
 }
 printf("\n");
}

// 释放链表内存
void freeList(Node *head) {
 Node *current = head;
 while (current != NULL) {
 Node *temp = current; // 临时保存当前节点
 current = current->next; // 移动到下一个节点
 free(temp); // 释放当前节点
 }
}

int main() {
 Node *head = createList(); // 创建链表
 printList(head); // 打印链表
 freeList(head); // 释放链表内存
 return 0;
}

链表的操作

常见的链表操作包括:

  • 插入节点: 在链表的头部、尾部或者中间插入新节点。
  • 删除节点: 删除链表中的指定节点。
  • 查找节点: 查找链表中是否存在指定值的节点。
  • 反转链表: 将链表中的节点顺序颠倒。

链表的应用

链表广泛应用于各种场景,例如:

  • 动态数组: 链表可以实现动态数组,可以根据需要动态地添加和删除元素。
  • 队列和栈: 链表可以实现队列和栈等数据结构。
  • 哈希表: 链表可以解决哈希冲突。

掌握链表对于理解和实现更复杂的数据结构,例如树和图,至关重要。在实际项目中,我们常常需要使用链表来解决各种问题。例如在 Nginx 的 upstream 模块中,就使用了链表来管理 upstream server 的配置信息,需要考虑反向代理、负载均衡、并发连接数等问题。使用宝塔面板可以方便地管理 Nginx 的配置,但深入理解 Nginx 的底层原理,才能更好地优化性能。

C 语言数据结构基石:指针、结构体与链表深度解析

转载请注明出处: CoderPunk

本文的链接地址: http://m.acea3.store/blog/415783.SHTML

本文最后 发布于2026-04-07 22:45:21,已经过了19天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 土豆泥选手 4 天前
    链表那部分的代码很实用,可以直接拿来用。不过,感觉可以再补充一些关于双向链表和循环链表的内容,就更完美了。
  • 向日葵的微笑 4 天前
    链表那部分的代码很实用,可以直接拿来用。不过,感觉可以再补充一些关于双向链表和循环链表的内容,就更完美了。
  • 秋名山车神 5 天前
    这篇文章写得真不错,指针部分讲得很透彻,解决了我的一个大疑惑!之前一直对结构体指针的用法不太明白,这下彻底搞懂了。