Menu
Coddy logo textTech

Паттерн Iterator

Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 56 из 61.

Паттерн Iterator предоставляет способ последовательно получать элементы из collection, не раскрывая её внутреннюю структуру. Вместо того чтобы предоставлять пользователям direct доступ к array, вы даёте им объект, который умеет проходить по data, получая по одному element за раз.

Итератору обычно нужны две части информации: ссылка на collection и текущая position. В C мы создаём структуру для хранения этого состояния:

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

Итератор предоставляет две ключевые functions. has_next() проверяет, есть ли ещё more elements для чтения, а next() возвращает current element и advances position:

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

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

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

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

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

challenge icon

Задание

Легко

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

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

  • iterator.h: Define структуру IntIterator, которая хранит указатель на array целых чисел, общий размер collection и текущую position. Declare три functions: create_iterator (принимает указатель на array и размер, возвращает initialized iterator), has_next (проверяет, остались ли ещё elements) и next (возвращает current element и advances position). Не забудьте include guards!
  • iterator.c: Implement ваши functions итератора. Function create_iterator должна возвращать IntIterator по значению с current position, установленной в 0. Function has_next возвращает 1, если осталось больше elements для чтения, и 0 otherwise. Function next возвращает element в current position, а затем increments position.
  • main.c: Прочитайте number elements, затем прочитайте each integer value в array. Create iterator для этого array, затем используйте цикл while с has_next и next, чтобы перебрать и вывести each element в отдельной строке.

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

  1. Количество elements в array
  2. Каждое integer value в отдельной строке

Используйте паттерн iterator, чтобы вывести все elements: никакого direct indexing array в вашем цикле обхода!

Пример output, когда inputs — это 4, затем 10, 20, 30, 40:

10
20
30
40

Пример output, когда inputs — это 3, затем -5, 0, 100:

-5
0
100

Пример output, когда inputs — это 1, затем 42:

42

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

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

#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Проверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C