Baixe o app para aproveitar ainda mais
Prévia do material em texto
Resumo da linguagem C Como é um programa em C? Exemplos de alguns programas escritos em C: 1. Imprimir no ecrã a sequência de caracteres "Hello world!". #include <stdio.h> main() { printf("Hello world!\n"); } 2. Cálculo de potências inteiras: função que inteiros x e n, calcula a n-ésima potência de x; #include <stdio.h> main() /* potências inteiras */ { int i; for(i=0; i<10; i++) printf("%d %d %d\n", i,power(2,i),power(-3,i)); printf("%d \n",power(i,i)); } power(x,n) /* calcula a n-ésima potência de x */ int x, n; { int i, p=1; for(i=1; i <= n; i++) p= p*x; return p;} Podemos salientar o seguinte: - Um programa em C é constituido por uma sequência de funções em que a função main() é a primeira função a ser executada (corresponde à noção de "programa principal" de algumas linguagens, e portanto tem de estar sempre presente). No primeiro exemplo apenas existe a função main() enquanto que no segundo define-se a função power(x,n) que é usada na função main() ("programa principal") para calcular potências inteiras. - Na linguagem C todas as variáveis tem de ser declaradas antes de serem usadas. Na declaração indica-se o tipo de cada variável e eventualmente qual o seu valor inicial. No programa anterior int i, p=1; indica que as variáveis i e p são inteiros e que p toma 1 como valor inicial. - Todas as instruções são terminadas por um ponto-e-vírgula, ";" . Para agrupar um conjunto de instruções de forma a desempenharem o papel de uma só, rodeamos essas instruções com chavetas {}. Por exemplo: n=0; while (n <= 10) { printf( "%d \n",n); n += 2; } - As linhas começadas por # tem significado especial: são instruções não para o compilador C propriamente dito, mas sim para um fase prévia à compilação, da qual se encarrega o chamado pré-compilador, que à custa destas instruções transforma o texto original num outro que o compilador ir ler. Assim #define FALSO 0 leva a que todas as ocorrências de FALSO sejam subtituídas por 0, e, #include <stdio.h> provoca a inclusão neste local de todo o texto que compõe o ficheiro stdio.h. - As linhas não são numeradas sendo a execução sequencial. - Quaisquer caracteres entre /* e */ são ignorados pelo compilador e permitem escrever comentários sobre o programa. Note-se que na maioria dos compiladores não é possível encaixar comentários. a = 8; /* Neste comentario /* <- este símbolo é ignorado */ - Nos dois programas aparece a função de escrita printf() que faz parte da biblioteca standard de funções do C. Esta função escreve no terminal (stdout) a sequência de caracteres que constitui o seu primeiro argumento, substituindo cada sequência do tipo %a (sendo a o formato de escrita) pelo argumento seguinte correspondente. A sequência "\n" permite mudar de linha. No segundo exemplo é escrito o valor de uma variável inteira na base decimal (%d). Mais funções de leitura e de escrita As funções de leitura e escrita não fazem parte da linguagem C mas existem sempre na " biblioteca standard". A função getchar() permite ler um caracter do terminal e putchar() permite escrever um caracter no terminal. main() { char c; while((c=getchar()) != 'A') putchar(c); } Este programa lê um caracter e escreve-o até ser lido o caracter 'A'. Neste caso a função printf() podia ser usada em vez de putchar(): printf("%c",c); onde %c indica que deve ser escrito um caracter. Se em vez de %c se tivesse escrito %d seria escrito o código ASCII do caracter, na base 10. A forma geral da função printf() é: printf(<formato>,<arg1>,...,<argn>) Exemplo: printf("valorn= %d valorx= %f /n",n,x) %d indica que n é escrito como inteiro decimal %f indica que x é do tipo float Se n tivesse o valor 100 e x o valor 5.835, apareceria no ecrã: valorn= 100 valorx= 5.835 Para ler também existe uma função de leitura formatada : scanf(<formato>, <arg1>,...<arg2>) Exemplo: scanf("%d,%f",&x,&n) %d indica que n é inteiro e deve ser lido na base 10 %f indica que x é do tipo float (real) O operador & indica que nos referimos ao endereço das variáveis x e n em vez d o seu valor, isto é, para a função scanf() tem que se passar sempre como parâmetros os endereços das variáveis para se saber onde colocar os valores lidos... A definição duma função tem a forma geral: tipo_do_resultado nome(declaração dos argumentos) { ... instrução ... } A sua chamada noutra função é da forma: nome(argumentos); A instrução return termina a execução da função e retorna um valor como resultado da função, cujo tipo é o do tipo_do_resultado; se na função não existir essa instrução esta é executada mas nenhum valor é retornado (funciona como um procedimento em linguagens de programação BASIC ou Pascal). Se o resultado da função for inteiro não é necessário indicar qual o seu tipo (em C o tipo por defeito é int). Exercício: Escreva um programa em C que imprima 55 vezes no terminal a frase " Este é o meu primeiro programa em C". Tipos de dados, variáveis e expressões Os tipos básicos de dados em C são : O tipo int pode ainda subdividir-se usando os modificadores: short, long e unsigned. Os dois primeiros relacionam-se com o tamanho de inteiros e o último permite considerar só números inteiros positivos. Assim por exemplo, para uma determinada implementação da linguagem C, poderemos ter: Constantes As constantes podem ser de qualquer dos tipos básicos trás referidos. Se forem reais podem representar-se em "notação científica" 3.489e-7 equivale a 3.489x10^-7 Além da base 10 as constantes podem representar inteiros em base 16 ou 8. Assim 0x1f, 037 e 31 representam todos o mesmo número respectivamente em base 16, 8 e 10. Os caracteres representam-se entre plicas, por exemplo 'i' representa o caracter i. As sequências seguintes representam caracteres especiais: %%% Podemos ainda usar #define para definir "constantes simbólicas" e o pré-compilador substituir todas as ocorrências dessas constantes pelo respectivo valor. Exemplo: #define MIN 0 #define MAX 90 #define INCRE 5 #define PI 3.1415926 #define FCONV PI/180 main() /* tabela da função "seno" para valores de 0,...90 para conversão de { radianos para graus */ int x; for (x=MIN; x <= MAX; x += INCRE) printf("%3d %6.5f\n", x, sin(FCONV*x))); } Variáveis As variáveis podem ser de qualquer dos tipos referidos e têm de ser sempre declaradas. Quando variáveis de tipos diferentes aparecem numa mesma expressão, existem algumas regras de conversão entre tipos. Sempre que é calculada uma expressão aritmética os char e short são convertidos para int e os float para double. Se na expressão intervier um long todos os valores são convertidos para long, excepto se também existir um float ou um double, caso em que tudo é convertido para double. Em C a declaração de variáveis indexadas é da forma: tipo nome[MaxVal] que permite reservar espaço para MaxVal variáveis do tipo tipo identificadas por nome[0] a nome[MaxVal -1]. Note-se que MaxVal tem de ser uma constante. Exemplo: #define MAXLINHA 80 main() { int l; char linha[MAXLINHA]; l = le_linha(linha,MAXLINHA); printf("comprimento= %d",l); } le_linha(char s[],int lim); /* lê uma linha e retorna o seu comprimento */ { int c, i; for(i=0; i< lim-1 && (c=getchar()) != '\n' ; ++i) s[i] = c; if( c =='\n '){ s[i] =c; ++i; } s[i] = '\0 '; return(i); } Este programa lê caracteres do terminal e coloca-os na variável indexada linha[] até que o fim de linha é encontrado ('\n'). Depois escreve o número de caracteres dessa linha. Note-se que as variáveis indexadas quando passadas como argumentos duma função são declaradas nessa função sem indicação do seu comprimento Qualquer sequência de caracteres entre aspas"isto e um exemplo" é representado internamente como uma variável indexada de caracteres que termina com o caracter '\0' (caracter nulo). Exemplo: #define FRASE " isto e um exemplo" main() { int l; l=strlen(FRASE); printf("%d\n",l); } strlen(s); char s[]; { int i; i=0; while(s[i] != '\0') ++i; return(i); } Este programa determina o comprimento de FRASE (sequência de caracteres) usando a função strlen() que conta o número de caracteres até ser encontrado o caracter nulo. Normalmente a biblioteca de funções do C possui várias funções para trabalhar com sequências de caracteres (incluindo esta). Operadores aritméticos, relacionais e lógicos Os operadores binários aritméticos são +, -, *, / e o operador modulo %. O único operador aritmético unário é o -. for(i=5; i < 100; i +=5) if ( i%3 != 0) printf( "%d \n",i); Os operadores + e - têm a mesma precedência. Esta é menor que a precedência de *, / e %, que por sua vez é menor que a do operador unário -. A associatividade, para estes operadores, é da esquerda para a direita. Os operadores relacionais são %%% Não confundir o operador igualdade == com o sinal de atribuição = . Por exemplo: n=1; if ( n == 0 ) x += n; else x = 8; if (n != p ) x = n; else x = n; Os operadores lógicos são: %%% A precedência de && é maior que a de || , e ambos têm menor precedência que os operadores relacionais. A expressão i <10 && i != 3 || i >= 20 é equivalente a ((i < 10) && (i != 3) ) || (i >= 20) O operador unário de negação ! converte um operando não nulo em 0 e um zero em 1. if( !num) é equivalente a if(num == 0) Note-se que em C não existem expressões booleanas: Uma expressão é verdadeira se o seu valor for diferente de zero e falsa se o seu valor for zero. Operadores incrementais O C tem dois operadores especiais para incrementar variáveis. O operador ++ adiciona 1 ao seu operando. ++n equivale a n=n+1 O operador -- subtrai 1 ao seu operando. --n equivale a n=n-1; Além disso ambos podem ser usados como operadores prefixos (++n ) ou sufixos ( n++). No primeiro caso a variável é incrementada antes do seu valor ser usado e enquanto no segundo o seu valor é usado e só depois é que a variável é incrementada. (análogo para --). Por exemplo se n tem o valor 5 x = ++n x fica com o valor 6 e n com o valor 6, mas se x = n++ x fica com o valor 5 e n com o valor 6. Atribuição A atribuição de valores a variáveis é feita usando o sinal = x = "ola" A atribuição pode fazer parte de expressões x= (y = 3) + (z = 4*6) atribui a y o valor 3, a z o valor 24 e x o valor 27. Por outro lado se i = i + 2 podemos escrever i += 2 Todos os operadores aritméticos binários tem um operador de atribuição da forma op= e e1 op= e2 é equivalente a e1 = (e1) op (e2) Note-se que: x *= y +1 é equivalente a x = x*(y+1) e não a x = x*y +1 !! Expressões condicionais A instrução if (a>b) z=a; else z=b; determina o máximo de a e b e atribui esse valor a z. Usando o operador condicional ternário ? : podemos escrever a expressão condicional, z= (a>b) ? a : b; /* z=max(a,b) */ A sua forma geral é e1 ? e2 : e3 A expressão e1 é calculada primeiro; se não for nula (verdadeira), então a expressão e2 é calculada e o seu valor é o valor da expressão condicional. Caso contrário a expressão e3 é calculada e a expressão condicional tem o seu valor. Vamos agora ver algumas instruções do C. Instrução condicional if (expressão) instrução else instrução onde a parte com else é opcional. Exemplos: 1. if (n != 0) x = 1/n; if ( m != n) m = n; else printf("%d",n); 2. main() { int x,y scanf("%d,%d",&x,&y) if (x > y) printf("%d",x); else { y += 1; printf("%d",y) } } 3. Pesquisa binária pesqbin(x,v,n) /* procura x em v[0],...,v[n-1]) */ int x, v[], n; { int min, max, med; min = 0; max = n - 1; while(min <= max) { med = (min + max)/2; if (x <v[mid]) max = med -1; else if (x > v[mid]) min = med +1; else /* valor encontrado */ return med; } return -1; } Exercício: Escreva um programa em C que simule o seguinte jogo: Dado um número mágico escolhido pelo "programa" o jogador tem de adivinhar qual é esse número, em várias tentativas nas quais o programa deve indicar se o número do jogador é maior, menor ou igual (neste caso ACERTOU !!) ao número mágico. Instrução "while" while (expressão) instrução main() { char ch; while((ch=getchar()) !='A'); } Instrução "do while" do instrução while ( expressão); do { ++x; do scanf("%d",&a); while(a s 0); } while(x != 20); Instrução "for" for (expressão1; expressão2; expressão3) instrução for(x =1; x <100; x++) if (! (x % 10)) printf("%d",x); Em C as expressões podem ser de qualquer tipo ( mesmo omitidas) e equivalem a: expressão1; while (expressão2){ instrução expressão3; } A expressão1 ou expressão3 podem ser expressões múltiplas, i.e várias expressões separadas por vírgulas (operador ','). for(x = 0, y = 0; x + y <10; ++x) scanf("%d",y); Exemplos: 1. inverte(s) /* inverte uma sequência de caracteres */ char s[]; { int c, i, j; for(i = 0, j = strlen(s) - 1; i < j; i++, j--) c = s[i]; s[i] = s[j] s[j] = c; } } A função strlen() determina o comprimento duma sequência de caracteres. 2. senha(s) char s[]; { int i; for(i = 0; i < 3 && strcmp(s,"segredo"); i++){ printf("qual a senha?\n"); gets(s); } if (i == 3) printf("Não conhece a senha!\n"); } A função strcmp(s1,s2) compara as sequências de caracteres s1 e s2 e retorna o valor 0 se forem iguais e um valor diferente de zero caso contrário. A função gets(s1) permite ler uma sequência de caracteres. 3. Converte uma sequência de caracteres no numero inteiro correspondente, na base 10. atoi(char s[]) { int i, n, sinal; for ( i = 0; s[i] == ' ' || s[i] == '\n' || s[i] == '\t'; i++); /*salta espaços iniciais */ sinal = 1 if (s[i] == '+' || s[i] == '-') /* determina sinal */ sinal = (s[i++] == '+') ? 1 : -1 for(n = 0; s[i] >= '0' && s[i] <= '9'; i++) n= 10*n + s[i] - `0`; return(sinal*n); } Instrução "switch" Esta instrução pode ser convertida num grupo de instruções equivalente a if ..else if ... else if... switch(expressão) instrução O valor da expressão é um inteiro (considerando as regras de conversão de tipos) e as instruções são habitualmente da forma: case constante : onde os valores dessas constantes têm de ser diferentes num mesmo "switch"; e uma pode ser da forma default : O valor da expressão é comparado com as constantes e as instruções associadas serão executadas. Vamos ver um exemplo ! Suponha que se pretende um programa que permita fazer a manutenção duma lista telefónica e nomeadamente introduzir um novo assinante, procurar um número de telefone dado o nome do assinante, retirar um assinante, listar todos os assinantes,etc. Esse programa pode começar com um "menu" que permita escolher qual a tarefa a realizar. Podemos ter então uma função menu(): menu() { char c; do{ printf("0. Terminar\n"); printf ("1 . Novo assinante\n" ); printf("2. Procura por nome\n"); printf("3. Procura por telefone\n"); printf("4. Retirar assinante\n"); printf("5. Lista de assinantes\n"); printf("Escolha opção:") c = getchar(); switch(c){ case '0': break; case '1': {novo(); break;} case '2': {p_nome(); break;} case '3': {p_telefone(); break;} case '4': {apaga(); break;} case '5': {lista(); break;} default: {printf("Opção errada\n"); break;} } } while(c != '0'); } Depois de se ter escolhido uma opção o seu valoré comparado com cada uma dos valores de 0 a 5. Se c for igual por exemplo a 3 então a função correspondente a "procura por telefone" é executada. A instrução break é usada para terminar o switch imediatadamente. Note-se que break pode ser também usada para sair de ciclos (while, do while e for) antes de se verificarem as condições de "fim de ciclo". Isto pode acontecer se existirem condições especiais para terminar um dado ciclo. Exemplos: 1. for(i = 0; i <100; i++) { if (a[i]=0) break; s += a[i] } 2. while(1) { c = getchar(); if (c == 'A') break; } Se existirem vários ciclos encaixados o break só termina o mais interior. A instrução continue pode ser usada num ciclo (while, do while e for) para obrigar a uma nova iteração sem executar todas as instruções do ciclo: for(i = 0; i < N; i++) { if (a[i] < 0) continue; s += a[i]; } Este ciclo adiciona os valores positivos de a[] e 'salta' nos negativos. Funções e Variáveis Já vimos que um programa em C é um conjunto de definições de funções e que a comunicação entre elas é feita pelos seus argumentos, pelos valores que retornam e, como veremos a seguir, pelas variáveis externas. Os argumentos das funções são passados por valor, isto é, a função que é chamada recebe uma cópia de cada argumento e não o endereço de cada variável. Isto significa que essa função não pode modificar o argumento original na função que a chamou. Dentro de cada função os argumentos são considerados variáveis locais inicializadas com os valores com que a função foi chamada. Contudo se uma variável indexada for passada como argumento os seus elementos não são copiados mas sim é passado o endereço do seu primeiro elemento. Assim a função que foi chamada pode alterar os valores da variável. Diz-se que as variáveis indexadas são passadas por referência. Dum modo geral as variáveis podem ser externas ou internas. São externas se forem definidas fora de qualquer função e internas se são argumentos de funções o u definidas dentro duma função. As internas são locais ao mais exterior par de chavetas que contém a sua definição e não são conhecidas fora dele ( em particular, variáveis locais com o mesmo nome mas pertencendo a funções diferentes são diferentes). Por defeito estas variáveis são automáticas, ou seja, não mantém os seus valores em chamadas consecutivas da função em que estão definidas. Seja, main() { int i; for(i=0; i <100; i++) if (complica(i)) printf("%d e' impar/n", i); } complica(i) int i; { int j,n=1; printf("%d \n",n++); j=i%2; if(i==10) i=100; return j; } Exercício: Descreve o que este programa faz atendendo ao que foi dito anteriormente . Escreve um programa muito mais simples que tenha o mesmo resultado. As variáveis externas são globais a todo o programa, isto é, podem ser usadas em qualquer função desse programa. As variáveis externas existem e mantêm sempre os seus valores em vez de "aparecerem" quando as funções são chamadas e "desaparecerem" quando estas retornam. Por este motivo se tivermos mais que uma função que use os mesmos dados podemos usar variáveis globais para definir esses dados em vez de os passarmos como argumentos das funções. Note-se que se uma função declarar como variável interna uma variável cujo nome foi usado previamente e para uma variável externa, esse nome passa a referir a variável interna que foi declarada (sendo portanto impossível usar a variável externa, nessa função) . int i; main() { for(i=0; i <100; i++) if (complica()) printf("%d e' impar\n", i); } complica() { int j, n=1; printf("%d /n",n++); j=i%2; if (i==10) i=100; return j; } Neste exemplo i é uma variável global e neste caso o programa pára ao fim de 10 passos. Quando se usa uma variável externa numa dada função deve-se declarar essa variável colocando o prefixo extern e a sua declaração normal para indicar que ela está definida fora dessa função. Contudo isto só é obrigatório quando a função que usar essa variável estiver definida antes da definição da variável ou quando a funções que constituem o programa estiverem definidas em vários ficheiros (e a função que use essa variável estiver definida num ficheiro diferente do da definição da variável). Assim no exemplo anterior podia-se ter escrito na função complica(), ou na main() extern int i; As variáveis, tanto externas como internas, podem ainda ser classificadas de estáticas. Se forem internas as variáveis retêm o seu valor ao longo de várias chamadas à função em que estão definidas. Se forem externas elas são conhecidas no ficheiro em que são declaradas mas não noutros ficheiros que façam parte do mesmo programa. Para indicar que uma dada variável é estática usa-se o prefixo static na sua declaração. No exemplo anterior se se declarar static int n; na função complica() o valor da variável n é mantido entre as várias chamadas da função portanto o seu valor é incrementado de 1 a 100 ao longo da execução do programa.
Compartilhar