C语言中的结构体、指针与基础数据结构详解
结构体与指针的基本用法
在C语言中,结构体(struct)允许我们将多个不同类型的数据组合成一个自定义类型。这类似于高级语言中的对象概念,但更加轻量和底层。例如,要表示一名学生的信息,我们可以将姓名、年龄和成绩封装在一个结构体中。
#include <stdio.h>
// 定义学生信息结构体
struct Student {
char name[64];
int age;
double score;
};
int main() {
// 声明并初始化结构体变量
struct Student s1 = {"张三", 20, 88.5};
// 直接访问成员
printf("姓名: %s, 年龄: %d, 成绩: %.1f\n", s1.name, s1.age, s1.score);
return 0;
}
当处理大型结构体或需要在函数间共享数据时,直接传递整个结构体会消耗较多内存和时间。此时使用指针更为高效。指针存储的是变量的内存地址,通过它可以间接访问和修改目标数据。
#include <stdio.h>
struct Student {
char name[64];
int age;
double score;
};
int main() {
struct Student s1 = {"李四", 21, 92.0};
struct Student *ptr = &s1; // 指针指向s1
// 使用 -> 操作符访问成员
printf("姓名: %s, 年龄: %d, 成绩: %.1f\n", ptr->name, ptr->age, ptr->score);
return 0;
}
链表:动态数据组织方式
链表是一种由节点串联而成的线性结构,每个节点包含数据域和指向下一个节点的指针域。相比数组,链表无需连续内存空间,插入和删除操作更灵活。
#include <stdio.h>
#include <stdlib.h>
// 链表节点定义
struct ListNode {
int value;
struct ListNode *next;
};
// 打印链表所有元素
void display(struct ListNode *head) {
while (head != NULL) {
printf("%d ", head->value);
head = head->next;
}
printf("\n");
}
int main() {
// 创建三个节点
struct ListNode *first = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode *second = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode *third = (struct ListNode*)malloc(sizeof(struct ListNode));
first->value = 10;
first->next = second;
second->value = 20;
second->next = third;
third->value = 30;
third->next = NULL;
display(first); // 输出: 10 20 30
// 释放内存
free(first);
free(second);
free(third);
return 0;
}
栈:后进先出的操作模型
栈遵循"后进先出"原则,常用于递归调用、表达式求值等场景。其核心操作是入栈(push)和出栈(pop),通常用数组模拟实现。
#include <stdio.h>
#define STACK_SIZE 100
int stack[STACK_SIZE];
int topIndex = -1; // 栈顶位置标记
void push(int item) {
if (topIndex >= STACK_SIZE - 1) {
printf("栈溢出!\n");
return;
}
stack[++topIndex] = item;
}
int pop() {
if (topIndex < 0) {
printf("栈为空!\n");
return -1;
}
return stack[topIndex--];
}
int main() {
push(100);
push(200);
printf("弹出: %d\n", pop()); // 输出 200
printf("弹出: %d\n", pop()); // 输出 100
return 0;
}
队列:先进先出的数据流管理
队列采用"先进先出"机制,适用于任务调度、广度优先搜索等应用。它维护两个指针:front 表示队首,rear 表示队尾。
#include <stdio.h>
#define QUEUE_CAPACITY 100
int queue[QUEUE_CAPACITY];
int frontPos = -1, rearPos = -1;
void enqueue(int val) {
if (rearPos == QUEUE_CAPACITY - 1) {
printf("队列已满!\n");
return;
}
if (frontPos == -1) frontPos = 0;
queue[++rearPos] = val;
}
int dequeue() {
if (frontPos == -1 || frontPos > rearPos) {
printf("队列为空!\n");
return -1;
}
return queue[frontPos++];
}
int main() {
enqueue(5);
enqueue(15);
printf("取出: %d\n", dequeue()); // 输出 5
printf("取出: %d\n", dequeue()); // 输出 15
return 0;
}
二叉树:分层结构的典型代表
二叉树是一种非线性结构,每个节点最多有两个子节点:左子树和右子树。它广泛应用于查找算法、堆排序等领域。
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int key;
struct TreeNode *leftChild;
struct TreeNode *rightChild;
};
// 创建新节点
struct TreeNode* createNode(int value) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->key = value;
node->leftChild = NULL;
node->rightChild = NULL;
return node;
}
// 前序遍历:根 → 左 → 右
void preorderTraversal(struct TreeNode* root) {
if (root != NULL) {
printf("%d ", root->key);
preorderTraversal(root->leftChild);
preorderTraversal(root->rightChild);
}
}
int main() {
struct TreeNode* root = createNode(1);
root->leftChild = createNode(2);
root->rightChild = createNode(3);
root->leftChild->leftChild = createNode(4);
root->leftChild->rightChild = createNode(5);
printf("前序遍历结果: ");
preorderTraversal(root); // 输出: 1 2 4 5 3
printf("\n");
return 0;
}