PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008

Documentos relacionados
PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008

PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008

PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008

PROGRAMAÇÃO DE MICROPROCESSADORES 2009 / 2010

Sumário. Ficheiros. Ficheiros

Programação. MEAer e LEE. Manipulação de ficheiros de texto. Bertinho Andrade da Costa. Instituto Superior Técnico. 2010/2011 1º Semestre

Linguagem C Ficheiros Compilação Separada

PROGRAMAÇÃO DE MICROPROCESSADORES 2011 / 2012

PROGRAMAÇÃO DE MICROPROCESSADORES 2009 / 2010

1/24 FICHEIROS DE TEXTO

13 a Aula - Instruções Condicionais. Ciclos. Pré-processador. Variáveis de ambiente. Mestrado em Engenharia Física Tecnológica

ALGORITMOS AULA 01. Baseado nas aulas do Prof. Jorgiano Vidal

A linguagem C (visão histórica)

Programação. Folha Prática 10. Lab. 10. Departamento de Informática Universidade da Beira Interior Portugal. Copyright 2010 All rights reserved.

UNIVERSIDADE LUSÓFONA DE HUMANIDADES E TECNOLOGIAS 2º Semestre 2013/2014

INSTITUTO FEDERAL DE! EDUCAÇÃO, CIÊNCIA E TECNOLOGIA RIO GRANDE DO NORTE

FUNÇÕES EM C Material adaptado da profa Silvana Maria Affonso de Lara

Algoritmos e Programação

Instituto Superior Técnico Introdução aos Algoritmos e Estruturas de Dados

Básico: estrutura de programa, sintaxe Interface com linha de comando

Computação 2. Aula 8. Profª. Fabiany Arquivos

Conhecendo a Linguagem de Programação C

Linguagem C Introdução. Contexto Histórico Principais diferenças do Java Funções em C Compilar programas em C no Linux

Exame de Programação Estruturada (A)

PROGRAMAÇÃO E ALGORITMOS (LEII) Universidade da Beira Interior, Departamento de Informática Hugo Pedro Proença, 2016/2017

Linguagem C. André Tavares da Silva.

Programação de Computadores II

PROGRAMAÇÃO DE MICROPROCESSADORES 2009 / 2010

Programação. MEAer e LEE. Bertinho Andrade da Costa. Instituto Superior Técnico. Argumentos da linha de comando Funções recursivas

Introdução à Programação Aula 16. Prof. Max Santana Rolemberg Farias Colegiado de Engenharia de Computação

Fundamentos de Programação

CAP. IX - MANIPULAÇÃO DE ARQUIVOS Generalidades sobre Arquivos. 9.2 Abertura e Fechamento de Arquivos. Operações com arquivos:

Departamento de Engenharia Informática. Sistemas Operativos 1. Utilitário Make

Curso de C. Introdução by Arnaldo V. Moura e Daniel F. Ferber 3/10/ :43 AM

TAD: Tipo Abstrato de Dados (parte 2)

Linguagens de programação. Introdução ao C (continuação)

Fundamentos de Programação 1

Gilberto A. S. Segundo. 24 de agosto de 2011

Ponteiros e Tabelas. K&R: Capítulo 5

3. Linguagem de Programação C

MESMO QUE ESTAS VARIÁVEIS TENHAM NOME IDÊNTICOS

1º Exame 14 de Junho de Duração: 2h30 (+15 min) Número: Nome: Notas

Módulo 7 Cadeias de Caracteres

UNIVERSIDADE DA BEIRA INTERIOR

Argumentos da linha de comando Exemplos Recursividade de funções Exemplos

Controlo de Execução. K&R: Capitulo 3

Programação de Computadores I Introdução ao C PROFESSORA CINTIA CAETANO

ADTs (Abstract Data Types): Motivação

Instituto Superior Técnico Algoritmos e Estruturas de Dados

Funções em C. Lucas Ferrari de Oliveira Professor Adjunto. Linguagem de Programação Estruturada I. Universidade Federal do Paraná

TAD: Tipo Abstrato de Dados (parte 2)

Programação 1. Atribuição, operadores aritméticos, entrada de dados. Técnico em Eletrônica Semestre 5 02

LINGUAGEM C: FUNÇÕES FUNÇÃO 08/01/2018. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

TE091 Programação Orientada a Objetos Engenharia Elétrica

Anhanguera Educacional S.A. Centro Universitário Ibero-Americano

Manipulação de Arquivos Exercício/Exemplo:

Linguagens de Programação I

EXERCÍCIO DE SONDAGEM TURMA 02 SEMESTRE DATA: 01/11/2016. Matrícula Nome Nota

Introdução à Programação em C

Sumário. Introdução à Ciência da Computação. Ponteiros em C. Introdução. Definição. Por quê ponteiros são importantes?

Arrays, Criação de Funções, Estruturas e Manipulação de Arquivos.

Linguagem C: Introdução

Computadores Digitais 2. Prof. Rodrigo de Souza Couto

Programação em C. Variáveis e Expressões. Universidade Federal do Rio Grande do Norte Departamento de Engenharia de Computação e Automação

PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008

Métodos Computacionais. Tipos Estruturados

Linguagem C. IF61A/IF71A - Computação 1 Prof. Leonelo Almeida. Universidade Tecnológica Federal do Paraná

Listas Lineares. Livro Projeto de Algoritmos Nívio Ziviani Capítulo 3 Seção 3.1

Programação de Computadores II. Cap. 7 Cadeias de Caracteres

Introdução à Programação

Conceitos básicos. Computação eletrônica: Gurvan Huiban

UNIVERSIDADE DA BEIRA INTERIOR

SSC INTRODUÇÃO À COMPUTAÇÃO PARA ENGENHARIA AMBIENTAL REGISTROS E ARQUIVOS. Profa. Dra. Milena Guessi Margarido

Tratamento de Caracteres

Programação 2017/2018 2º Semestre

Programação de Computadores II Aula 03. Linguagem C I

#include <stdio.h> Void main() { printf( Cheguei!\n"); } INTRODUÇÃO A LINGUAGEM C

LINGUAGEM C: FUNÇÕES FUNÇÃO 04/07/2017. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

Linguagem C Controle do Fluxo de Execução. Lógica de Programação

Algoritmos II prof. Daniel Oliveira

LINGUAGEM C: ARQUIVOS

Computação e Programação (2007/2008-1º Semestre)

Estruturas da linguagem C. 1. Identificadores, tipos primitivos, variáveis e constantes, operadores e expressões.

Introdução a Programação. Arquivos

ESCOLA SUPERIOR DE TECNOLOGIA DE TOMAR DEPARTAMENTO DE ENGENHARIA INFORMÁTICA 2002/ Valores

Indexação e Busca. O objetivo deste trabalho é projetar e implementar um sistema de programas para indexação e busca em arquivos de texto.

Algoritmos e Programação. Linguagem C Procedimentos e. Eliane Pozzebon

Programação de Computadores II. Cap. 7 Cadeias de Caracteres 1/2

Programação I Funções. Prof. Carlos Alberto

Programação Básica. Estrutura de um algoritmo

UNIVERSIDADE LUSÓFONA DE HUMANIDADES E TECNOLOGIAS 2º Semestre 2013/2014

Working 03 : Conceitos Básicos I

Leitura Segura de Strings

Curso de C. Declaração de Variáveis 18/3/ :48 1

1 Exercícios com ponteiros

Conceitos Básicos de C

prim = A ; prim = &A[0];

Ponteiros & tabelas (cont.) K&R: Capítulo 5

Disciplina de Algoritmos e Programação

Conceitos básicos de programação

Transcrição:

Departamento de Engenharia Electrotécnica PROGRAMAÇÃO DE MICROPROCESSADORES 2007 / 2008 Mestrado Integrado em Engenharia Electrotécnica e Computadores 1º ano 1º semestre Estruturação de código e outros aspectos avançados http://tele1.dee.fct.unl.pt Luis Bernardo Paulo Pinto

