黑马程序员---C语言存储期的简单比较

本文详细对比了C语言中静态存储区与动态存储区的特性,包括生命周期、存储位置、初始值以及作用范围等关键区别。同时,介绍了register和extern在变量管理中的应用,旨在为读者提供全面的C语言存储期理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-----------android培训java培训、java学习型技术博客、期待与您交流!------------       

  C语言存储期的简单比较

一.对于statis 与 auto 的区别?

1.在内存中的存储区域不一样,(静态存储区与动态存储区)

2.Statis生命周期不一样,整个运行过程期间不释放Auto 什么时候调用什么时候分配,调用结束释放

3.如果不赋予初值的话:statis默认初值0和\0,auto不确定

4.statis每次函数调用时不再重新赋初值,保留上次函数调用结束的值。Auto每次调用执行一次原有的赋值语句

5.statis局部变量,虽然存在于整个程序运行期间,但是由于局部限制,只能被本函数使用,不能被其他函数调用。

二.Registerde 的概述

对于使用频繁地变量,计算机会自动识别,并存放在内存中,因而对人为声明的必要性不大

三.Extern 的概述

1.可以在一个文件内扩展外部变量的作用域,

2.可以将外部变量的作用域扩展到其他文件

<think>我们正在讨论C语言链表实现与操作。根据提供的引用,我们可以总结链表的基本概念和结构。 引用[1]和[2]介绍了链表的基本结构:链表由节点组成,每个节点包含数据域和指针域(指向下一个节点)。引用[1]中展示了一个有序链表的结构,包含头指针、尾指针和链表大小。引用[3]给出了一个学生管理系统中链表节点的结构体定义。 引用[4]则展示了一个链表应用的例子(约瑟夫环问题)。 用户问题:想学习C语言中链表的实现和操作。 因此,我们将按照以下步骤讲解: 1. 链表的基本概念 2. 链表节点的定义 3. 链表的初始化(以引用[1]中的有序链表为例) 4. 链表的基本操作(创建、插入、删除、遍历等) 5. 一个简单的链表应用示例 注意:引用中提供的代码片段可能存在错误或不完整,我们将修正并完善。 步骤1:链表的基本概念 链表是一种动态数据结构,通过指针将一系列节点连接起来。每个节点包含两部分:数据域(存储数据)和指针域(存储下一个节点的地址)。 步骤2:链表节点的定义 通常,我们使用结构体来定义链表节点,如引用[3]所示: ```c struct Node { int data; // 数据域,这里以int为例,可以是任意类型 struct Node *next; // 指针域,指向下一个节点 }; ``` 步骤3:链表的初始化 我们可以创建一个链表,并初始化头节点(有时也称为哨兵节点)。引用[1]中展示了一个有序链表的初始化函数,我们稍作调整: ```c #include <stdio.h> #include <stdlib.h> #define LEN sizeof(struct Node) // 定义节点长度 struct Node { int data; struct Node *next; }; // 定义链表结构(类似引用[1]中的OrderedList) struct LinkedList { struct Node *head; // 头指针 struct Node *tail; // 尾指针(在单链表中,尾指针可以方便尾部插入) int size; // 链表长度 }; // 初始化链表 int InitList(struct LinkedList *list) { // 创建头节点(哨兵节点) list->head = (struct Node*)malloc(LEN); if (list->head == NULL) { return 0; // 内存分配失败 } // 初始时,链表为空,头节点的next指向NULL list->head->next = NULL; list->tail = list->head; // 尾指针指向头节点 list->size = 0; return 1; } ``` 步骤4:链表的基本操作 4.1 插入节点(尾部插入) 在链表尾部插入新节点,并更新尾指针。 ```c // 尾部插入新节点 void Append(struct LinkedList *list, int data) { // 创建新节点 struct Node *newNode = (struct Node*)malloc(LEN); newNode->data = data; newNode->next = NULL; // 将新节点连接到尾节点后面 list->tail->next = newNode; list->tail = newNode; // 更新尾指针 list->size++; } ``` 4.2 遍历链表 从头节点后的第一个节点开始,依次访问每个节点。 ```c void Traverse(struct LinkedList *list) { struct Node *p = list->head->next; // 跳过头节点(哨兵节点) while (p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); } ``` 4.3 在指定位置插入节点(例如在第pos个位置插入) 注意:pos从1开始,表示插入后成为第pos个节点(不包括头节点) ```c // 在位置pos插入节点(pos从1开始) int Insert(struct LinkedList *list, int pos, int data) { if (pos < 1 || pos > list->size + 1) { return 0; // 位置不合法 } // 找到插入位置的前一个节点 struct Node *p = list->head; for (int i = 1; i < pos; i++) { // 移动pos-1次 p = p->next; } // 创建新节点 struct Node *newNode = (struct Node*)malloc(LEN); newNode->data = data; newNode->next = p->next; p->next = newNode; // 如果插入在尾部,更新尾指针 if (p == list->tail) { list->tail = newNode; } list->size++; return 1; } ``` 4.4 删除指定位置的节点 ```c // 删除位置pos的节点 int Delete(struct LinkedList *list, int pos) { if (pos < 1 || pos > list->size) { return 0; // 位置不合法 } // 找到要删除节点的前一个节点 struct Node *p = list->head; for (int i = 1; i < pos; i++) { p = p->next; } struct Node *temp = p->next; // 要删除的节点 p->next = temp->next; // 如果删除的是尾节点,更新尾指针 if (temp == list->tail) { list->tail = p; } free(temp); list->size--; return 1; } ``` 步骤5:释放链表 使用完毕后,释放所有节点(包括头节点)。 ```c void DestroyList(struct LinkedList *list) { struct Node *p = list->head; while (p != NULL) { struct Node *temp = p; p = p->next; free(temp); } list->head = NULL; list->tail = NULL; list->size = 0; } ``` 步骤6:一个简单的应用示例 我们可以创建一个链表,插入一些数据,然后遍历和删除。 ```c int main() { struct LinkedList list; if (!InitList(&list)) { printf("初始化链表失败\n"); return 1; } // 尾部插入三个节点 Append(&list, 1); Append(&list, 2); Append(&list, 3); Traverse(&list); // 输出:1 2 3 // 在位置2插入4 Insert(&list, 2, 4); Traverse(&list); // 输出:1 4 2 3 // 删除位置3的节点 Delete(&list, 3); Traverse(&list); // 输出:1 4 3 DestroyList(&list); // 释放链表 return 0; } ``` 以上是一个简单的链表实现和操作教程。注意,这里我们使用了带头节点的链表(哨兵节点),这样可以在处理插入和删除时避免对头指针的特殊处理。 根据引用[4],链表还可以用于解决约瑟夫环问题(类似于引用[4]中的徒弟退局问题)。由于篇幅限制,这里不再展开,但读者可以尝试用上述链表实现约瑟夫环问题。 §§相关问题§§ 1. 如何用链表实现约瑟夫环问题? 2. 链表和数组在性能上有哪些区别? 3. 如何实现链表的反转? 4. 链表中的头节点(哨兵节点)有什么作用?</think>### C语言链表实现与操作教程 链表是一种动态数据结构,通过指针将零散的内存块串联起来。以下是基于黑马程序员教程的链表实现详解: #### 一、链表基本结构 ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 struct Node { int data; // 数据域 struct Node *next; // 指针域(指向下一个节点) }; ``` - **数据域**:存储实际数据(如`int`、`char`或自定义结构体) - **指针域**:存储下一个节点的内存地址 - **头指针**:指向链表第一个节点(关键标识)[^2] #### 二、核心操作实现 1. **创建节点** ```c struct Node* createNode(int data) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); if (newNode == NULL) { printf("内存分配失败!"); exit(1); } newNode->data = data; newNode->next = NULL; return newNode; } ``` 2. **头部插入** ```c void insertAtHead(struct Node** head, int data) { struct Node* newNode = createNode(data); newNode->next = *head; *head = newNode; // 更新头指针 } ``` 3. **尾部插入** ```c void insertAtTail(struct Node** head, int data) { struct Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; return; } struct Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } ``` 4. **删除节点** ```c void deleteNode(struct Node** head, int key) { struct Node *temp = *head, *prev = NULL; // 删除头节点 if (temp != NULL && temp->data == key) { *head = temp->next; free(temp); return; } // 查找待删除节点 while (temp != NULL && temp->data != key) { prev = temp; temp = temp->next; } if (temp == NULL) return; // 未找到 prev->next = temp->next; // 跳过被删节点 free(temp); // 释放内存 } ``` 5. **遍历链表** ```c void printList(struct Node* node) { while (node != NULL) { printf("%d -> ", node->data); node = node->next; } printf("NULL\n"); } ``` #### 三、完整示例(学生管理系统节点) ```c // 学生结构体(引用[3]扩展) struct Student { char name[50]; int age; long studentID; float gpa; struct Student* next; // 链表指针 }; // 初始化链表(引用[1]优化) void initStudentList(struct Student** head) { *head = NULL; // 初始化为空链表 } // 添加学生记录 void addStudent(struct Student** head, const char* name, int age, long id, float gpa) { struct Student* newStudent = (struct Student*)malloc(sizeof(struct Student)); strcpy(newStudent->name, name); newStudent->age = age; newStudent->studentID = id; newStudent->gpa = gpa; newStudent->next = *head; *head = newStudent; } ``` #### 四、链表特性分析 1. **动态内存**:运行时分配内存,避免静态数组的大小限制 2. **高效插入/删除**:时间复杂度$O(1)$(头部操作)或$O(n)$(随机位置) 3. **内存开销**:每个节点需额外存储指针(通常4/8字节) 4. **应用场景**: - 动态数据集合(如学生管理系统[^3]) - 需要频繁插入/删除的场景 - 实现队列、栈等高级数据结构 - 约瑟夫环问题等算法(引用[4]) #### 五、调试技巧 ```c // 检查内存泄漏(开发阶段必备) void freeList(struct Node** head) { struct Node* current = *head; struct Node* next; while (current != NULL) { next = current->next; free(current); current = next; } *head = NULL; // 防止野指针 } ``` > **关键提示**:链表操作后务必更新头指针;每次`malloc`必须对应`free`防止内存泄漏[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值