C 语言没有内置的迭代器
最重要的一点是:C 语言本身没有像 C++ 或 Java 那样内置的、标准化的 iterator 类或概念。

C++ 的迭代器通常是一个对象,封装了指针行为,并提供 operator++, operator*, operator== 等操作,而 C 语言没有运算符重载和类,因此无法直接实现这种形式的迭代器。
C 语言的数据结构遍历(也就是迭代器的核心功能)是通过指针来完成的。 指针就是 C 语言最原始、最底层的“迭代器”。
指针作为迭代器:最基础的形式
在 C 语言中,当你遍历一个连续内存块的数据结构(如数组)时,指针就是你的迭代器。
示例:遍历数组

#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]);
// 'ptr' 就是一个迭代器
// 初始化:指向序列的第一个元素
int* ptr = arr;
// 遍历条件:检查指针是否到达了序列末尾
// 在 C 中,通常用指针是否为 NULL 来判断,但对于数组,更常用比较指针与数组末尾的地址
while (ptr < arr + n) {
// 解引用:获取当前元素 (operator*)
printf("Current element: %d\n", *ptr);
// 移动到下一个元素 (operator++)
ptr++;
}
return 0;
}
在这个例子中,指针 ptr 完美地扮演了迭代器的角色:
- 初始化:
int* ptr = arr;(迭代器begin()) - 解引用:
*ptr(迭代器operator*()) - 比较:
ptr < arr + n(迭代器operator==()或operator!=(),这里用了<因为数组地址是连续的) - 递增:
ptr++(迭代器operator++())
为自定义数据结构(如链表)创建迭代器
对于非连续内存的数据结构,比如链表,我们同样可以用指针作为迭代器,但为了让代码更清晰、更安全、更具可读性,我们可以封装指针的行为,创建一个“迭代器结构体”。
为什么需要封装?
- 可读性:
list_iterator_next(it)比it = it->next更能表达“迭代”的意图。 - 安全性: 可以在封装的函数中增加边界检查,防止访问空指针。
- 抽象性: 隐藏了数据结构的内部实现(比如链表节点是
struct node还是struct ListNode),使用者只需要关心迭代器的 API,而不需要关心底层结构。
示例:链表迭代器
#include <stdio.h>
#include <stdlib.h>
// 1. 定义链表节点
typedef struct Node {
int data;
struct Node* next;
} Node;
// 2. 定义迭代器结构体
// 它的核心就是一个指向节点的指针
typedef struct {
Node* current;
} ListIterator;
// 3. 创建迭代器(相当于 begin())
ListIterator list_iterator_begin(Node* head) {
ListIterator it = { head };
return it;
}
// 4. 检查迭代器是否有效(相当于判断是否 end())
int list_iterator_has_next(ListIterator* it) {
return it->current != NULL;
}
// 5. 获取当前元素的值(相当于 operator*)
int list_iterator_get_current(ListIterator* it) {
if (it->current) {
return it->current->data;
}
// 或者返回一个错误值/抛出错误
return -1;
}
// 6. 移动到下一个元素(相当于 operator++)
void list_iterator_next(ListIterator* it) {
if (it->current) {
it->current = it->current->next;
}
}
// 辅助函数:创建链表节点
Node* create_node(int data) {
Node* new_node = (Node*)malloc(sizeof(Node));
new_node->data = data;
new_node->next = NULL;
return new_node;
}
int main() {
// 创建一个链表: 1 -> 2 -> 3 -> NULL
Node* head = create_node(1);
head->next = create_node(2);
head->next->next = create_node(3);
// 使用迭代器遍历链表
ListIterator it = list_iterator_begin(head);
printf("Iterating through the list:\n");
while (list_iterator_has_next(&it)) {
printf("Current element: %d\n", list_iterator_get_current(&it));
list_iterator_next(&it);
}
// 释放内存 (省略)
return 0;
}
在这个链表示例中,ListIterator 结构体就是一个典型的 C 语言风格的迭代器实现,它将指针操作封装成了一组有意义的函数。
C 标准库中的迭代器思想
C 标准库虽然没有 iterator 类型,但一些函数(特别是与内存和搜索相关的)体现了迭代器的思想。
-
qsort和bsearch: 这两个函数接受一个void*指针和元素大小size_t,在回调函数中,你需要对这个指针进行算术运算来访问元素。// qsort 的比较函数 int compare(const void* a, const void* b) { // a 和 b 是 void* 指针,需要先转换 int arg1 = *(const int*)a; int arg2 = *(const int*)b; return (arg1 > arg2) - (arg1 < arg2); }这里的
a和b就像是迭代器,qsort内部在移动它们,而你的回调函数则在使用它们。 -
memchr,memcpy,memset: 这些函数接受一个void*指针(通常是内存块的起始地址),然后在其上进行操作,指针在函数内部被“迭代”以完成设置、复制或查找。
现代 C 的替代方案:基于范围的 for 循环 (C23)
即将到来的 C23 标准引入了基于范围的 for 循环,这极大地简化了遍历容器的过程,并且其底层机制与迭代器概念紧密相关。
示例:C23 的基于范围的 for 循环
#include <stdio.h>
// 假设我们有一个数组
int arr[] = {10, 20, 30, 40, 50};
int main() {
// C23 语法
printf("Iterating with C23 range-based for loop:\n");
for (int x : arr) {
printf("Element: %d\n", x);
}
// C23 也支持获取迭代器(指针)
printf("\nIterating with C23 and iterators (pointers):\n");
for (int* it = &arr[0]; it < &arr[sizeof(arr)/sizeof(arr[0])]; it++) {
printf("Element: %d\n", *it);
}
return 0;
}
编译器会自动将 for (int x : arr) 转换成类似我们手动写的指针版本,这表明,即使没有 iterator 类,C 语言也在向更方便、更安全的迭代方式演进。
| 特性 | C++ 迭代器 | C 语言迭代器 |
|---|---|---|
| 本质 | 一个对象,封装了指针和操作 | 指针本身,或封装了指针的结构体 |
| 初始化 | container.begin() |
ptr = arr 或 ListIterator it = list_iterator_begin(head) |
| 解引用 | *it 或 it->operator*() |
*ptr 或 list_iterator_get_current(&it) |
| 移动 | ++it 或 it.operator++() |
ptr++ 或 list_iterator_next(&it) |
| 比较 | it != end() |
ptr != NULL 或 ptr < end_ptr |
| 优点 | 类型安全、抽象、功能丰富(双向、随机访问) | 灵活、底层、性能高(直接操作内存) |
| 缺点 | 相对复杂,有运行时开销(虚函数表等) | 容易出错(野指针、越界),需要手动管理 |
在 C 语言中,指针就是迭代器,对于简单的数组遍历,直接使用指针就足够了,对于更复杂的自定义数据结构(如链表、树、哈希表),最佳实践是创建一个“迭代器结构体”,并将指针操作封装成一组清晰的函数(如 has_next(), get(), next()),这样既能获得迭代器的便利性和可读性,又能保持 C 语言的效率和灵活性。
