Menu
Coddy logo textTech

Паттерн Iterator

Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 56 из 61.

Паттерн Итератор предоставляет способ последовательного доступа к элементам коллекции без раскрытия её внутренней структуры. Вместо того чтобы предоставлять пользователям прямой доступ к массиву, вы даете им объект, который умеет перебирать данные по одному элементу за раз.

Итератору обычно требуются две части информации: ссылка на коллекцию и текущая позиция. В языке C мы создаем структуру (struct) для хранения этого состояния:

typedef struct {
    int* data;      // указатель на массив
    int size;       // общее количество элементов
    int current;    // текущая позиция
} IntIterator;

Итератор предоставляет две ключевые функции. has_next() проверяет, есть ли еще элементы для чтения, а next() возвращает текущий элемент и перемещает позицию вперед:

int has_next(IntIterator* it) {
    return it->current < it->size;
}

int next(IntIterator* it) {
    return it->data[it->current++];
}

Использование итератора выглядит лаконично и скрывает детали массива:

IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
    printf("%d\n", next(&it));
}

Вызывающей стороне никогда не нужно знать, что numbers является массивом или как работает индексация. Эта абстракция позволяет легко изменить базовую структуру данных позже — например, с массива на связный список — без изменения кода, который использует итератор.

challenge icon

Задание

Легко

Давайте создадим итератор NumberList — чистую абстракцию, которая позволяет обходить коллекцию целых чисел, не раскрывая структуру базового массива.

Вы организуете свой код в трех файлах:

  • iterator.h: Определите структуру IntIterator, которая содержит указатель на массив целых чисел, общий размер коллекции и текущую позицию. Объявите три функции: create_iterator (принимает указатель на массив и размер, возвращает инициализированный итератор), has_next (проверяет, остались ли еще элементы) и next (возвращает текущий элемент и продвигает позицию вперед). Не забудьте про include guards!
  • iterator.c: Реализуйте функции итератора. Функция create_iterator должна возвращать IntIterator по значению с текущей позицией, установленной в 0. Функция has_next возвращает 1, если есть еще элементы для чтения, и 0 в противном случае. Функция next возвращает элемент в текущей позиции, а затем увеличивает позицию.
  • main.c: Считайте количество элементов, затем считайте каждое целое число в массив. Создайте итератор для этого массива, затем используйте цикл while с функциями has_next и next, чтобы обойти и вывести каждый элемент на новой строке.

Ваша программа получит:

  1. Количество элементов в массиве
  2. Каждое целое число на отдельной строке

Используйте паттерн «Итератор» для вывода всех элементов — никакого прямого индексирования массива в цикле обхода!

Пример вывода, когда входные данные 4, затем 10, 20, 30, 40:

10
20
30
40

Пример вывода, когда входные данные 3, затем -5, 0, 100:

-5
0
100

Пример вывода, когда входные данные 1, затем 42:

42

Итератор скрывает то, как хранятся данные — ваш основной цикл просто спрашивает «есть ли еще?» и «дай мне следующий», ничего не зная об индексах массива или расположении в памяти.

Шпаргалка

Паттерн Итератор предоставляет способ последовательного доступа к элементам коллекции, не раскрывая её внутреннюю структуру.

Структура итератора хранит ссылку на коллекцию, размер и текущую позицию:

typedef struct {
    int* data;      // указатель на массив
    int size;       // общее количество элементов
    int current;    // текущая позиция
} IntIterator;

Итератор предоставляет две ключевые функции:

int has_next(IntIterator* it) {
    return it->current < it->size;
}

int next(IntIterator* it) {
    return it->data[it->current++];
}

Использование итератора скрывает детали реализации массива:

IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
    printf("%d\n", next(&it));
}

Эта абстракция позволяет изменять базовую структуру данных без модификации клиентского кода.

Попробуйте сами

#include <stdio.h>
#include "iterator.h"

int main() {
    int n;
    scanf("%d", &n);
    
    int arr[n];
    
    // TODO: Считайте n целых чисел в массив
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }
    
    // TODO: Создайте итератор для массива
    
    // TODO: Используйте цикл while с has_next и next для обхода
    // и выведите каждый элемент на отдельной строке
    // НЕ используйте прямую индексацию массива в цикле обхода!
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming