Sistemas Operativos 2006/2007 Breve Introdução à Linguagem C Paulo Marques Departamento de Eng. Informática Universidade de Coimbra [email protected] Bibliografia C How to Program, 5th Edition by Deitel & Associates Prentice Hall, August 2006 ISBN 0132404168 The C Programming Language, 2nd Edition by Kernighan & Ritchie Prentice Hall, March 1988 ISBN 0131103628 2 Cálculo de uma Raíz Quadrada Qual o algoritmo para calcular a raiz quadrada de um número x? x y0 49 20 n y 0 20 1 11.225 2 7.795128 3 7.040553 4 7.000117 5 7 6 7 7 7 1 x yn ( yn ) 2 yn “Método Babilónico” 3 Programa de Cálculo da Raíz Quadrada 4 Compilar e Executar $ gcc –Wall raiz.c –o raiz $ ./raiz 5 Notas #include <stdio.h> #define ERRO_MAXIMO 0.0001 As funções (métodos) existem directamente no ficheiro Controlo de fluxo de execução / tipos Definição de uma constante Inexistência de classes Inclui a biblioteca “stdio” (Standard IO) Semelhante ao Java main() / printf() main() Função principal do programa e seu ponto de entrada printf() Permite escrever dados para o ecrã 6 Tipos de Dados Básicos O tamanho de cada tipo de dados varia de plataforma para plataforma. sizeof(datatype) Retorna o tamanho, em bytes do tipo de dados 7 Controlo de Fluxo de Execução 8 Tabelas double pessoas[10]; Cria uma tabela de 10 elementos do tipo double na stack Acesso como em Java (pessoas[i]) O tamanho é pré-definido e fixo! pessoas 0 1 2 3 4 5 6 7 8 9 double matrix[3][3]; matrix [0][0] [0][1] [0][2] [1][0] [1][1] [1][2] [2][0] [2][1] [2][2] 9 Pequeno exemplo com tabelas simples 10 Notas As tabelas quando são declaradas têm de indicar o tamanho dos dados que vão conter! scanf(“%d”, &variavel_int) Lê do teclado um inteiro scanf(“%lf”, &variavel_double) Lê do teclado um double Para ultrapassar esta limitação tem de se utilizar ponteiros (mais sobre isso daqui a pouco…) O & representa o endereço da variável destino. Isto é, um ponteiro (mais sobre isso daqui a pouco…) media = 0.0; desvio_padrao = 0.0; Inicialização EXPLÍCITA de variáveis!!! O C não inicializa as variáveis automaticamente. 11 Strings char nome[6] = “JORGE”; A tabela tem de conter 6 elementos: Cinco para os caracteres: ‘J’, ‘O’, ‘R’, ‘G’, ‘E’ Um para o terminador da string: ‘\0’ char nome[] = “JORGE”; char nome[] = { ‘J’, ‘O’, ‘R’, ‘G’, ‘E’, ‘\0’ }; char* nome = “JORGE”; Funções úteis: #include <string.h> strcpy(), strncpy(), strcmp(), strncmp(), strcat(), strncat(), strstr(), strchr(), sprintf() 12 Ponteiros (1) Um ponteiro representa um endereço de memória, permitindo aceder a outras variáveis ou buffers explicitamente reservados int* ptr; ptr *ptr ptr é um ponteiro para uma variável inteira é o ponteiro (endereço) em si valor apontado por ptr &var representa o endereço da variável var NULL ponteiro nulo (não aponta para nada) 13 Exemplo Simples – Notação // Um inteiro int idade = 20; // Um ponteiro para um inteiro int* ptrIdade = NULL; // Uma atribuição... ptrIdade = &idade; idade (0x5490) “20” “30” ptrIdade (0x6000) 0 ptrIdade (0x6000) 0x5490 // Acesso à idade original... printf(“%d”, *ptrIdade); // Acesso à idade original... *ptrIdade = 30; (Nota para a versão impressa: este slide contém uma uma animação em que o 20 originalmente em idade passa a 30) 14 Quiz 15 Alocação dinâmica de memória As tabelas têm de ter um tamanho fixo Para resolver esse problema, utiliza-se: void* malloc(size_t total_size) Alocação dinâmica de memória Ponteiros Reserva total_size size bytes retornando um ponteiro para a zona de memória reservada. É necessário converter o ponteiro retornado num ponteiro “real” void free(void* ptr) Liberta a zona de memória apontada por ptr, anteriormente reservada 16 Exemplo de uso de memória dinâmica Notas: Muitas vezes é possível utilizar os ponteiros como se fossem tabelas, assim como usar tabelas como se fossem ponteiros Ao utilizar ponteiros como tabelas, o compilador gera o código para aceder correctamente aos valores apontados pelos índices. Exemplo: tabela[i] é equivalente a *((char*) tabela + sizeof(double)*i) Ao utilizar-se um ponteiro directamente, fazendo-se aritmética com o mesmo, os avanços são em múltiplos do tipo de dados base. Exemplo: tabela[2] é equivalente a *(tabela+2), que é sensivelmente equivalente a *((char*) tabela + sizeof(double)*i) (na verdade é um “bug” subtil…) 17 Passagem de parâmetros por referência Por vezes é necessário ter funções cujos argumentos sejam passados por referência… Função que troca dois valores passados como argumento Função que calcula os quadrados de elementos passados numa tabela, por referência 18 CUIDADO Nunca retornar referências para memória reservada na stack!!!! 19 Possível solução Existem outras soluções possíveis (e até mais seguras)… Qual é o problema desta abordagem? 20 Estruturas Uma estrutura permite agrupar a informação em blocos Há diferentes formas de o fazer, todas equivalentes Original Mais prática Abreviada 21 Estruturas e Ponteiros Quando se utilizam estruturas e ponteiros, existe um operador especial de acesso: -> É equivalente escrever: ptrPessoa->nome ou (*ptrPessoa).nome 22 Mais um exemplo de ponteiros… Uma lista ligada é uma estrutura de dados que permite armazenar um número arbitrário de elementos não pré-definidos Consiste num encadear de elementos, em que cada elemento possui um ponteiro para o próximo elemento list 30 value 20 next value next NULL 10 value next 23 Programa (Parte I) 24 Programa (Parte II) NOTA: É muito mais fácil adicionar “à cabeça” do que no final da lista! TODO: Implementar as funções: remove_list(), remove_element(), is_present() A memória não está a ser liberta no final do programa!!! 25 Leitura e Escrita básica de disco Existem dois tipos de leitura e escrita: Baixo nível: open()/close()/read()/write() Alto nível: fopen()/fclose()/fprintf()/fscanf()/fread() 26 write_random_int_file() 27 print_int_file() 28 » Now this is not the end. It is not even the beginning of the end. But it is, perhaps, the end of the beginning « Winston Churchill 29