1 Introdução Este trabalho aborda um conjunto de aspectos focados nos capítulos 10, 11, 13 e 14 do livro Linguagem C de Luís Damas, recomendado para a disciplina de Programação de Microprocessadores. O programa vai refazer o trabalho da última aula, utilizando arrays de estruturas, tipo enumerados, e divisão do código por vários ficheiros. Esta aula visa consolidar estas matérias através de um conjunto de exercícios, mas principalmente por exemplificar o modo como se constrói um programa que usa vários ficheiros. Durante a aula vai ser desenvolvida uma aplicação em várias fases que mantém os dados dos alunos num array, e que permite exportar esses dados ou importar esses dados de um ficheiro binário. Neste trabalho introduz-se o conceito de modularidade. São fornecidos quatro ficheiros: aluno.c, aluno.h, lista_alunos.c, e Makefile. Pretendese que o aluno complete o código no ficheiro lista_alunos.c, utilizando os tipos de dados e as funções que os manipulam, através dos protótipos definidos em aluno.h. 2 Os ficheiros aluno.h e aluno.c Neste trabalho vai-se usar uma abordagem diferente da usada nos três trabalhos anteriores. Em vez de se começar a programar a partir da função main, vai-se iniciar a programação pelo desenvolvimento de um tipo de dados para guardar os dados dos alunos, e depois, por programar um conjunto de funções para realizar as várias operações sobre este tipo de dados. Desta forma, vai programar-se um ficheiro aluno.h com as definições de tipos e com o protótipo das funções desenvolvidas, e um ficheiro aluno.c com o código dessas funções. Constrói-se assim um conjunto de funções e dados que tratam os alunos. Para desenvolver a aplicação na função main apenas é usado o conteúdo do ficheiro aluno.h. Podem declarar-se variáveis dos tipos lá definidos e invocar as funções cujos protótipos estão lá definidos. O conteúdo do ficheiro aluno.c apenas vai ser necessário quando se quiser montar o executável final, juntando as várias funções do programa. Repare que é isso o que acontece quando se usa a biblioteca <stdio.h>: invoca-se a função scanf sem saber como é executada. Quando os programas começam a ter uma dimensão grande, este expediente de partir o problema é muito útil. Os dois ficheiros, aluno.h e aluno.c, são fornecidos completos com o enunciado. Este trabalho vai voltar a realizar uma lista de alunos, como no trabalho anterior, com o mesmo formato de dados e de ficheiros binários. A diferença é que agora os dados dos alunos vão ser guardados todos em memória. As operações suportadas são idênticas às do trabalho anterior, excepto as operações de leitura e escrita para um ficheiro. As operações de manipulação da lista de alunos são executadas na memória do computador, e só são passadas para o ficheiro quando o utilizador usa a opção correspondente. Desta forma, o programa é mais rápido a realizar as operações. 2.1 ESTRUTURAS DE DADOS Como se disse anteriormente, os dados dos alunos são guardados na mesma estrutura que no trabalho anterior. No entanto, há algumas diferenças na forma como se declaram os tipos auxiliares. Repare que o tipo bool é agora declarado como um tipo 2

