Instituto Superior de Engenharia de Lisboa LEETC - Programação Imperativa em C e C++ Semestre letivo 2013/14-2 Teste de 1.ª data Nota importante: Valoriza-se a escrita de código que inclua comentários esclarecedores da implementação seguida e que contenha indentação legível. 1. [3 valores] Considere a macro M: #define M(varname, index) ( ( (unsigned char*) & varname )[index] ) a) [1] Descreva os resultados apresentados em standard output, na execução do troço de programa seguinte, tendo em conta as características da plataforma IA-32. Justifique. int a = 0x12345678; printf( "%x %x\n", M(a,0), M(a,3) ); b) [1] Suponha a existência de uma variável com o nome b, cujo tipo pode ser básico ou struct. Escreva um troço de programa que utilize a macro M para apresentar, em standard output, o conteúdo da memória ocupada pela variável b. c) [1] Admitindo que pretende escrever programas com portabilidade para plataformas little-endian (armazena o byte de menor peso no endereço mais baixo) ou big-endian (ordem inversa), escreva a macro SET_IF_LITTLE_ENDIAN(res) que recebe no parâmetro res o nome de uma variável com tipo inteiro, afetando-a com 1, se a plataforma de execução for little-endian, ou 0, se for big-endian. 2. [12 valores] Interprete o excerto de programa seguinte, destinado a gerir vetores genéricos. Cada vetor é formado por um descritor e um array para os dados, ambos alojados dinamicamente. O array tem crescimento automático, pela colocação de dados. typedef struct vector { int buffer_size; /* espaço alojado, em número de elementos */ int data_size; /* número de elementos de dados armazenados */ int el_size; /* dimensão do elemento em bytes */ int (*compare)( void * elem1, void * elem2 ); /* função de comparação, retorna: <0, elem1 < elem2; 0, elem1 == elem2; >0, elem1 > elem2. */ char * buffer; /* ponteiro para o alojamento do array */ } Vector; Vector * vector_create( int buffer_size, int el_size, int (*compare)( void * elem1, void * elem2 ) ){ Vector init = { buffer_size, 0, el_size, compare, malloc( buffer_size* el_size ) }; Vector * vec = malloc( sizeof *vec ); *vec = init; return vec; } void vector_put( Vector * vec, void * elem ){ if( vec->data_size == vec->buffer_size ) vec->buffer = realloc( vec->buffer, ++vec->buffer_size * vec->el_size ); memcpy( vec->buffer + vec->el_size * vec->data_size++, elem, vec->el_size ); } void * vector_search( Vector * vec, void * key ){ int i; char * p; for( i = vec->data_size, p = vec->buffer ; i != 0 ; --i, p += vec->el_size ) if( vec->compare( p, key ) == 0 ) return p; return NULL; } PICC, 2013/14-2 Teste, 1.ª data Por exemplo, o troço de programa seguinte cria um vetor de elementos do tipo int e coloca os valores 10, 30 e 20. int x = 10, y = 30, z = 20, k1 = 30, k2 = 40, *p1, *p2; Vector * v = vector_create( 1, sizeof(int), compare_int ); vector_put( v, &x ); vector_put( v, &y ); vector_put( v, &z ); p1 = vector_search( v, &k1 ); p2 = vector_search( v, &k2 ); A pesquisa do valor 30 obtém um ponteiro válido e a pesquisa do valor 40 obtém um ponteiro com o valor NULL. a) [1] Escreva a função compare_int, para associar ao vetor do exemplo anterior, passando no parâmetro compare da função vector_create. A função compare_int recebe o endereço de dois elementos do tipo int e devolve um valor negativo, zero ou superior a zero se, respetivamente, o primeiro elemento for inferior, igual ou superior ao segundo. b) [4] Escreva uma versão em assembly IA-32 da função vector_search. c) [1] Modifique a função vector_put de modo a deixar os dados ordenados crescentemente, após cada colocação. Propõe-se que use a função qsort, da biblioteca normalizada, que realiza a ordenação genérica de arrays, recebendo o endereço base do array, o número de elementos, a dimensão do elemento e o endereço de uma função de comparação para determinar a ordem relativa dos elementos. void qsort( void* base, size_t num, size_t size, int (*cmp_func)( const void*, const void* ) ); d) [1] Indique, justificando, se é possível melhorar a eficiência da função de pesquisa vector_search, tendo em conta o armazenamento ordenado resultante da modificação especificada na alínea c). e) [2,5] Admitindo que se pretende organizar o código para gestão de vetores genéricos num módulo de programa, descreva resumidamente o que se deve colocar no ficheiro de programa, vector.c, e escreva completamente o ficheiro de inclusão, vector.h. f) [1] Supondo que escreveu o programa de aplicação na função main de um módulo com o nome demo.c, escreva o makefile para gerar o executável demo usando a organização especificada na alínea e). g) [1,5] Considere que o programa demo.c da alínea f) contém o exemplo de aplicação apresentado, mas falta criar a função compare_int. Qual é a fase que falha no processo de produção do executável (compilação, de que módulo, ou ligação)? Qual é o comando, do makefile anterior, que falha? Usando a ferramenta nm, em que ficheiro encontraria a referência ao símbolo compare_int e como seria classificado? 3. [2 valores] Considere uma árvore binária de pesquisa, cujos nós foram definidos com o tipo Tnode. typedef struct tnode{ struct tnode * left; struct tnode * right; void * data; } Tnode; Escreva a função Tinvert_order que inverte o critério de ordenação usado na árvore (crescente para decrescente ou vice-versa). No estado inicial a árvore já está ordenada por um critério; deve realizar apenas a troca de ligações necessária para invertê-lo. Não se pretende modificar o estado de balanceamento. 4. [3 valores] Considere uma lista simplesmente ligada, cujos nós foram definidos com o tipo Lnode. typedef struct lnode{ struct lnode * next; int data; } Lnode; Pretende-se criar uma lista ordenada crescente com os valores lidos de um ficheiro de texto, “dados.txt”. O ficheiro contém uma sequência de valores numéricos inteiros, expressos em ASCII com notação decimal, com ordenação predominantemente crescente – a maioria dos valores estão por ordem, mas alguns poderão não estar. A criação da lista com esta especificação é feita pela função Lnode * Lcreate_from_file( FILE * f ); que retorna o endereço do primeiro elemento da lista construída. a) [0,5] Escreva um troço de programa que abra o ficheiro e invoque a função Lcreate_from_file. b) [2,5] Escreva a função Lcreate_from_file, assegurando a reordenação dos elementos fora de ordem. Valoriza-se a eficiência, tirando partido da ordem predominante dos dados no ficheiro. Note que se percorrer a lista na totalidade, ou quase, por cada elemento a inserir, a eficiência é relativamente baixa. ISEL, 2014.07.07