int main(void) { struct sequence_of_longs sequence; SEQL_initialize(&sequence); for (long i = 0L; i != 10L; i++) SEQL_add(&sequence, i); printf("The length is: %d\n", SEQL_length(&sequence)); printf("The sequence is: "); SEQL_println(&sequence); printf("The items are:"); for (int i = 0; i != SEQL_length(&sequence); i++) printf(" %ld", SEQL_item(&sequence, i)); putchar('\n'); return EXIT_SUCCESS; }
// #### Definição long recursive_fibonacci_using_ADT(int n) { assert(n >= 0); assert(n <= MAXIMUM_TERM_FITTING_A_LONG); // Em vez de se usar um _array_ de `long` como memória para os termos já // calculados da sucessão de Fibonacci, bem como um inteiro indicando a // quantidade de termos memorizados, recorremos aqui ao TAD sucessão de // `long`, representado pela estrutura `struct sequence_of_longs`. No // caso particular da sequência se Fibonacci, a utilização deste TAD não // traz grandes vantagens face à utilização de um _array_, dada a // pequena quantidade de termos da sucessão representáveis no tipo // _long_. No entanto, é um bom exercício recorrer aqui ao TAD, // exercício que nos pode ser útil noutros casos em que o // dimensionamento _a priori_ do _array_ não seja tão fácil. // // Tal como definido o TAD, o código cliente só pode trabalhar com as // sucessões através de ponteiros. Assim, precisamos de definir uma // variável local _estática_ (de modo a que o seu valor persiste entre // invocações da função `recursive_fibonacci_using_ADT`). Dadas as // restrições do C, não podemos usar o construtor `SEQL_new()` // directamente na inicialização, que tem de ser feita usando uma // _expressão constante_. Assim, optámos por inicializar o ponteiro `F` // com o valor especial `NULL`. static struct sequence_of_longs *F = NULL; // Dada a inicialização do ponteiro com `NULL`, podemos agora detectar o // seu valor inicial `NULL` para lhe atribuir o endereço de uma nova // estrutura `struct sequence_of_longs` construída de forma dinâmica // através do construtor `SEQL_new()`. Este código é executado sempre // que a função é invocada, o que é uma infelicidade, mas não há forma // de o evitar, dado que não é possível inicializar o ponteiro `F` para // a sucessão de `long` com o valor devolvido pela função `SEQL_new()`. // // Outro problema associado às limitações do C é o da libertação de // memória. O C não fornece nenhum mecanismo para executar código no // contexto das variáveis locais estáticas no final do programa de modo // a podermos «arrumar a casa», ou seja, libertar recursos que lhes // estejam associados. Neste caso os recursos são apenas duas variáveis // dinâmicas: (a) a `struct sequence_of_long` apontada por `F` e, embora // como clientes não o devêssemos precisar de o saber, (b) o _array_ // dinâmico usado internamente pelo TAD para guardar os termos. Como // toda a memória dinâmica associada ao programa em execução é libertada // durante a sua terminação, a nossa violação do princípio de que quem // reserva memória explicitamente a deve também libertar explicitamente // não é dramática. if (F == NULL) F = SEQL_new(); // Se o termo já constar na sucessão de `long` contendo os termos da // sucessão de Fibonacci já calculados, então limitamo-nos a devolvê-lo. if (n < SEQL_length(F)) return SEQL_term(F, n); // Se o termo não está ainda calculado, há que fazê-lo. Uma vez que, // depois de o calcular, teremos de o adicionar à memória e devolver, // definimos uma variável `F_n` para guardar o valor calculado. Uma vez // que o valor usado para inicializar esta variável depende do valor de // `n`, usamos o operador `?:` do C para discriminar entre as três // diferentes formas de inicialização, evitando ter de recorrer a uma // definição sem inicialização seguida de duas instruções de selecção // encadeadas: // // ```C // long F_n; // if (n == 0) // F_n = 0L; // else if (n == 1) // F_n = 1L; // else // F_n = recursive_fibonacci_using_ADT(n - 2) + // recursive_fibonacci_using_ADT(n - 1); // ``` long F_n = n == 0 ? 0L : n == 1 ? 1L : recursive_fibonacci_using_ADT(n - 2) + recursive_fibonacci_using_ADT(n - 1); // Agora que já temos o valor de `F_n` calculado, devemos guardá-lo em // memória, na nossa sucessão de `long`, de modo a não precisar de ser // calculado de novo. SEQL_add(F, F_n); // Finalmente, devolvemos o valor calculado. return F_n; }