enumerado com dois valores possíveis (FALSE e TRUE), que também define os valores para cada constante. Neste trabalho também vai usar-se a estrutura struct Aluno para guardar os dados de cada aluno, e para ler e escrever no ficheiro. Mas graças a um typedef o tipo Aluno é definido como sendo igual ao tipo struct Aluno. Desta forma, deixa de ser necessário colocar o struct nas variáveis que guardam dados de alunos. typedef enum { FALSE= 0, TRUE= 1 bool; #define MAX_STUDENTNAME_LENGTH 160 struct Aluno { char nome[max_studentname_length]; int numero; int turno; ; typedef struct Aluno Aluno; 2.2 FUNÇÕES PARA MANIPULAR DADOS DO TIPO ALUNO Nesta secção são apresentados os protótipos das funções desenvolvidas para aceder a variáveis do tipo Aluno. Juntamente com o enunciado é fornecido o ficheiro aluno.c com o código das funções. As funções não são descritas aqui porque: 1) Não é necessário para realizar o exercício, pois basta saber como se chamam as funções e o que fazem; 2) A maior parte do código já foi utilizada no trabalho anterior. A função inicia_dados_aluno permite iniciar o conteúdo de uma variável do tipo Aluno apontada por aluno_ptr com o campo nome vazio (todos os caracteres com o valor \0 ), e os campos numero e turno com o valor 0 (zero). void inicia_dados_aluno(aluno *aluno_ptr); A função aluno_esta_definido verifica se o comprimento do nome da variável apontada por aluno_ptr é maior que zero. Retorna TRUE se é maior que zero, ou FALSE em caso contrário. bool aluno_esta_definido(aluno *aluno_ptr); A função string_dados_aluno retorna uma string com os dados internos da variável apontada por aluno_ptr. Neste caso é mostrado um detalhe na realização da função no ficheiro aluno.c para destacar a utilização da variável static buffer. As variáveis normais de uma função desaparecem quando termina a função. Neste caso a palavra-chave static faz com que a variável buffer seja criada no início do programa, mantendo-se activa e sempre com o mesmo valor entre invocações da função string_dados_aluno. /* No ficheiro aluno.h */ char *string_dados_aluno(aluno *aluno_ptr); /* No ficheiro aluno.c */ char *string_dados_aluno(aluno *aluno_ptr){ static char buffer[max_studentname_length+21]; As funções ler_nome e ler_numero são idênticas às funções com o mesmo nome usadas no trabalho anterior, e permitem respectivamente ler uma string com um 3

tamanho máximo max_len, ou um número para a variável apontada por number_ptr. Em ambos os casos retorna TRUE em caso de sucesso, ou FALSE se falhou a leitura. bool ler_nome(char *string, int max_len); bool ler_numero(int *number_ptr); A função ler_dados_aluno lê a partir do teclado os dados de um aluno para uma variável apontada por aluno_ptr. Retorna TRUE caso consiga ler os dados com sucesso, ou FALSE caso contrário. bool ler_dados_aluno(aluno *aluno_ptr); A função read_file_dados_aluno é usada para ler os dados de um aluno para a variável apontada por aluno_ptr a partir do ficheiro binário apontado por fp. A função write_file_dados_aluno é usada para escrever os dados do aluno apontada por aluno_ptr para o ficheiro binário apontado por fp. Em ambos os casos, as funções retornam TRUE em caso de sucesso, ou FALSE se falhou a operação. bool read_file_dados_aluno(file *fp, Aluno *aluno_ptr); bool write_file_dados_aluno(file *fp, Aluno *aluno_ptr); A função copia_dados_aluno copia todos os campos da variável apontada por de_ptr para a variável para_ptr. void copia_dados_aluno(aluno *para_ptr, Aluno *de_ptr); Um dos problemas que pode ocorrer quando se separa o código por vários ficheiros é a possibilidade de ter erros por o ficheiro aluno.h ser incluído mais de uma vez. Isto pode acontecer em programas muito grandes que incluem ficheiros que por sua vez incluem outros ficheiros, e pode-se chegar a uma situação onde o controlo que quem inclui quem é difícil de fazer e o mesmo ficheiro é incluído mais do que uma vez. As linhas assinaladas abaixo são usadas para evitar este problema. Tem um comportamento parecido como um IF para a parte do compilador que faz o processamento dos #define. As instruções entre o #ifndef e o #endif só são executadas se o símbolo (neste caso, _ALUNO_H_) não estiver definido (#ifndef == Se não está definido). Neste caso, a primeira instrução é definir o símbolo para nunca mais (noutros ficheiros) a parte restante do código ser executada. A parte restante é incluir os ficheiros. Assim, eles nunca serão incluídos mais de que uma vez. Já agora, e para situações mais profissionais, dentro deste IF até se pode colocar código normal de C que só é compilado se o símbolo estiver definido. Assim, um programa pode ter uma parte de código que pode ser compilada ou não. #ifndef _ALUNO_H_ #define _ALUNO_H_ // definições #endif 3 O ficheiro lista_alunos.c O ficheiro lista_alunos.c contém a parte do trabalho relacionada com o menu e com as várias funcionalidades disponíveis a partir do menu. Pretende-se ter as opções representadas na figura seguinte. No resto deste enunciado vão ser definidas as funções 4

que realizam estas operações e o menu principal. O trabalho dos alunos é simplesmente completar uma delas e fazer o menu principal. 0: Sair 1: Ler alunos de ficheiro 2: Acrescentar aluno 3: Apagar aluno 4: Listar alunos 5: Listar alunos por turno 6: Salvar alunos para ficheiro A leitura dos dados de alunos de um ficheiro é executada pela função ler_alunos_ficheiro, Vai poder ser chamada com o nome de um ficheiro, ou sem nome, pretendendo-se, nesse caso, que a função peça o nome ao utilizador. A função recebe como parâmetros: dados, um array de dados do tipo Aluno; n_alunos, um apontador para um inteiro com o número de alunos preenchidos no array; e nome, o nome do ficheiro ou o valor da constante NULL se o nome não estiver definido. A função modifica o array e o número de elementos, não deixando preencher mais do que MAX_N_ALUNOS elementos. Repare que para obter o endereço do aluno na posição *n_alunos (próxima posição livre) do array tanto que pode usar &dados[*n_alunos] como (dados+*n_aluno) optou-se pela primeira forma para aumentar a legibilidade do código. São usadas as funções ler_nome e read_file_dados_aluno definidas em aluno.h., cujo código está em aluno.c. /* Realiza a opção 1: Ler alunos de ficheiro */ void ler_alunos_ficheiro(char *nome, Aluno dados[], int *n_alunos) { char buffer[max_name_size]; // Para guardar o nome do ficheiro FILE *fp; if (nome == NULL) { // Se não se introduziu o nome do ficheiro printf("introduza o nome do ficheiro a ler: "); if (!ler_nome(buffer, MAX_NAME_SIZE)) // Falhou leitura do nome nome= buffer; // fp= fopen(nome, "rb"); if (fp == NULL) { perror("erro a abrir ficheiro: "); /* da stdlib.h */ while (!feof(fp)) { // Enquanto não chega o fim do ficheiro if ((*n_alunos >= MAX_N_ALUNOS)!read_file_dados_aluno(fp, &dados[*n_alunos])) break; ++(*n_alunos); // incrementa contador de alunos no array fclose(fp); Como os dados são guardados em memória, é simples acrescentar um novo aluno basta preencher a primeira posição livre do array e incrementar o contador. A função adicionar_aluno recebe e modifica o array dados e o apontador para a variável inteira n_alunos, com o número de elementos do array. Usa a função ler_dados_aluno para ler os dados do utilizador, não incrementando o número de elementos se a leitura falhar. 5

/* Realiza a opção 2: Acrescentar aluno */ void adicionar_aluno(aluno dados[], int *n_alunos) { if (*n_alunos < MAX_N_ALUNOS) { // Se há espaço no array e if (ler_dados_aluno(&dados[*n_alunos])) // leu sem erros ++(*n_alunos); // incrementa número de alunos A operação de apagar um elemento ao array de dados é um pouco mais complicada. No array dados é necessário garantir que os *n_alunos primeiros elementos do array têm dados válidos. A opção usada foi de substituir o aluno removido pelo actual último aluno da lista, caso não se esteja a apagar o último elemento. Note-se que o array não está ordenado e portanto não há problemas em modificar a ordem. Podia-se também copiar todos os elementos restantes do array uma posição para baixo. Assim, depois de pedir o número de aluno a apagar, a função apagar_aluno procura o índice do aluno a apagar. Caso o número exista no array, copia o último elemento para essa posição, limpa a última posição e decrementa a variável com o número de elementos do array. /* Realiza a opção 3: Apagar aluno */ void apagar_aluno(aluno dados[], int *n_alunos) { int i, numero; if (*n_alunos <= 0) // Não há alunos para apagar printf("qual é o número do aluno a apagar? "); if (!ler_numero(&numero)) // Não foi introduzido número for (i= 0; i<*n_alunos; i++) if (dados[i].numero == numero) break; if (i == *n_alunos) // Não encontrou número // Apaga aluno na posição i (*n_alunos)--; // Decrementa um elemento ao array if (i!= *n_alunos) // Se não é o último elemento do array // copia último elemento do array para posição a apagar copia_dados_aluno(&dados[i], &dados[*n_alunos]); // Limpa dados do anterior último elemento do array inicia_dados_aluno(&dados[*n_alunos]); A função listar_alunos foi aproveitada para fazer a listagem de todos os alunos e dos alunos por turno dependendo de um parâmetro de entrada. No caso de se querer listar apenas um turno, é perguntado ao utilizador o número do turno. Os dados são escritos a partir de uma string que é construída pela função string_dados_aluno. typedef enum { LISTAR_TODOS, LISTAR_POR_TURNO tipo_listar; /* Realiza as opções 4: Listar alunos (se tipo == LISTAR_TODOS); 5: Listar alunos por turno (se tipo == LISTAR_POR_TURNO) */ void listar_alunos(tipo_listar tipo, Aluno dados[], int *n_alunos) { int i, cnt=0, turno= 0; if (tipo == LISTAR_POR_TURNO) { 6

printf("qual é o turno a listar? "); if (!ler_numero( &turno)) // Não foi introduzido número for (i= 0; i<*n_alunos; i++) { if (aluno_esta_definido(&dados[i]) && ((tipo == LISTAR_TODOS) (dados[i].turno == turno))) { printf("%s\n", string_dados_aluno(&dados[i])); /* EXERCÍCIO 1: MODIFICAR O CÓDIGO PARA esperar por ENTER do utilizador para continuar em cada MAX_LINES linhas, interrompendo se o utilizador introduzir 'q' */ printf("falta PROGRAMA ESPERA POR UM ENTER DO UTILIZADOR EM CADA %d LINHAS\n", MAX_LINES); A função salvar_alunos_ficheiro guarda o array dos alunos num ficheiro em modo binário. Repare que no caso de falhar uma escrita o ficheiro é apagado. /* Realiza a opção 6: Salvar alunos para ficheiro */ void salvar_alunos_ficheiro(aluno dados[], int *n_alunos) { char nome[max_name_size]; FILE *fp; int i; printf("introduza o nome do ficheiro a escrever: "); if (!ler_nome(nome, MAX_NAME_SIZE)) // Falhou leitura do nome fp= fopen(nome, "wb"); if (fp == NULL) { perror("erro a abrir ficheiro: "); for (i= 0; i<*n_alunos; i++) if (aluno_esta_definido(&dados[i])) if (!write_file_dados_aluno(fp, &dados[i])) { // Falhou escrita - aborta operação fclose(fp); remove(nome); // Apaga ficheiro fclose(fp); Finalmente vai-se desenvolver a função main (que deveria ser a primeira tarefa). Tal como no trabalho anterior, neste trabalho a função main está estruturada como um menu, que apresenta a lista de opções e em seguida corre uma função associada à opção escolhida. Neste caso, o parâmetro na linha de comando é opcional. Pode chamar-se a aplicação com um parâmetro (por exemplo./alunos dados.dat ), ou sem parâmetros (./alunos). No primeiro caso, o conteúdo do ficheiro é carregado para a memória. No segundo caso o processo de leitura do ficheiro é executado numa das opções. Depois, o programa deve ficar no menu principal até que o utilizador introduza a opção 0 Sair. Pretende-se que os alunos programem as tarefas do menu principal. 7

#include <stdio.h> #include "aluno.h" // Carrega as definições do ficheiro aluno.h #define MAX_NAME_SIZE 180 // Tamanho máximo de nome de ficheiro #define MAX_N_ALUNOS 400 // Dimensão do array onde se guardam // os dados dos alunos #define MAX_LINES 20 // Número máximo de linhas que pode // escrita sem esperar por um ENTER main(int argc, char *argv[]) { Aluno dados[max_n_alunos]; // Dados dos alunos int n_alunos= 0; // Contador de elementos usados no array // define a primeira posição livre do array int i; /* Inicia todas as posições do array de alunos */ for (i= 0; i<max_n_alunos; i++) inicia_dados_aluno(&dados[i]); printf("%s - Programa de gestão de alunos\n", argv[0]); if (argc == 2) { /* Programa chamado com um parâmetro */ printf("%s vai carregar todos os dados do ficheiro '%s'\n", argv[0], argv[1]); ler_alunos_ficheiro(argv[1], dados, &n_alunos); printf("falta PROGRAMAR O MENU PRINCIPAL\n"); /* EXERCÍCIO 2: PROGRAMAR O MENU PRINCIPAL DO PROGRAMA, com as opções: printf(" 0: Sair\n"); printf(" 1: Ler alunos de ficheiro\n"); printf(" 2: Acrescentar aluno\n"); printf(" 3: Apagar aluno\n"); printf(" 4: Listar alunos\n"); printf(" 5: Listar alunos por turno\n"); printf(" 6: Salvar alunos para ficheiro\n"); */ Cada opção é realizada utilizando uma das funções apresentadas anteriormente nesta secção. Para facilitar a vida na introdução de um número elevado de alunos foi criado um ficheiro binário com alguns alunos dados.dat, e é fornecido com o enunciado. 4 Makefile O uso da ferramenta make começa a ser interessante quando o programa começa a ter muitos ficheiros. Imagine um programa com 30 ficheiros de código (.c) e uns 10 de include (.h). Imagine que mudava o código num dos ficheiros de código. Não faz sentido compilar todos os ficheiros de código, mas apenas o que mudou. Assim, deve-se agora usar a opção -c no compilador para ele produzir apenas os ficheiros objecto (.o) de cada ficheiro de código e uma instrução final para linkar todos os ficheiros objecto para produzir o ficheiro executável. Este nosso trabalho ainda é muito pequenino, mas o ficheiro Makefile apresentado a seguir tem a seguinte interpretação. O objectivo principal é produzir o executável 8

lista_alunos. Outro objectivo que é tratado se se executar make clean é apagar todos os ficheiros objecto, todos os ficheiros terminados com ~, assim como o executável. Para o objectivo principal é dito que o executável depende dos tempos de modificação dos dois ficheiros objecto indicados. Caso algum deles tenha um tempo de modificação superior ao tempo do ficheiro executável, eles vão ter de ser actualizados e depois executa-se a operação de linkagem ( gcc o ). Para os actualizar vai-se seguir o que é dito na linha respectiva que tem a mesma estrutura (de quem depende e o que se deve fazer). Também pode pensar na Makefile ao contrário, a começar por baixo. Isto é, para cada ficheiro objecto é visto se ele está actualizado referentemente aos ficheiros de que depende, e depois é visto o executável referentemente aos ficheiros objecto. all: lista_alunos lista_alunos: lista_alunos.o aluno.o gcc -o lista_alunos lista_alunos.o aluno.o lista_alunos.o: lista_alunos.c aluno.h gcc -c lista_alunos.c aluno.o: aluno.c aluno.h gcc -c aluno.c clean: rm -f *~ *.o lista_alunos Existe um comando do Linux, designado por touch, que toca no ficheiro, actualizando-lhe a data de modificação. Experimente fazer ou $ touch aluno.c $ touch aluno.h e depois fazer make. Vai ver a ferramenta make executar o que deve para actualizar o ficheiro executável. 9