指针与结构体的使用详解(C语言)
在C语言中,结构体(struct) 和 指针(pointer) 是两个非常重要的概念。将它们结合使用,可以实现很多复杂的数据结构,比如链表、树、图等。
一、结构体基本使用
1. 定义结构体
struct Person {
char name[50];
int age;
float height;
};
这定义了一个名为 Person
的结构体类型,包含三个成员:名字、年龄、身高。
2. 声明结构体变量
struct Person p1;
也可以用 typedef
简化:
typedef struct {
char name[50];
int age;
float height;
} Person;
Person p2; // 直接使用 Person 类型
二、指针与结构体的结合使用
1. 定义结构体指针
struct Person *ptr;
或使用 typedef
后的简写:
Person *ptr;
2. 给结构体指针分配内存
ptr = (Person*)malloc(sizeof(Person));
注意:使用完后记得释放内存:
free(ptr);
3. 访问结构体成员(两种方式)
- 点运算符(.):用于普通结构体变量
- 箭头运算符(->):用于结构体指针
Person p;
p.age = 20;
Person* ptr = &p;
ptr->age = 25; // 等价于 (*ptr).age = 25;
三、指针与结构体在链表中的典型应用
链表是最经典的结构体与指针结合使用的例子。
1. 定义链表结构体
typedef struct Node {
int data;
struct Node* next; // 指向下一个节点
} Node, *LinkList;
Node
表示链表节点;LinkList
是指向Node
的指针,常用于表示链表头指针。
2. 创建链表节点
Node* createNode(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (!newNode) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = value;
newNode->next = NULL;
return newNode;
}
3. 尾插法创建链表
LinkList createList() {
int value;
LinkList head = NULL, tail = NULL;
printf("请输入整数序列(输入9999结束):\n");
while (1) {
scanf("%d", &value);
if (value == 9999) break;
Node* newNode = createNode(value);
if (head == NULL) {
head = tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
}
return head;
}
4. 打印链表
void printList(LinkList head) {
Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
5. 主函数调用
int main() {
LinkList list = createList();
printList(list);
// 释放内存(可选)
Node* current = list;
while (current != NULL) {
Node* temp = current;
current = current->next;
free(temp);
}
return 0;
}
四、你可能遇到的问题与解答
❓1. typedef struct Node { ... } Node, *LinkList;
是什么意思?
Node
是结构体类型别名,等价于struct Node
;LinkList
是指向Node
的指针别名,等价于Node*
;- 常用于链表定义,简化写法。
✅ 示例:
LinkList head; // 等价于 Node* head;
❓2. 为什么用指针访问结构体成员要用 ->
而不是 .
?
.
用于普通结构体变量;->
是(*ptr).
的简写方式,用于结构体指针。
✅ 示例:
Node node;
node.data = 10; // 正确
Node* ptr = &node;
ptr->data = 20; // 正确
(*ptr).data = 30; // 也正确,但写法麻烦
❓3. malloc
是做什么的?为什么结构体要动态分配?
malloc
是在堆上分配内存;- 结构体变量如果在函数中定义,函数结束后就会被释放;
- 使用
malloc
可以在函数外部继续访问结构体内容。
✅ 示例:
Node* createNode(int value) {
Node* node = (Node*)malloc(sizeof(Node));
node->data = value;
node->next = NULL;
return node;
}
❓4. 为什么要用 typedef
?
- 简化结构体声明;
- 避免每次都写
struct Node
; - 提高代码可读性和可维护性。
✅ 不使用 typedef:
struct Node {
int data;
struct Node* next;
};
struct Node* head;
✅ 使用 typedef:
typedef struct Node {
int data;
struct Node* next;
} Node;
Node* head;
❓5. Node* head = NULL;
和 LinkList head = NULL;
是一样的吗?
✅ 是的,它们是等价的。
Node* head
和LinkList head
都是结构体指针;LinkList
是Node*
的别名。
五、完整示例代码
#include <stdio.h>
#include <stdlib.h>
// 定义链表结构体
typedef struct Node {
int data;
struct Node* next;
} Node, *LinkList;
// 创建节点
Node* createNode(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
return newNode;
}
// 创建链表(尾插法)
LinkList createList() {
int value;
LinkList head = NULL, tail = NULL;
printf("请输入整数序列(输入9999结束):\n");
while (1) {
scanf("%d", &value);
if (value == 9999) break;
Node* newNode = createNode(value);
if (head == NULL) {
head = tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
}
return head;
}
// 打印链表
void printList(LinkList head) {
Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// 主函数
int main() {
LinkList list = createList();
printList(list);
// 释放内存
Node* current = list;
while (current != NULL) {
Node* temp = current;
current = current->next;
free(temp);
}
return 0;
}
六、总结
概念 | 说明 |
---|---|
struct |
定义结构体类型,封装多个不同类型的变量 |
typedef |
给结构体类型取别名,简化代码 |
-> |
用指针访问结构体成员时使用 |
malloc |
动态分配内存,用于创建结构体节点 |
Node* / LinkList |
都是结构体指针,用于链表操作 |
✅ 你可能需要练习的场景
- 创建双向链表(含
prev
和next
指针) - 使用结构体模拟学生管理系统
- 用结构体和指针实现栈、队列