Код показывает, как вы можете генерировать произвольную последовательность чисел
с помощью 'генераторов' .
генераторы - это популярный инструмент в динамических языках, таких как python, который позволяет
итерация по произвольной длинной последовательности без выделения всей последовательности сразу.
Отслеживание происходит в строках
p->next = pow2next;
p->continue_from = 0;
Что говорит p , что он должен вызвать pow2next , чтобы получить следующий элемент в последовательности
и continue_from = 0 , чтобы указать, что где в начале последовательности.
Когда вы звоните p-> next (p) , на самом деле он просто позвонит pow2next с p как параметр.
Для первого вызова это просто вернет 1 и увеличит continue_from до 2 .
switch(p->continue_from) {
case 0:
p->continue_from = 1;
return 1;
/* ... */
При втором вызове ( continue_from = 2 ) он создаст новую map_gen работающую структуру
на свежую struct pow2s и использование функции times2 :
case 1:
p->g = map(times2,pow2()) ;
p->continue_from = 2;
return p->g->next(p->g) ;
/* ... */
Все последующие вызовы проходят через p-> g-> next (p-> g) , который использует times2 и map_gen для получения следующего
значение / создание новых map_gen структур по мере необходимости.
Отслеживание всех значений выполняется с помощью struct-member continue_from или с помощью кодов возврата.
Показывая интересный подход к генераторам в C, я должен заявить, что этот код теряет память!
Как вы можете видеть, он распределяет новые структуры, используя malloc , но никогда не free их.
Надеюсь, это объяснение не должно сбивать с толку, даже если вы только начинаете изучать C.
Если вы действительно хотите разбираться в генераторах, вам может понравиться небольшой курс Python;)
UPDATE
Как вы указали в своем комментарии ни один из генераторов никогда не возвращает значение> 2 .
Ключ к увеличивающимся числам лежит в функции map_next :
int map_next(struct mapgen *p) {
return p->f(p->g->next(p->g));
}
Вместо того, чтобы возвращать исправление, он применяет номер, к которому он применяется p-> f ()
(в нашем случае функция times2 () с результатом p-> g-> next (p-> g) .
Это рекурсивный вызов.
Он будет продолжать вызывать map_next () для каждого map_gen в списке, пока не достигнет последнего.
Этот последний элемент возвратит фиксированное значение ( 1 или 2 ).
Который затем возвращается к предыдущему вызову, который будет применяться times2 () к нему и возвращать результат вызывающему, который, в свою очередь, будет применять times2 ( ) и верните результат вызывающему объекту .... (вы поняли).
Все эти рекурсивные вызовы суммируют и формируют окончательное значение.
Если вы распечатаете результат каждого pow2next () вызова, вы получите следующее:
/* first call */
1
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
2
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
4
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
pow2next: returning 8 /* times2(4) */
8
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
pow2next: returning 8 /* times2(4) */
pow2next: returning 16 /* times2(8) */
16
/* and so on */
Вы можете ясно видеть, как результат самого верхнего вызова передается полностью до первого вызова, чтобы сформировать результат.