Apostila C Boa

Embed Size (px)

Citation preview

  • Linguagem C - Notas de Aula

    Profa . Carmem Hara e Prof. Wagner ZolaReviso: Prof. Armando Luiz N. Delgado

    Maio 2008

    Parte I

    Programao Bsica em CEstas notas de aula apresentam os conceitos bsicos da Linguagem C e se prope a abordar apenas o que importante para a compreenso bsica de programas de computadores.

    1

  • 1 Programas C

    Um programa C consiste de uma ou mais partes chamadas funes. Um programa em C consiste de pelomenos uma funo chamada main. Esta funo marca o ponto de incio de execuo do programa.

    Programas C tem a seguinte estrutura geral:

    #include

    definio de constantes

    funes

    int main(){

    declarao de variveis....sentenas....

    }

    1.1 Sentenas: simples e compostas

    Cada instruo em C chamada de sentena. Sentenas simples so terminadas com um ponto e vrgula.Usando chaves, podemos agrupar sentenas em blocos, chamados de sentenas compostas.

    Exemplos de sentenas incluem:

    Simples:

    x = 3;

    Composta:

    {i = 3;

    printf("%d\n", i);

    i = i + 1;}

    O corpo da funo main() um exemplo de sentena composta.

    1.2 Variveis em C

    Uma varivel uma informao qe voc pode usar dentro de um programa C . Esta informao est associadacom um lugar especfico da memria (isso feito pelo compilador). O nome da varivel e o endereo damemria onde a informao est armazenada esto associados. O nome e o endereo no mudam. Mas, ovalor da informao pode mudar (o valor do que est dentro da caixa pode mudar, embora o tipo seja sempreo mesmo). Cada varivel tem um tipo associado. Alguns tipos de variveis que discutiremos incluem int,char e float.

    Cada varivel usa uma determinada quantidade de armazenamento em memria. A maneira como sabe-mos quantos bytes so utilizados pelo tipo da varivel. Variveis do mesmo tipo utilizam o mesmo nmerode bytes, no interessando qual o valor que a varivel armazena.

    2

  • Um dos tipos utilizados para armazanar nmeros o int. Ele usado para armazenar nmeros inteiros.Outro tipo o char, usado para armazenar caracteres. Um caracter um smbolo (uma letra do alfabeto,

    um dgito, um smbolo de pontuao, etc). Um char armazenado em 1 byte de memria. Cada caracter associado com um valor entre 0 e 255. O compilador C faz a traduo para voc, portanto voc no precisasaber estes nmeros. Em C , um caracter representado entre apstrofes (). Por exemplo, C, a, 5, $.Note que 5 um caracter, e no o inteiro 5.

    A figura acima mostra como um int e um char so armazenados na memria.Outro tipo existente o float, usado para armazenar nmeros reais (nmeros com o ponto decimal). Este

    nmeros so armazenados em duas partes: a mantissa e o expoente. Eles so armazenados de uma maneiraque se assemelha a notao exponencial. Por exemplo, o nmero 6.023 1023 escrito como 6.023e23.Neste caso, a mantissa 6.023 e o expoente 23.

    Estes nmeros so armazenados de uma forma padro, tal que a mantissa tem apenas um dgito paraa esquerda do ponto decimal. Desta forma, 3634.1 escrito como 3.6341e3, e 0.0000341 escrito 3.41e-5. Note tambm que a preciso limitada pela mantissa. Somente os 6 dgitos mais significativos soarmazenados. Em Dev-C++ um float ocupa 4 bytes de memria. H muitos outros tipos (short, long,double), que sero descritos no futuro.

    1.3 Definio de Varivel em C

    Se voc usa variveis no programa, voc deve defini-las. Isto envolve especificar o tipo da varivel e o seunome. As regras para formar nomes de variveis em C so:

    qualquer sequncia de letras, digitos, e _, MAS DEVE COMEAR com uma letra ou com _.Por exemplo, hora_inicio, tempo, var1 so nomes de variveis vlidos, enquanto 3horas, total$ eazul-claro no so nomes vlidos;

    Maisculas 6= Minsculas; No so permitidos nomes ou palavras reservadas da linguagem. sempre uma boa idia ter certas regras (para voc mesmo) para nomear variveis para tornar o pro-

    grama mais legvel:

    D nomes significativos as variveis (mas no muito longos); Use nomes de variveis do tipo i, j, k somente para variveis tipo contadores; Pode-se usar letras maisculas ou _ para juntar palavras. Por exemplo, horaInicio ou hora_inicio.

    Use o que voc preferir, mas SEJA CONSISTENTE em sua escolha.

    3

  • auto break case char const continuedefault do double else enum externfloat for goto if int longmain register return short signed sizeofstatic struct switch typedef union unsignedvoid volatile while

    Tabela 1: Palavras Reservadas da Linguagem C

    Os tipos bsicos de dados existentes em C so:

    Tipo de Dado Bits Faixa de Valores

    char 8 -128 a 127int 16 -32768 a 32767float 32 7 dgitos significativosdouble 64 15 dgitos significativos

    Abaixo est um exemplo de um programa com diversas definies de variveis:

    int main(){

    int pera;char qualidade;float peso;

    pera = 3;qualidade = A;peso = 0.653;...

    }

    Quando variveis so definidas, elas no possuem valores ainda. Ns damos valores s variveis usandoo operador de atribuio (=). Variveis tambm podem ser inicializadas para conter valores quando sodefinidas. Usando esta forma, o program acima ficaria:

    int main(){

    int pera = 3;char qualidade = A;float peso = 0.653;

    ...}

    Para resumir: quando um programa executado, uma varivel associada com:

    um tipo: diz quantos bytes a varivel ocupa, e como ela deve ser interpretada. um nome: um identificador. um endereo: o endereo do byte menos significativo do local da memria associado a varivel.

    4

  • um valor: o contedo real dos bytes associados com a varivel; o valor da varivel depende do tipoda varivel; a definio da varivel no d valor a varivel; o valor dado pelo operador de atribuio,ou usando a funo scanf(). Ns veremos mais tarde que a funo scanf() atribui a uma varivel umvalor digitado no teclado.

    Em C , nomes de variveis devem ser declarados antes de serem usados. Se no for declarado, ocorrerum erro de compilao.

    Devem ser dados valores s variveis antes que sejam utilizadas. Se voc tentar utilizar a varivelantes de especificar o seu valor, voc obter lixo (o que quer que esteja armazenado no endereo davarivel na memria quando o programa comea sua execuo), culminando com falha na execuodo programa.

    1.4 Constantes

    Em C , alm de variveis, ns podemos usar tambm nmeros ou caracteres cujos valores no mudam. Elesso chamados de constantes. Constantes no so associados a lugares na memria.

    Assim como variveis, constantes tambm tm tipos. Uma constante pode ser do tipo int, char, etc.Voc nao tem que declarar constantes, e pode utiliz-las diretamente (o compilador reconhece o tipo pelamaneira que so escritos). Por exemplo, 2 do tipo int, e 2.0 do tipo double. Por conveno, todas asconstantes reais so do tipo double.

    1.5 Caracteres Constantes

    Um constante caracter escrita entre apstrofes, como em A. Todas as letras, nmeros e smbolos quepodem ser impressos so escritos desta forma em C . s vezes precisamos de caracteres que no podemser impressos, por exemplo, o caracter de nova linha, que no tem uma tecla especfica no teclado. Nestecaso, usa-se caracteres de escape. Tais caracteres so escritos no somente como um smbolo entre aps-trofes, mas como um sequncia de caracteres entre apstrofes. Por exemplo, \n o caracter para novalinha (uma sequncia que inicia com a barra invertida chamada de sequncia de escape). Se quisermosrepresentar o caracter de barra invertida, temos que escrever \\. Note que \n o caracter de nova linha- embora use-se dois smbolos para represent-lo. A barra invertida chamada de escape. Ele diz ao com-pilador que o n que segue no a letra n, mas que a sequncia completa de caracteres deve ser interpretadacomo o caracter de nova linha.

    Cada caracter constante tem um valor inteiro igual ao seu valor numrico do seu cdigo ASCII. Porexemplo, considere a constante A, que tem cdigo ASCII 65, e B que tem cdigo 66. Ns podemos usara expresso A + 1. O resultado o valor 66. E se o tipo da expresso resultante for char, ento o resultadoda expresso B.

    1.6 Entrada e Sada

    Se quisermos que um programa C mostre alguns resultados, ou se quisermos que o programa pea ao usu-rio que entre com alguma informao, ns podemos usar as funes existentes em C chamadas printf() escanf(). Se voc quiser usar estas funes em seu programa, voce deve incluir a seguinte linha no incio doseu cdigo fonte:

    #include Isto faz com que o arquivo header chamado stdio.h seja includo no seu arquivo fonte. Este arquivo

    contm prottipos das funes print() e scanf(). Ele declara ao compilador o nome das funes e algumasinformaes adicionais necessrias para que as instrues sejam executadas corretamente.

    5

  • 1.7 Exibindo informaes na tela: printf()

    printf() pode ser utilizado para imprimir mensagens e valores em uma variedade de formatos. Por enquanto,printf() melhor descrito atravs de exemplos.

    printf(Al todo mundon);

    Imprimir Al todo mundo na tela do computador.Para dizer funo printf exatamente o que fazer, ns devemos especificar o que ser impresso. Ns

    devemos dar a funo o que chamamos de argumentos. No exemplo acima, Alo todo mundo umargumento para a funo printf().

    O primeiro argumento do printf() sempre um string (uma srie de caracteres entre aspas (")).Ns tambm podemos colocar caracteres de escape no string para imprimir caracteres especiais. Por

    exemplo, colocando \n no string causa que o restante do string seja impresso na linha seguinte. Outroscaracteres de escape sero apresentados no futuro.

    Se quisermos imprimir o valor de expresses variveis, argumentos adicionais so necessrios. Dize-mos ao printf() como mostrar valores de expresses usando especificadores de formato. Podemos colocar%c, %d, %f (ou outros especificadores de formato listados no texto) dentro do primeiro argumento paraespecificar o que queremos dar display. Ns ento passamos argumentos adicionais que ser referem aosespecificadores de formato (na ordem em que eles ocorrem). Este argumentos podem ser constantes ouvariveis, ou alguma expresso mais complicada. O que quer que eles sejam, eles devem ser avaliados e osvalores obtidos e impressos de acordo com os especificadores de formato. Considere o seguinte programa:

    #include #define PRECO 1.99

    int main(){

    int pera = 3;char qualidade = A;float peso = 2.5;

    printf(Existem %d peras de qualidade %c , pera, qualidade);printf(pesando %f quilos.\n, peso);printf(O preco por quilo e %f, total e %f\n, PRECO, peso * PRECO);

    }

    A sada do programa ser:

    Existem 3 peras de qualidade A pesando 2.500000 quilos.O preco por quilo e 1.990000, total e 4.975000

    A linha #define PRECO 1.99 no incio do programa define uma macro. Ou seja, definimos quePRECO um sinnimo para 1.99 e, portanto, toda ocorrncia de PRECO no programa substitudo por1.99 antes que ele seja compilado.

    Ns tambm podemos especificar o tamanho utilizado para impresso da seguinte forma:

    %6d inteiro, com pelo tamanho pelo menos 6%6f ponto flutuante, com tamanho pelo menos 6%.3f ponto flutuante, com 3 digitos depois do ponto decimal%6.3fponto flutuante, com tamanho pelo menos 6 e 3 digitos depois do ponto decimal%6.0fponto flutuante, com pelo menos tamanho 6 e nenhum digito depois do ponto decimal.

    6

  • Note que a especificao de tamanho simplesmente determina o tamanho mnimo. Se o nmero nocouber no tamanho especificado, o nmero completo ser mostrado.

    Quando utilizar a funo printf() tenha cuidado para especificar o tipo correto dos argumentos. Se o tipodo argumento no for correto, o compilador Dev-C++ no acusar erro, e um valor incorreto ser mostrado.Por exemplo, no programa abaixo que est incorreto:

    #include

    int main(){

    printf(Exemplo errado: %d\n, 3.14159);}

    O resultado do programa ser alguma coisa como:

    Exemplo errado: -31147

    1.8 Lendo informao: scanf()

    scanf() pode ser usado para ler valores digitados no teclado. Estes valores so lidos de acordo com especi-ficadores de converso, que so especificados pelo programador como argumentos do scanf().

    Considere o seguinte programa:

    #include

    int main(){

    int idade;

    printf(Entre sua idade: );scanf(%d, &idade);

    printf(Voce tem %d anos\n, idade);}

    Este programa mostrar no monitor: Entre sua idade: e aguardar que um nmero seja digitado e atecla ENTER. Depois disso, a varivel idade conter o valor digitado pelo usurio.

    Assim como com o printf(), o primeiro argumento o especificador de formato. Os prximos argumen-tos correspondem a o que est sendo especificado pelo primeiro argumento.

    Note o & precedendo a varivel idade. Simplesmente lembre-se que voc geralmente precisar colocarum & precedendo nomes de variveis em um scanf(). Voc sempre precisar us-lo antes de variveis dotipo primrio como os discutidos at este momento (int, char, float, e suas verses long e unsigned).

    Mais de um valor pode ser lido por um mesmo scanf(). Considere o seguinte exemplo:

    #include

    int main(){

    int dia, mes, ano;

    printf(Entre com a data do seu aniversario (dd mm aa): );scanf(%d %d %d, &dia, &mes, &ano);

    7

  • printf(Voce nasceu em %d/%d/%d\n, dia, mes, ano);}

    Este exemplo funciona exatamente como o exemplo anterior. Um nico scanf() l os 3 nmeros quandoestes nmeros so separados por espaos (espaos em branco, tabulao, novas linhas). Ento voc podeteclar ENTER depois de cada nmero, ou colocar espaos ou tabulaes entre os nmeros. Os espaos soignorados pelo scanf(). Os brancos na especificao de formato do scanf(), %d %d %d so simplesmentepara facilitar a leitura do programa, e no tem nada a ver com os espaos ignorados pelo scanf(). Se tivsse-mos escrito %d%d%d, o scanf() funcionaria da mesma forma. Os espaos em branco simplesmente sonecessrios para saber quando termina um nmero e comea o outro.

    Porm se o scanf() estiver lendo caracteres (%c), os espaos no so ignorados, j que espaos socaracteres vlidos na linguagem. Por exemplo, o cdigo ASCII para espao em branco e 32.

    1.9 Algoritmo X Programa

    ALGORITMO PERIMETRO_AREA

    /* Calcula o permetro e a area de uma circunferenciade raio R (fornecido pelo usuario) */

    /* Definir variaveis */int Raio;float Perim, Area, PI;PI = 3.14159;

    /* Obter Raio da circunferencia */Escreva("Entre com o valor do raio:");Leia(Raio);

    /* Calcular Perimetro do Circulo */Perim = 2 * PI * Raio;

    /* Calcular Area da Circunferencia */Area = PI * Raio ** 2;

    /* Exibir Resultados */Escreva("O perimetro da circunferencia de raio", Raio, "eh", Perim);Escreva("e a area eh ",Area);

    /* Terminar Programa */

    FIM_ALGORITMO PERIMETRO_AREA

    Programa em C

    /* programa que calcula o permetro e a rea de umacircunferncia de raio R (fornecido pelo usurio) */

    #include /* inclui diretivas de entrada-sada */#include /* inclui diretivas das funes matemticas */

    8

  • #define PI 3.14159

    int main(){

    /* Definir variaveis */int Raio;float Perim, Area;

    /* Obter Raio da circunferencia */printf("Entre com o valor do raio: ");scanf("%d", &Raio);

    /* Calcular Perimetro do Circulo */Perim = 2 * PI * Raio;

    /* Calcular Area da Circunferencia */Area = PI * pow(Raio, 2);

    /* Exibir Resultados */printf("O perimetro da circunferencia de raio %d eh %.2f \n", Raio, Perim);printf("e a area eh %.2f", Area);

    }

    9

  • 2 Operaes Aritmticas e Expresses.Operaes Relacionais.

    2.1 Operaes Aritmticas

    Em C , ns podemos executar operaes aritmticas usando variveis e constantes. Algumas operaes maiscomuns so:

    + adio

    - subtrao

    * multiplicao

    / diviso

    % resto (mdulo)

    Estas operaes podem ser usadas como mostram os exemplos abaixo, assumindo que as variveis ne-cessrias j esto declaradas:

    celsius = (fahrenheit - 32) * 5.0 / 9.0;

    forca = massa * aceleracao;

    i = i + 1;

    2.1.1 Precedncia de Operadores

    Em C , assim como em lgebra, h uma ordem de precedncia de operadores.Assim, em (2 + x)(3x2 +1), expresses em parntesis so avaliadas primeiro, seguidos por exponenci-

    ao, multiplicao, diviso, adio e subtrao.Da mesma forma, em C , expresses entre parntesis so executadas primeiro, seguidas de *, / and %

    (que tem todos a mesma precedncia), seguido de + and - (ambos com a mesma precedncia).Quando operaes adjacentes tm a mesma precedncia, elas so associadas da esquerda para a direita.

    Assim, a * b / c * d % e o mesmo que ((((a * b) / c) * d) % e).

    2.1.2 A Operao de Resto (%)

    Esta operao usada quando queremos encontrar o resto da diviso de dois inteiros. Por exemplo, 22dividido por 5 4, com resto 2 (4 5 + 2 = 22).

    Em C , a expresso 22 % 5 ter valor 2.Note que % s pode ser utilizados entre dois inteiros. Usando ele com um operando do tipo float

    causa um erro de compilao (como em 22.3 % 5).

    2.1.3 Expresses e Variveis

    Expresses aritmticas podem ser usadas na maior parte dos lugares em que uma varivel pode ser usada.O exemplo seguinte vlido:

    int raio = 3 * 5 + 1;

    printf("circunferencia = %f\n", 2 * 3.14 * raio);10

  • Exemplos de lugares onde uma expresso aritmtica NO pode ser usada incluem:

    int yucky + 2 = 5;

    scanf("%d", &(oops * 5))

    Este exemplo ilegal e causar erro de compilao.

    2.2 Operadores Relacionais

    Em C , h operadores que podem ser usados para comparar expresses: os operadores relacionais.H seis operadores relacionais em C :

    < menor que

    > maior que

    = maior ou igual que ()== igual a

    != no igual a (6=)Os resultados deste operadores 0 (correspondendo a falso), ou 1 (correspondendo a verdadeiro). Va-

    lores como esses so chamados valores booleanos. Algumas linguagens de programao como Pascal temum tipo de varivel distinto para valores booleanos. Este no o caso do C , onde valores booleanos soarmazenados como variveis numricas tais como o int.

    Considere o seguinte programa:

    int main(){

    int idade;

    idade = 17;printf("Pode tirar carteira de motorista? %d\n", idade >= 18);idade = 35;printf("Pode tirar carteira de motorista? %d\n", idade >= 18);

    }

    A sada deste programa ser:

    Pode tirar carteira de motorista? 0Pode tirar carteira de motorista? 1

    Na primeira linha, idade 17. Logo, 17 >= 18 falso, que 0.Depois disso, idade 35. Logo, 35 >= 18 verdadeiro, que 1.Note tambm que o operador de igualdade escrito com sinais de igual duplo, ==, no =. Tenha

    cuidado com esta diferena, j que colocar = no lugar de == no um erro sinttico (no gera erro decompilao), e no significa o que voc espera.

    11

  • 2.2.1 Precedncia dos operadores relacionais

    Operadores aritmticos tem precedncia maior que os operadores relacionais. Por exemplo, a expresso3 + 5 < 6 * 2 o mesmo que (3 + 5) < (6 * 2).

    Se por alguma razo voc quer que o resultado do uma operao relacional em uma expresso aritmtica, necessrio usar parntesis. Por exemplo, a expresso score + (score == 0) ser sempre igual aovalor de score, exceto quando o valor de score seja 0. Neste caso, o valor da expresso 1 (porque(score == 0) igual a 1).

    Uma observao sobre valores booleanos embora voc possa assumir que o valor de uma operaorelacional 0 ou 1 em C , qualquer valor diferente de zero considerado verdadeiro. Falaremos sobreisso mais tarde durante o curso.

    2.3 Reviso de Expresses:

    O que impresso pelos dois programas abaixo?

    #include

    int main() {int score = 5;

    printf(%d, 5 + 10 * 5 % 6); ==> 7printf(%d, 10 / 4); ==> 2printf(%f, 10.0 / 4.0); ==> 2.5printf(%c, A + 1); ==> Bprintf(%d, score + (score == 0)); ==> 5

    }

    #include

    int main() {int n1, n2, n3;

    printf(Entre com um numero inteiro: );scanf(%d, &n1);n1 += n1 * 10;n2 = n1 / 5;n3 = n2 % 5 * 7;n2 *= n3-- % 4;printf(%d %d %d, n2, n3, n2 != n3 + 21);

    }

    Como a seguinte expresso completamente parentizada ?

    a * b / c + 30 >= 45 + d * 3 ++e == 10

    2.4 Exemplo de programas

    Exemplo 1: escreva um programa que leia um nmero inteiro e imprima 0 se o nmero for par e 1 se onmero for mpar.

    12

  • #include

    int main() {int numero;

    printf(Entre com um numero inteiro: );scanf(%d, &numero);printf(\nPar? %d\n, numero % 2 );

    }

    Exemplo 2: escreva um programa que leia 3 nmeros inteiros e calcule a soma, mdia, e produto.

    #include

    int main() {int n1, n2, n3;int soma;

    printf( "Entre com 3 numeros inteiros: ");scanf( "%d %d %d",&n1, &n2, &n3);soma = n1 + n2 + n3;printf( "Soma = %d\n", soma );printf( "Media = %8.2f\n", soma / 3.0 );printf( "Produto = %d\n", n1 * n2 * n3 );

    }

    2.5 Precedncia e associatividade de operadores

    Operador Associatividade

    () esquerda para direita++ -- & (unrios) direita para esquerda* / % esquerda para direita+ - esquerda para direita< >= esquerda para direita== != esquerda para direita= += -= *= /= %= direita para esquerda

    13

  • 3 Expresses como valores

    Em C , todas as expresses so avaliadas. O resultado da avaliao um valor e pode ser usado em quaisquerlugares.

    3.1 Expresses aritmticas, relacionais e lgicas

    Como voc j sabe, expresses usando operadores aritmticos, relacionais e lgicos1 so avaliados. O valorresultante um nmero. Para os operadores relacionais e lgicos, este nmero pode ser 0 (que significafalso) ou 1 (que significa verdadeiro). Por exemplo:

    3 + 5 * 4 % (2 + 8) tem valor 3;3 < 5 tem valor 1;x + 1 tem valor igual ao valor

    da varivel x mais um;(x < 1) || (x > 4) tem valor 1 quando o va-

    lor da varivel x fora dointervalo [1,4], e 0 quandox est dentro do intervalo.

    3.2 Expresses envolvendo o operador de atribuio (=)

    O formato do operador de atribuio :

    lvalue = expressao (1)

    Um lvalue (do ingls left-hand-side value - valor a esquerda) um valor que se refere a um endereona memria do computador. At agora, o nico lvalue vlido visto no curso o nome de uma varivel. Amaneira que a atribuio funciona a seguinte: a expresso do lado direito avaliada, e o valor copiadopara o endereo da memria associada ao lvalue. O tipo do objeto do lvalue determina como o valor daexpressao armazenada na memria.

    Expresses de atribuio, assim como expresses, tm valor. O valor de uma expresso de atribuio dado pelo valor da expresso do lado direito do =. Por exemplo:

    x = 3 tem valor 3;x = y+1 tem o valor da expresso

    y+1.Como consequncia do fato que atribuies serem expresses que so associadas da direita para es-

    querda, podemos escrever sentenas como:

    i = j = k = 0;

    Que, usando parnteses, equivalente a i = (j = (k = 0)). Ou seja, primeiro o valor 0 atri-budo a k, o valor de k = 0 (que zero) atribudo a j e o valor de j = (k = 0) (que tambm zero) atribudo a i.

    Uma caracterstica muito peculiar de C que expresses de atribuio podem ser usados em qualquerlugar que um valor pode ser usado. Porm voc deve saber que us-lo dentro de outros comandos produzum efeito colateral que alterar o valor da varivel na memria. Portanto, a execuo de:

    int quadrado, n = 2;

    printf("Quadrado de %d eh menor que 50? %d \n", n, (quadrado = n * n) < 50);

    1Operadores lgicos && e || sero vistos na prxima aula.

    14

  • causa no apenas que o valor 4 seja impresso, como a avaliao da expresso relacional dentro do printf()faz com que o nmero 4 seja copiado para o endereo de memria associado com a varivel quadrado.Note que necessrio usar parnteses em quadrado = n * n j que = tem menor precedncia que ooperador relacional
  • 4 Ordem sequencial de execuo de sentenaso comando condicional: if and if - else

    A execuo de um programa C comea com a funo main(). Em todos os exemplos que vimos at estemomento, sentenas so executadas sequencialmente. A ordem sequencial de execuo de senteas podeser alterada se certas condies forem satisfeitas durante a execuo do programa. Isto chamado desviocondicional.

    Todas as linguagens de programao oferecem comandos para o desvio condicional. O mais simples asentea if. Em C , ele tem o formato:

    if (expressao)sentenca

    Quando uma sentena if encontrada em um programa,

    1. O teste na expressao em parnteses avaliada.

    2. Se o valor da expresso de teste for DIFERENTE de zero, a sentena que segue a expresso de teste executada.

    Figura 1: O comando if

    Considere o seguinte exemplo que converte uma frao digitada pelo usurio (numerador e denomina-dor) em decimal e imprime o resultado:

    #include

    main(void){

    int a, b;

    printf("Entre com uma fracao (numerador and denominador): ");scanf("%d %d", &a, &b);

    printf("A fracao em decimal eh %f\n", 1.0 * a / b);}

    No exemplo acima, escrevemos 1.0 * a / b, j que a e b so do tipo int, e portanto a / b umadiviso de inteiros e a parte fracional do resultado seria truncado, o que certamente no o que desejamos.

    16

  • Voce v algo errado neste programa ? Uma coisa a ser notada que se o usurio digitar um denominadorigual a 0, ns teremos um erro de execuo, j que o programa tentaria executar uma diviso por zero. Oque necessrio fazer testar se o denominador igual a zero e dividir s no caso dele for diferente de zero.Poderamos reescrever o programa acima da seguinte forma:

    Exemplo 1:

    #include

    main(void){

    int a, b;

    printf("Entre com uma fracao (numerador e denominador): ");scanf("%d %d", &a, &b);

    if (b != 0)printf("A fracao em decimal eh %f\n", 1.0 * a / b);

    }

    Exemplo 2: Programa que l dois nmeros e ordena o par caso o primeiro nmero digitado for maior queo segundo.

    #include

    main() {int num1, num2, aux;

    printf("Entre com dois numeros inteiros: ");scanf("%d %d", &num1, &num2);

    if (num1 > num2) {aux = num1;num1 = num2;num2 = aux;printf("Trocou \n");

    }

    printf("Os numeros ordenados: %d %d\n", num1, num2);

    }

    O programa do Exemplo 1 acima ficaria ainda melhor se ao invs de no fazer nada no caso do denomi-nador ser zero, imprimirmos uma mensagem de erro ao usurio, explicando o que h de errado.

    A sentena em C que permite fazermos isso o if - else. O formato do if-else :

    if (expressao)sentenca1

    elsesentenca2

    17

  • Figura 2: O comando if-else

    Primeiro, a expressao (que usualmente chamamos de condio) avaliada. Caso a condio seja ver-dadeira (o que equivalente a dizer que o valor diferente de zero), entao a sentenca1 executada. Casocontrrio, a sentenca2 executada.

    Note que uma sentena pode ser simples ou composta. Se voc quiser agrupar diversas sentenas paraserem executadas, voc pode coloc-las entre chaves ({ e }).

    Por hora, vamos continuar com nosso exemplo simples e torn-lo mais explicativo:

    Exemplo 3:

    #include

    main(void){

    int a, b;

    printf("Entre com uma fracao (numerador and denominador): ");scanf("%d %d", &a, &b);

    if (b != 0)printf("A fracao decimal e %f\n", 1.0 * a / b);

    elseprintf("Erro: denominador zero!\n");

    }

    Exemplo 4: Considere agora o exemplo j visto que pede que um usurio entre com um nmero e verifiquese o nmero par. Porm agora, queremos que o programa imprima o numero e par ou o numero eimpar.

    #include

    main(void){

    int num;

    18

  • /* obtem um numero do usuario */printf("Entre com um inteiro: ");scanf("%d", &num);

    /* imprime uma mensagem dizendo se o numero e par ou impar */if (num % 2 == 0)

    printf("O numero e par.\n");else

    printf("O numero e impar.\n");

    }

    4.1 Um erro comum

    muito frequente utilizar o operador relacional == em expresses condicionais da sentena if. Por exem-plo:

    int saldo = 2000;

    if (saldo == 1)printf("Voce esta quebrado! \n");

    elseprintf("Seu saldo e %d\n", saldo);

    Como a sentena saldo = 2000 inicializa o valor da varivel saldo com 2000, a expressosaldo == 1 tem valor 0. Portanto, a sentea que segue o else ser executada, e a mensagem

    Seu saldo e 2000

    ser impressa.Agora, suponha que, devido a um erro, voc tenha colocado = ao invs de ==:

    int saldo = 2000;

    if (saldo = 1)printf("Voce esta quebrado! \n");

    elseprintf("Seu saldo e %d\n", saldo);

    Agora, a expresso saldo = 1 tem valor 1. Portanto, a sentena que segue o if ser executada, ea mensagem

    Voce esta quebrado!

    ser impressa. Alm disso, a atribuio causar um efeito colateral, e alterar o valor de saldo para 1.Tal uso do operador de atribuio no ilegal, e no ser detectado pelo compilador como erro. Portanto,

    tome cuidado com o uso de atribuio no lugar de igualdade. Tal erro muito comum, e no fcil de achar.Como regra geral, NO utilize atribuies dentro de outras sentenas.

    19

  • 5 Aninhando senteas if e if-else

    Como era de se esperar, possvel colocar uma sentena condicional dentro de outra. Por exemplo, sequisermos imprimir uma mensagem apropriada caso um nmero seja positivo ou negativo e par ou mpar,ns poderamos escrever o seguinte:

    #include

    main(void){

    int num;

    /* Obtem um numero do usuario */printf("Entre com um inteiro: ");scanf("%d", &num);

    /* Imprime uma mensagem dizendo se o numero e positivo ounegativo, positivo ou negativo. */

    if (num >= 0) {if (num % 2 == 0)

    printf("O numero e par e positivo\n");else

    printf("O numero e impar e positivo\n");}else {if (num % 2 == 0)

    printf("O numero e par e negativo\n");else

    printf("O numero e impar e negativo\n");}

    }

    5.1 A ambigidade do else

    O aninhamento de sentenas if-else sem usar chaves ({ e }) para delimitar o bloco de senteas a serexecutado pode trazer efeitos indesejados.

    H uma regra simples para determinar qual if est associado a qual else.

    Regra de associao: Um else est associado com a ltima ocorrncia do if sem else.O exemplo seguinte est errado porque associa o else ao if "incorreto":

    #include

    main(void){

    int num;

    /* Obtem um numero do usuario */printf("Entre com o numero de peras: ");scanf("%d", &num);

    20

  • /* Imprime uma mensagem dizendo se o numero de peras e 0 ou 1(*** isto esta errado !! ***) */

    if (num != 0)if (num == 1)

    printf("Voce tem uma pera.\n");elseprintf("Voce nao tem nenhuma pera.\n");

    }

    Neste exemplo, o if tem o seguinte significado, segundo a regra de associao:

    #include

    main(void){int num;

    /* Obtem um numero do usuario */printf("Entre com o numero de peras: ");scanf("%d", &num);

    /* Como a sentenca if e vista pelo compilador */if (num != 0)

    if (num == 1)printf("Voce tem uma pera.\n");

    elseprintf("Voce nao tem nenhuma pera.\n");

    }

    Para evitar este problema, chaves ({ e }) devem ser usadas para tirar a ambiguidade. O exemplo abaixomostra como as chaves podem ser inseridas para corrigir o programa acima.

    #include

    main(void){

    int num;

    /* Obtem um numero do usuario */printf("Entre com o numero de peras: ");scanf("%d", &num);

    /* Como corrigir o problema (este programa funciona) */if (num != 0) {

    if (num == 1)printf("Voce tem uma pera.\n");

    } elseprintf("Voce nao tem nenhuma pera.\n");

    }

    Exerccio 1: Faa um programa que leia 3 nmeros e imprima o maior.21

  • #include

    main(void){

    int a, b, c, maior;

    printf("Entre com os tres numeros: ");scanf("%d %d %d", &a, &b, &c);

    if (a > b)maior = a;

    elsemaior = b;

    if (maior < c)maior = c;

    printf("O Maior numero eh %d\n", maior);

    }

    6 Operadores Lgicos

    Todos os programas at agora consideraram if com condies de teste simples. Alguns exemplos de testessimples: b != 0, contador = 0)if (num % 2 == 0)

    printf("Numero par nao negativo.\n");

    Com os operadores lgicos isso pode ser simplificado:

    if ((num>=0) && (num%2 == 0))printf("Numero par nao negativo.\n");

    A operao de negao, !, pode ser usado da seguinte forma:!expresso lgica: O valor a negao lgica da expresso dada. Por exemplo:

    22

  • !0 1!1 0

    Ns podemos usar o operador de negao lgica e escrever o exemplo acima como:

    if (num>0 && !(num%2))printf("Numero par nao negativo.\n");

    Os dois operadores binrios operam sobre duas expresses lgicas e tem o valor 1 (verdadeiro) or 0(falso). Os exemplos abaixo mostram o seu uso:

    a==0 && b==0 (verdadeiro se ambos a == 0 e b == 0, portanto se a e b so 0)a==0 || b==0 (verdadeiro se pelo menos uma das variveis a or b for 0)

    Uma expresso usando && verdadeira somente se ambos os operadores forem verdadeiros (nozero).

    Uma expresso usando || falsa somente se ambos os operadores forem falsos (zero).

    Verifique na Tabela 2 o resultado do uso de operadores lgicos:

    expr1 expr2 expr1 && expr2 expr1 || expr2verdadeiro verdadeiro verdadeiro verdadeiroverdadeiro falso falso verdadeirofalso verdadeiro falso verdadeirofalso falso falso falso

    Tabela 2: Resultado de uso de Operadores Lgicos

    A precedncia do operador de negao lgica a mais alta (no mesmo nvel que o - unrio). Aprecedncia dos operadores lgicos binrios menor que a dos operadores relacionais, e mais alta que aoperao de atribuio. O && tem precedncia mais alta que o ||, e ambos associam da esquerda para adireita (como os operadores aritmticos).

    Como a precedncia dos operadores lgicos menor que a dos operadores relacionais, no necessriousar parnteses em expresses como:

    x >= 3 && x

  • Operador Associatividade

    () esquerda para direita! - ++ -- (cast) & (unrios) direita para esquerda* / % esquerda para direita+ - esquerda para direita< >= esquerda para direita== != esquerda para direita&& esquerda para direita|| esquerda para direita= += -= *= /= %= direita para esquerda

    Tabela 3: Precedncia e associatividade de operadores

    #include

    main() {

    int lado1, lado2, lado3;int s1, s2, s3;

    printf(Entre com o tamanho dos lados do triangulo: );scanf(%d %d %d, &lado1, &lado2, &lado3);

    /* calcula o quadrado dos lados */s1 = lado1*lado1;s2 = lado2*lado2;s3 = lado3*lado3;

    /* testa a condicao para um triangulo reto */

    if ( lado1>0 && lado2>0 && lado3 > 0 ) {if (s1==s2+s3 || s2==s1+s2 || s2==s1+s3) ) {printf("Triangulo reto!\n");

    }else {

    printf("Nao pode ser um triangulo!\n");}

    }

    Na utilizao de expresses lgicas, as seguintes identidades so teis. Elas so chamadas de Lei deDeMorgan:

    !(x && y) equivalente a !x || !ye

    !(x || y) equivalente a !x && !y

    7 Exemplos

    7.1 IF - ELSE

    Assuma as seguintes declaraoes de variveis:

    24

  • int x = 4;int y = 8;

    O que impresso pelos seguintes programas ?

    1. if (y = 8)if (x = 5)

    printf( "a " );else

    printf( "b " );printf( "c " );printf( "d\n" );

    ==> a c d

    2. mude = para ==

    ==> b c d

    3. altere o programa acima para produzir a seguinte saida:

    Assuma x = 5 e y = 8(a) a(b) a d

    Assuma x = 5 e y = 7(a) b c d

    7.2 Operadores lgicos

    O que impresso pelas seguintes sentenas?

    1. Assuma x = 5 e y = 8.

    if (x == 5 && y == 8)printf( "a\n" );

    elseprintf( "b\n" ); ==> a

    2. Assuma x = 4 e y = 8.

    if (x == 5 || y == 8)printf( "a\n" );

    elseprintf( "b\n" ); ==> a

    if !(x == 5 || y == 8) /* equiv. (x != 5 && y != 8) */printf( "a\n" );

    elseprintf( "b\n" ); ==> b

    25

  • if !(x == 5 && y == 8) /* equiv. (x != 5 || y != 8) */printf( "a\n" );

    elseprintf( "b\n" ); ==> a

    3. Precedncia: ! > && > ||

    if (x == 5 || y == 8 && z == 10)

    equiv.

    if (x == 5 || (y == 8 && z == 10))

    8 A construo else-if

    Embora ela no seja um tipo diferente de sentena, a seguinte construo bastante comum para programardecises entre diversas alternativas:

    if (expressao1)sentenca1

    else if (expressao2)sentenca2

    else if (expressao3)sentenca3

    ...else if (expressaon1)

    sentencan1else

    sentencan

    As expresses lgicas so avaliadas em ordem, comeando com a expressao1. Se uma das expres-ses for verdadeira, a sentena associada ser executada. Se nenhuma for verdadeira, ento a sentena,sentencan, do ltimo else ser executada como opo default. Se a opo default no for necessria,ento a parte

    elsesentencan

    pode ser removida.

    26

  • Exemplo 9: O seguinte exemplo mostra um else-if de trs opes. O programa l dois nmeros e dizse eles so iguais ou se o primeiro nmero menor ou maior que o segundo.

    #include

    main(void){

    int num1, num2;

    /* obtem 2 numeros do usuario */printf("Entre um numero: ");scanf("%d", &num1);printf("Entre com um outro numero: ");scanf("%d", &num2);

    /* mostra a mensagem de comparacao */if (num1 == num2)

    printf("Os numeros sao iguais\n");else if (num1 < num2)

    printf("O primeiro numero e menor\n");else

    printf("O primeiro numero e maior\n");}

    No programa acima, se (num1 == num2) for verdadeiro, ento os nmeros so iguais. Seno, verificado se (num1 < num2). Se esta condio for verdadeira, ento o primeiro nmero menor. Seisso no for verdadeiro, ento a nica opo restante que o primeiro nmero maior.

    Exemplo 10: Este programa l um nmero, um operador e um segundo nmero e realiza a operaocorrespondente entre os operandos dados.

    #include

    main(void){

    float num1, num2;char op;

    /* obtem uma expressao do usuario */27

  • printf("Entre com numero operador numero\n");scanf("%f %c %f", &num1, &op, &num2);

    /* mostra o resultado da operacao */if (op == +)

    printf(" = %.2f", num1 + num2);else if (op == -)

    printf(" = %.2f", num1 - num2);else if (op == /)

    printf(" = %.2f", num1 / num2);else if (op == *)printf(" = %.2f", num1 * num2);

    elseprintf(" Operador invalido.");

    printf("\n");}

    Exemplos da execuo deste programa:

    Entre com numero operador numero:5 * 3.5= 17.50

    Entre com numero operador numero:10 + 0= 10.00

    Entre com numero operador numero:10 x 5.0Operador invalido.

    28

  • 9 A sentena switch

    A sentena switch outra maneira de fazer decises mltiplas. Ele pode ser usado para testar se uma dadaexpresso igual a um valor constante e, dependendo do valor, tomar determinadas aes.

    O formato da sentena switch :switch (expressao) {

    case expressao-constante 1:sentencas 1

    case expressao-constante 2:sentencas 2...

    default:sentencas n

    }

    A sentena switch primeiro avalia a expresso. Se o valor da expresso for igual a uma das expressesconstantes, as sentenas que seguem o case so executados. Se o valor da expresso no for igual anenhuma das constantes, as sentenas que seguem default so executadas.

    As sentenas que seguem o case so simplesmente uma lista de sentenas. Esta lista pode conter maisde uma sentena e no necessrio coloc-las entre chaves ({ e }). A lista de sentenas tambm pode servazia, isto , voc pode no colocar nenhuma sentena seguindo o case.

    Tambm no obrigatrio colocar o default. S o use quando for necessrio.Note no diagrama acima que TODAS as sentenas que seguem a constante com o valor igual ao da

    expresso sero executados. Para que se execute APENAS as sentenas que seguem o case que seja igualao valor da expresso precisamos usar a sentena break, que veremos em seguida.

    10 A sentena break

    O break faz com que todas as sentenas que o seguem dentro da mesma sentena switch sejam ignora-dos. Ou seja, colocando a sentena break no final de uma sentena case faz com que as sentenas queseguem os cases subsequentes no sejam executadas. Em geral, este o comportamento desejado quandose usa o switch, e cases sem o break no final so de pouca utilidade. Portanto, o uso de sentenascase sem o break devem ser evitados e quando utilizados devem ser comentados ao lado com algo como/* continua proxima sentenca - sem break */.

    Com a sentena break o diagrama de fluxo fica:29

  • Note a similaridade com o diagrama da sentena else-if e a diferena com o diagrama da sentenaswitch acima.

    O prximo programa tem a mesma funo de calculadora do programa anterior, porm utilizando asentena switch.

    Exemplo 11:

    #include

    main(void){

    float num1, num2;char op;

    printf("Entre com numero operador numero:\n");scanf("%f %c %f", &num1, &op, &num2);

    switch (op) {case +:

    printf(" = %.2f", num1 + num2);break;

    case -:printf(" = %.2f", num1 - num2);break;

    case *:printf(" = %.2f", num1 * num2);break;

    case /:printf(" = %.2f", num1 / num2);break;

    default:printf(" Operador invalido.");break;

    }printf("\n");

    30

  • }Como mencionado anteriormente, possvel no colocar nenhuma sentena seguindo um case. Isso til quando diversas sentenas case (diversas constantes) tm a mesma ao.

    Por exemplo, podemos modificar o programa acima para aceitar x e X para multiplicao e \ paradiviso. O programa fica ento:

    #include

    main(void){

    float num1, num2;char op;

    printf("Entre com numero operador numero:\n");scanf("%f %c %f", &num1, &op, &num2);

    switch (op) {case +:

    printf(" = %.2f", num1 + num2);break;

    case -:printf(" = %.2f", num1 - num2);break;

    case *:case x:case X:printf(" = %.2f", num1 * num2);break;

    case /:case \\:

    printf(" = %.2f", num1 / num2);break;

    default:printf(" Operador invalido.");break;

    }printf("\n");

    }

    Exerccio 2: Ler mes e ano e imprimir o numero de dias do mes no ano digitado.

    #include

    main() {int mes, ano, numDias;

    printf("Entre com mes e ano (mm aa):");scanf( "%d %d", &mes, &ano);if( mes < 1 || mes > 12 || ano < 0 || ano > 99 )

    printf("mes ou ano invalido\n");

    31

  • else {switch( mes ){case 1:case 3:case 5:case 7:case 8:case 10:case 12:

    numDias = 31;break;

    case 2:if( ano % 4 == 0 )

    numDias = 29;else

    numDias = 28;break;

    default:numDias = 30;

    }printf("%2d/%2d tem %d dias\n", mes, ano, numDias);

    }}

    32

  • 11 Funes

    11.1 Funes: o que so e por que us-las

    Quando queremos resolver um problema, em geral tentamos dividi-lo em subproblemas mais simples e re-lativamente independentes, e resolvemos os problemas mais simples um a um. A linguagem C dispe deconstrues (abstraes) que auxiliam o projeto de programas de maneira top-down. Uma funo cria umamaneira conveniente de encapsular alguns detalhes de processamento, ou seja, como algum resultado ob-tido. Quando esta computao necessria, a funo chamada, ou invocada. Desta forma, quando umafuno chamada o usurio no precisa se preocupar como a computao realizada. importante sabero que a funo faz (qual o resultado da execuo de uma funo) e tambm como se usa a funo. Criandofunes, um programa C pode ser estruturado em partes relativamente independentes que correspondem assubdivises do problema.

    Voc j viu algumas funes: printf(), scanf(), getchar(), sqrt(). Elas so funesde uma biblioteca padro (do C ). Voc no sabe como elas foram escritas, mas j viu como utiliz-las. Ouseja, voc sabe o nome das funes e quais informaes especficas voc deve fornecer a elas (valores quedevem ser passados para as funes) para que a funo produza os resultados esperados.

    Quando nos referirmos a uma funo neste texto usaremos a maneira frequentemente utilizada que onome da funo seguido de ().

    Tomemos como exemplo o programa abaixo, que calcula o produto de 2 nmeros inteiros positivosapenas se ambos forem primos:

    /*----------------------------------------------------------------------Verifica se 2 Numeros sao primos e multiplica um pelo outro se o forem----------------------------------------------------------------------

    */

    #include

    int main(){

    int n1, n2, j;int prod = 0;

    printf("\nEntre com 2 numeros inteiros: ");scanf ("%d %d", &n1, &n2);

    /* Se for indicado 1, 0 ou negativo, nao sao primos */if ( n1 >= 2 && n2 >= 2) {

    /* Testa se n1 primo */j = n1 - 1;while ((j > 1) && (n1 % j != 0)){

    j = j - 1;}

    if( j == 1) { /* n1 eh primo *//* Testa se n2 primo */j = n2 - 1;

    33

  • while ((j > 1) && (n2 % j != 0)){j = j - 1;

    }

    if( j == 1) /* n2 eh primo */prod = n1 * n2;

    }}

    if (prod)printf("PRODUTO = %d\n", prod);

    }

    Observe que o cdigo que verifica se um nmero primo teve que ser reproduzido dentro do programapor duas vezes (para testar se os nmeros fornecidos pelo usurio eram primos).

    Um dos benefcios mais bvios de usar funes que podemos evitar repetio de cdigo. Em outraspalavras, se voc quiser executar uma operao mais de uma vez, voc pode simplesmente escrever a funouma vez e utiliz-la diversas vezes ao invs de escrever o mesmo cdigo vrias vezes. Outro benefcio quese voc desejar alterar ou corrigir alguma coisa mais tarde, mais fcil alterar em um nico lugar.

    O exemplo acima poderia ser simplificado pela criao de uma funo chamada ehPrimo, que dadoum nmero n, d como resultado 1 se este nmero primo, ou 0 (zero) se o nmero no primo:

    int ehPrimo(int n){

    int j;

    j = n - 1;while ((j > 1) && (n % j != 0)){

    j = j - 1;}

    if (j == 1)return 1;

    elsereturn 0;

    }

    O exemplo pode ser ento alterado e simplificado com o uso da funo ehPrimo():

    /*----------------------------------------------------------------------Verifica se 2 Numeros sao primos e multiplica um pelo outro se o forem----------------------------------------------------------------------

    */

    #include

    34

  • int ehPrimo(int n){

    int j;

    j = n - 1;while ((j > 1) && (n % j != 0)){

    j = j - 1;}

    if (j == 1)return 1;

    elsereturn 0;

    }

    main(){

    int n1, n2, j;int prod = 0, ep1, ep2;

    printf("\nEntre com 2 numeros inteiros: ");scanf ("%d %d", &n1, &n2);

    /* Se for indicado 1, 0 ou negativo, nao sao primos */if ( n1 >= 2 && n2 >= 2) {

    ep1 = ehPrimo(n1); /* Verifica se n1 eh primo */ep2 = ehPrimo(n2); /* Verifica se n2 eh primo */

    if (ep1 != 0 && ep2 != 0)prod = n1 * n2;

    }

    if (prod)printf("PRODUTO = %d\n", prod);

    }

    Como pode ser observado, sejam quais forem os 2 nmeros fornecidos, no precisa escrever um cdigosimilar ao mostrado na funo ehPrimo acima para cada nmero.Basta chamar a funo ehPrimo(),passar os valores necessrios para verificar a primalidade de cada nmero, e utilizar os resultados.

    Evitar repetio de cdigo a razo histrica que funes foram inventadas (tambm chamado de proce-dimento ou subrotinas em outras linguagens de programao). A maior motivao para utilizar funes naslinguagens contemporneas a reduo da complexidade do programa e melhoria da modularidade do pro-grama. Dividindo o programa em funes, muito mais fcil projetar, entender e modificar um programa.Por exemplo, obter a entrada do programa, realizar as computaes necessrias e apresentar o resultado aousurio pode ser implementado como diferentes funes chamadas por main() nesta ordem.

    Funes podem ser escritas independentemente uma da outra. Isto significa que, em geral, variveisusadas dentro de funes no so compartilhadas pelas outras funes. Assim sendo, o comportamento da

    35

  • funo previsvel. Se no for assim, duas funes completamente no relacionadas podem alterar os dadosuma da outra. Se as variveis so locais a uma funo, programas grandes passam a ser mais fceis de seremescritos. A comunicao entre funes passa a ser controlada elas se comunicam somente atravs pelosvalores passados as funes e os valores retornados.

    11.2 Definindo funes

    Um programa C consiste de uma ou mais definies de funes (e variveis). H sempre uma funochamada main. Outras funes tambm podem ser definidas. Cada uma pode ser definida separadamente,mas nenhuma funo pode ser definida dentro de outra funo. Abaixo, mostramos um exemplo simplesde um programa que consiste de duas funes: main() e alo(). Quando executado, este programaimprimir a mensage Alo! trs vezes.

    #include

    /* declaracao (prottipo) da funcao alo() */void alo(void);

    /* definicao da funcao main() */main(){

    int i;

    i = 1;while (i

  • chamado de void, e esta palavra escrita no cabealho na frente do nome da funo. Se a funo no tiverargumentos formais, a palavra void escrita no lugar da lista de argumentos formais entre os parnteses.Para simplificar a exposio, falaremos sobre o tipo do retorno e os argumentos formais mais tarde. Elesservem para permitir que as funes troquem informaes entre si.

    11.3 Funes simples

    Para comear, vamos utilizar funes na seguinte forma:

    void nome-da-funo(void){

    declaraes e senteas (corpo da funo)}

    O primeiro void significa que esta funo no tem tipo de retorno (no retorna um valor), e o segundosignifica que a funo no tem argumentos (ela no precisa de nenhuma informao externa para ser exe-cutada). Isso no significa que a funo no faz nada. Ela pode realizar alguma ao, como imprimir umamensagem. O exemplo abaixo mostra um programa que usa uma funo como essa:

    void alo(void);

    main(){

    alo();}

    void alo(void){

    printf("Alo.\n");}

    Neste exemplo, o programa consiste de duas funes, main() e alo(). A ordem em que as funesso definidas no importante, desde que prottipos de funes so usadas. A linha

    void alo(void);

    no topo do programa um prottipo de funo para a funo alo(). Um prottipo usado para declararuma funo. Um prottipo passa ao compilador informaes sobre uma funo que definida dentro deum programa em algum lugar. Prottipos so sempre colocados prximo ao incio do programa, antes docomeo da definio de funes.

    A funo alo() imprime a mensagem Alo. quando chamada. A sentena printf() o corpoda funo. Dentro da funo main() h uma chamada a funo alo(). A funo chamada pelo seunome seguido de () (j que a funo alo no tem argumentos, nenhuma expresso escrita dentro dosparnteses). A funo alo() no retorna um valor, ela chamada simplesmente para realizar uma ao(imprimir a mensagem). A chamada de funo uma sentena vlida em C , portanto deve ser terminadapor ponto e vrgula (;).

    alo();

    Outra coisa que voc deve ter notado que main() tambm uma funo. A funo main() no difereem nada das demais funes, com a exceo de que contm o programa principal. Alm disso, no necessrio declarar o prottipo da funo main().

    37

  • 11.3.1 Argumentos

    Nosso prximo exemplo pede que o usurio digite suas iniciais, e ento chama a funo cumprimenta()para imprimir a mensagem Ola junto com as iniciais digitadas. Estas iniciais (seus valores) so passadaspara a funo cumprimenta(). A funo cumprimenta() definida de forma que ela imprimir amensagem incluindo quaisquer iniciais passadas.

    #include

    void cumprimenta(char, char);

    int main(){

    char primeiro, segundo;

    printf("Entre com duas iniciais (sem separacao): ");primeiro = getchar();segundo = getchar();cumprimenta(primeiro, segundo);

    }

    void cumprimenta(char inic1, char inic2){

    printf("Ola, %c%c!\n",inic1,inic2);}

    A funo main() chama a funo cumprimenta(); main() passa para cumprimenta() osvalores dos dois caracteres para serem impressos. Veja um exemplo de execuo do programa:

    Entre com duas iniciais (sem separacao): YKAlo, YK!

    Note que h uma correspondncia entre o nmero e tipo dos valores que main() passa (estes so chamadosde parmetros reais ou argumentos reais) e os argumentos listados no cabealho da funo cumprimenta().

    11.4 Funes que retornam um valor

    Funes que no retornam nenhum valor (como alo(), main()) possuem tipo void.Alm de executarem aes (como imprimir) uma funo tambm pode retornar um valor para o pro-

    grama que o chamou. Uma funo que retorna um valor tem no cabealho o nome do tipo do resultado. Ovalor retornado pode ser de qualquer tipo, incluindo int, float e char ( claro que uma vez definida,a funo s de um tipo especfico). Uma funo que retorna um tipo diferente de void executa algunsclculos, e retorna o resultado (que um nico valor) para quem a chamou. A funo chamadora pode entousar o resultado. Para retornar um valor para a funo chamadora, a funo usa a sentena return.

    O formato da sentena return a seguinte:

    return expresso;

    A expresso avaliada e o seu valor convertido ao tipo de retorno da funo (o tipo da funo dadono cabealho da funo antes do nome da funo).

    Considere o seguinte exemplo. O programa consiste de duas funes: main() e quadrado. Oprograma pede que o usurio digite trs nmeros e verifica se eles podem ser os lados de um tringulo reto.

    38

  • /* programa que verifica se 3 numeros podem ser os lados de um

    * triangulo reto.

    */#include

    int quadrado(int);

    int main(){

    int s1, s2, s3;

    printf("Entre tres inteiros: ");scanf("%d %d %d", &s1, &s2, &s3);

    if ( s1 > 0 && s2 > 0 && s3 > 0 &&(quadrado(s1) + quadrado(s2) == quadrado(s3) ||quadrado(s2) + quadrado(s3) == quadrado(s1) ||quadrado(s3) + quadrado(s1) == quadrado(s2)) )

    printf(" %d %d %d podem formar um triangulo reto\n", s1, s2, s3);else

    printf(" %d %d %d nao podem formar um triangulo reto\n",s1, s2, s3);}

    /* funcao que calcula o quadrado de um numero */int quadrado(int n)

    {return n * n;

    }

    Note que quando chamamos a funo quadrado() passamos o valor no qual desejamos executar oclculo, e tambm usamos o valor retornado pela funo em expresses. O valor de quadrado(s1) ovalor que a funo quadrado() retorna quando chamado com o valor do argumento sendo igual ao valorda varivel s1.

    Os valores retornados pelas chamadas de funes podem ser usados em todos os lugares valores podemser usados. Por exemplo,

    y = quadrado(3);Aqui quadrado(3) tem o valor 9, portanto 9 pode ser atribudo a varivel y;

    x = quadrado(3) + quadrado(4);atribuir 25 a varivel x, e

    area = quadrado(tamanho);atribuir a varivel area o valor da varivel tamanho elevado ao quadrado.

    O prximo exemplo tem uma funo chamada cinco:

    int cinco(void);

    main(){

    printf("cinco = %d\n", cinco() );}

    39

  • int cinco(void){

    return 5;}

    A sada do programa sercinco = 5

    porque o valor de cinco() dentro da sentena printf() 5. Olhando na sentena return, 5 aexpresso retornada para o chamador.

    Outro exemplo:

    int obtem_valor(void);

    main(){

    int a, b;

    a = obtem_valor();b = obtem_valor();

    printf("soma = %d\n", a + b);}

    int obtem_valor(void){

    int valor;

    printf("Entre um valor: ");scanf("%d", &valor);

    return valor;}

    Este programa obtm dois inteiros do usurio e mostra a sua soma. Ele usa a funo obtem valor()que mostra uma mensagem e obtm o valor do usurio.

    Um exemplo de sada deste programa :

    Entre um valor: 15Entre um valor: 4soma = 19

    11.5 Mais sobre o return

    Quando uma funo return executada, a funo imediatamente acaba mesmo que haja cdigo nafuno aps a sentena return. A execuo do programa continua aps o ponto no qual a chamada defuno foi feita. Sentenas return podem ocorrer em qualquer lugar na funo no somente no final.Tambm vlido ter mais de um return dentro de uma funo. A nica limitao que return retornaum nico valor.

    O seguinte exemplo mostra uma funo (uma verso para int da funo obtem valor) que pedepara usurio um valor e se o usurio digitar um valor negativo, imprime uma mensagem e retorna um valorpositivo.

    40

  • int obtem_valor_positivo(void){

    int valor;

    printf("Entre um valor: ");scanf("%d", &valor);

    if (valor >= 0)return valor;

    printf("Tornando o valor positivo...\n");

    return -valor;}

    Em uma funo void, return; (s com ;) pode ser usado para sair de uma funo. O exemploseguinte, pede instrues ao usurio. Se o usurio reponder nao, a funo termina. Do contrrio, eleimprime as instrues e depois termina.

    void instrucoes(void){

    int ch;

    printf("Voce quer instrucos? (s/n): ");ch = getchar();

    /* Termina se resposta for n */if (ch == n || ch == N)

    return;

    /* Mostra instrucoes */printf("As regras do jogo sao . . . ");

    .

    .

    .return;

    }

    O return final (antes de fechar as chaves do corpo da funo) na funo opcional. Se omitido, afuno atingir o final da funo e retornar automaticamente. Note que o return opcional somente parafunes void.

    11.6 Mais sobre Argumentos

    A comunicao entre uma funo e o chamador pode ser nas duas direes. Argumentos podem ser usadospelo chamador para passar dados para a funo. A lista de argumentos definida pelo cabealho da funoentre parnteses.. Para cada argumento voc precisa especificar o tipo do argumento e o nome do argumento.Se houver mais de um argumento, eles so separados por vrgula. Funes que no possuem argumentostem void como lista de argumento. No corpo da funo os argumentos (tambm chamados de argumentosformais ou parmetros formais) so tratados como variveis. erro defini-los dentro do corpo da funoporque eles j esto definidos no cabealho. Antes da execuo da funo os valores passados pelo chamadorso atribudos aos argumentos da funo.

    41

  • Considere o seguinte programa com a funo abs() que calcula o valor absoluto de um nmero.

    int abs(int);

    main(){

    int n;

    printf("Entre um numero: ");scanf("%d", &n);

    printf("Valor absoluto de %d e %d", n, abs(n));}

    /* Definicao da funcao abs */int abs(int x){

    if (x < 0)x = -x;

    return x;}

    A funo abs() tem um argumento do tipo int, e seu nome x. Dentro da funo, x usado comouma varivel x.

    Uma vez que abs() tem um nico argumento, quando ela chamada, h sempre um valor dentro doparnteses, como em abs(n). O valor de n passado para a funo abs(), e antes da execuo da funo,o valor de n atribudo a x.

    Aqui est um exemplo de uma funo que converte uma temperatura de Farenheit para Celsius:

    float fahr_para_cels(float f){

    return 5.0 / 9.0 * (f - 32.0);}

    Como voc pode ver, esta funo tem somente um argumento do tipo float. Um exemplo de chamadadesta funo poderia ser:

    fervura = fahr_para_cels(212.0);O resultado da funo fahr para cels(212.0) atribudo a fervura. Portanto, depois da

    execuo desta sentena, o valor de fervura (que do tipo float) ser 100.0.O exemplo seguinte possui mais de um argumento:

    float area(float largura, float altura){

    return largura * altura;}

    Esta funo possui dois argumentos do tipo float. Para chamar uma funo com mais de um argumento,os argumentos devem ser separados por vrgula. A ordem em que os argumentos so passados deve ser namesma em que so definidos. Neste exemplo, o primeiro valor passado ser a largura e o segundo a altura.Um exemplo de chamada seria

    tamanho = area(14.0, 21.5);Depois desta sentena, o valor de tamanho (que do tipo float) ser 301.0.

    42

  • Quando passar os argumentos, importante ter certeza de pass-los na ordem correta e que eles so dotipo correto. Se isso no for observado, pode ocorrer erro ou aviso de compilao, ou resultados incorretospodem ser gerados.

    Uma ltima observao. Os argumentos que so passados pelo chamador podem ser expresses em gerale no somente constantes e varivies. Quando a funo chamada durante a execuo do programa, estasexpresses so avaliadas, e o valor resultante passado para a funo chamada.

    11.7 Chamada por valor

    Considere novamente a funo quadrado(). Se esta funo chamada de main() como

    p = quadrado(x);

    somente o valor (no o endereo) de x passado para quadrado. Por exemplo, se a varivel tem valor5, para a funo quadrado(), quadrado(x) ou quadrado(5) so o mesmo. De qualquer forma,quadrado() receber somente o valor 5. quadrado() no sabe se na chamada da funo o 5 era umaconstante inteira, o valor de uma varivel do tipon int, ou alguma expresso como 625/25 - 4 * 5.Quando quadrado() chamado, no interessa qual a expresso entre parnteses, ela ser avaliada e ovalor passado para quadrado().

    Esta maneira de passar argumentos chamada de chamada por valor. Argumentos em C so passadospor valor. Portanto, a funo chamada no pode alterar o valor da varivel passada pelo chamador comoargumento, porque ela no sabe em que endereo de memria o valor da varivel est armazenado.

    11.8 Variveis locais

    Como voc provavelmente j reparou em alguns exemplos, possvel definir variveis dentro de funes, damesma forma que temos definido variveis dentro da funo main(). A declarao de variveis feita noincio da funo.

    Estas variveis so restritas a funo dentro da qual elas so definidas. S esta funo pode enxergarsuas prprias variveis. Por exemplo:

    void obtem_int(void);

    main(){

    obtem_int();

    /* **** Isto esta errado **** */printf("Voce digitou %d\n", x);

    }

    void obtem_int(void){

    int x;

    printf("Entre um valor: ");scanf("%d", &x);

    printf("Obrigado!\n");

    43

  • }A funo main() usou um nome x, mas x no definido dentro de main; ele uma varivel local aget int(), no a main(). Este programa gera erro de compilao.

    Note que possvel ter duas funes que usam variveis locais com o mesmo nome. Cada uma delas restrita a funo que a define e no h conflito. Analise o seguinte programa (ele est correto):

    int obtem_novo_int(void);

    main(){

    int x;

    x = obtem_novo_int();

    /* ****Isto nao esta errado !! **** */printf("Voce digitou %d\n", x);

    }

    int obtem_novo_int(void){

    int x;

    printf("Entre um valor: ");scanf("%d", &x);

    printf("Obrigado!\n");return x;

    }

    A funo obtem novo int() usa uma varivel local chamada x para armazenar o valor digitado eretorna como resultado o valor de x. main() usa outra varivel local, tambm chamada de x para recebero resultado retornado por obtem novo int(). Cada funo tem sua prpria varivel x.

    11.9 Prottipos

    Os prottipos servem para dar ao compilador informaes sobre as funes. Isso para que voc possa chamarfunes antes que o compilador tenha a definio (completa) das funes. O prottipo de uma funo idntico ao cabealho da funo, mas o nome dos argumentos podem ser omitidos e ele terminado comuma vrgula. Prottipos declaram uma funo ao invs de defini-las. O formato dos prottipos :

    tipo-de-retorno nome-da-funo(lista-dos-tipos-dos-argumentos);

    Definindo prottipos, voc no precisa se preocupar com a ordem em que define as funes dentro doprograma. A principal vantagem de definir prottipos que erros de chamada de funes (como chamaruma funo com o nmero incorreto de argumentos, ou com argumentos de tipo errado) so detectados pelocompilador. Sem prottipos, o compilador s saberia que h erro depois de encontrar a definio da funo.Em verses antigas do compilador C , programas com tais erros compilariam sem erros, o que tornava adepurao de erros mais difcil.

    Abaixo, mostramos duas funes e seus prottipos:

    float volume(float, float, float);44

  • float dinheiro(int, int, int, int);

    float volume(float comprimento, float largura, float altura){

    return comprimento * largura * altura;}

    float dinheiro(int c25, int c10, int c5, int c1){

    return c25 * 0.25 + c10 * 0.10 +c5 * 0.05 + c1 * 0.01;

    }

    11.10 Documentao de funes

    Voc deve documentar as funes que escreve. Na documentao voc deve especificar as seguintes infor-maes:

    Ao o que a funo faz

    Entrada descrio dos argumentos passados para a funo

    Sada descrio do valor retornado pela funo

    Suposies o que voc assume ser verdade para que a funo funcione apropriadamente

    Algoritmo como o problema resolvido (mtodo)

    Estas informaes devem ser colocadas como comentrio antes da definio da funo.

    11.11 Comentrios

    Voc pode colocar comentrios no seu programa para documentar o que est fazendo. O compilador ignoracompletamente o que quer esteja dentro de um comentrio.

    Comentrios em C comeam com um /* e terminam com um */. Alguns exemplos:

    /* Este e um comentario sem graca */

    /* Este eum comentarioque usadiversas linhas

    */

    /* Este e

    * um comentario

    * de diversas linhas

    * mais bonito

    */

    45

  • Note que no podemos aninhar comentrios dentro de comentrios. Um comentrio termina no primeiro*/ que encontrar. O comentrio abaixo ilegal:

    /* Este e um comentario /* illegal */ ilegal */

    Regras para comentrio sempre uma boa idia colocar comentrios em seu programa das coisas que no so claras. Isto vai

    ajudar quando mais tarde voc olhar o programa que escreveu j h algum tempo ou vai ajudar a entenderprogramas escritos por outra pessoa.

    Um exemplo de comentrio til:

    /* converte temperatura de farenheit para celsius */celsius = (fahrenheit - 32) * 5.0 / 9.0;

    O comentrio deve ser escrito em portugus e no em C . No exemplo abaixo

    /* usando scanf, obter valor de idade e multiplicar por 365 para

    * obter dias */scanf("%d", &idade);dias = idade * 365;

    o comentrio basicamente uma transcrio do cdigo do programa. Em seu lugar, um comentriocomo

    /* obtem idade e transforma em numero de dias */

    seria mais informativo neste ponto. Ou seja, voc deve comentar o cdigo, e no codificar o comentrio.

    Voc tambm deve evitar comentrios inteis. Por exemplo:

    /* Incrementa i */i++;

    No h necessidade de comentrios j que i++ j auto explicativo.

    E abaixo est um exemplo de como voc deve comentar uma funo.

    /* funcao instrucoes()

    * acao: mostra instrucoes do programa

    * entrada: nenhuma

    * saida: nenhuma

    * suposicoes: nenhuma

    * algoritmo: imprime as instrucoes

    */void instrucoes(void){

    /* mostra instrucoes */printf("O processo de purificacao do Uranio-235 e . . . ");

    .

    .}

    46

  • 12 O pr-processador

    O pr-processador um programa que faz alguns processamentos simples antes do compilador. Ele exe-cutado automaticamente todas as vezes que seu programa compilado, e os comandos a serem executadosso dados atravs de diretivas do pr-processador.

    Estas diretivas so colocadas em linhas que contm somente a diretiva (elas no so cdigo da linguagemC , portanto as regras para elas so um pouco diferentes). As linhas que comeam com um # so comandospara o pr-processador. A linha inteira reservada para este comando (nenhum cdigo C pode aparecernesta linha e comandos do pr-processador no podem estar separados em diversas linhas).

    12.1 A diretiva #define

    Uma diretiva que usada frequentemente o #define. Esta diretiva usada para fazer substituiode macros. Por enquanto, mostraremos uma utilizao simples do #define, que simplestemente umasubstituio no texto.

    O uso mais frequente desta diretiva dar nomes simblicos a uma constante (voc j viu outra maneirade definir contantes que colocar a palvavra const antes da definio de uma varivel). Por exemplo,seria conveniente usar PI em seus programas ao invs de digitar 3.1415926535 toda hora. Como outroexemplo, se voc quiser escrever um programa sobre estudantes de uma turma de 81 alunos, voc poderiadefinir NUM_ALUNOS como 81. Assim, se o nmero de alunos mudar, voc no precisaria modificar todoo seu programa onde o nmero de alunos (81) utilizado, mas simplesmente alterar a diretiva #define.Estas duas diretivas so definidas da seguinte forma:

    #define PI 3.1415926535#define NUM_ALUNOS 81

    Por conveno, nomes introduzidos por um #define so geralmente em letra maiscula (e variveisso em letra minscula, ou uma mistura de letras minsculas e maisculas). Assim, quando voc v um nomeem um programa, voc sabe se o nome refere-se a uma varivel ou um nome definido por um #define.

    Considere o seguinte programa exemplo que usa PI:

    #define PI 3.14159265

    int main(){

    double raio;

    printf("Entre com o raio: ");scanf("%f", &raio);

    printf("Circunferencia = %f\n", 2.0 * PI * raio);}

    Lembre-se que o nome PI no um nome de varivel. Ele um nome que o pr-processador substituirpelo texto especificado pelo #define (mais ou menos da mesma forma que o comando pesquisa-e-substituido editor de texto). O compilador nunca v ou sabe sobre PI. O compilador v o seguinte printf() doprograma acima depois do pr-processador ser executado:

    printf("Circunferencia = %f\n", 2.0 * 3.14159265 * raio);

    12.2 A diretiva #include

    Agora imagine que estamos escrevendo uma biblioteca geomtrica: um conjunto de funes para calculara rea de cilindros, cones, esferas. Se diferentes pessoal esto escrevendo cada uma das funes, eles

    47

  • provavelmente colocaro suas funes em diferentes arquivos. Mas todas as funes usam o numero pi, ealgumas outras constantes podem ser necessrias tambm. Ao invs de colocar o #define no incio decada arquivo, um nico arquivo geom.h pode ser criado. Este arquivo conter a linha

    #define PI 3.14159265Assim, se todos os arquivos de funes geomtricas puderem enxergar geom.h, eles compartilharo asmesmas definies. para isso que usamos a diretiva #include, para incluir em seu programa, informa-es que esto em outro arquivo. Estas diretivas geralmente esto no incio do programa fonte, antes dadefinio de funes e varveis. Por exemplo, a diretiva

    #include "geom.h"colocada nos arquivos fontes que contm as funes geomtricas far com que todos eles usem o nomesimblico PI ao invs de 3.14159265. O fato do nome do arquivo estar em aspas significa que o ar-quivo geom.h est no mesmo diretrio que os arquivos fontes (ao invs do diretrio onde se encontram asbibliotecas padro de C ).

    A diretiva#include

    colocada no incio do programa fonte para incluir informaes (como prottipos de funes) que sonecessrios quando printf() e scanf() so chamados dentro do programa. O arquivo entre < > estem algum diretrio padro conhecido pelo pr-processador. Este arquivo stdio.h comum a todas asimplementaes da linguagem C e contm infomaes necessrias para executar operaes de entrada esada da entrada e sada padro (teclado e monitor).

    A extenso .h vem do ingls header file. Apesar de no ser obrigatrio que arquivos includos tenhama extenso .h, geralmente esta a conveno utilizada.

    12.3 Comentrios

    De um modo geral, o pr-processador dos compiladores existentes remove todos os comentrios do arquivofonte antes do programa ser compilado. Portanto, o compilador nunca v realmente os comentrios.

    13 Mais sobre funes

    A nfase aqui ser em como funes funcionam. O que acontece quando uma funo chamada ? A quevarivel um nome est se referenciando?

    O tratamento em tempo de execuo de um nome de varivel em C simples: um nome de varivel ouuma varivel local (a funo) ou uma varivel global (definida fora de qualquer funo).

    Em C , todas as funes tem que ser definidas. Para cada funo deve ser definido um prottipo. Oprottipo escrito fora de qualquer funo. Desta forma, nomes de funes so visveis para todas as outrasfunes que podem ento invoc-las. A funo main() especial: onde a execuo do programa comea,e o prottipo de main() pode ser omitido.

    Uma definio de funo consiste de quatro partes:

    1. o nome da funo;

    2. a lista de parmetros formais (argumentos) com seus nomes e tipos. Se no houver argumentos, apalavra void escrita entre os parnteses.

    3. o tipo do resultado que a funo retorna atravs da sentena return ou void se a funo no retornanenhum valor. Lembre-se que somente um valor pode ser retornado por uma sentena return.

    4. o corpo da funo, que uma sentena composta (comea e termina com chaves ({ }) contendodefinio de variveis e outras sentenas. Em C , no se pode definir uma funo dentro de outra.

    48

  • Para funes com argumentos: uma funo chamada dando o seu nome e uma lista de argumentos(expresses que so avaliadas e cujos valores so atribudos para os correspondentes parmetros formais dafuno).

    Por exemplo, suponha que triang area() e circ area() sejam funes que calculam a rea detringulos e crculos, respectivamente. Seus prottipos so:

    float triang_area(float , float);float circ_area(float);

    Estas funes podem chamadas de dentro de outras funes. Os argumentos reais com os quais elas sochamadas podem ser expresses constantes, or variveis locais, ou qualquer expresso cuja avaliao resulteem valores do tipo float (inteiros so convertidos para float da mesma forma que ocorre com atribuiode inteiros para variveis do tipo float). Alguns exemplos de chamadas:

    float area2, area3, area4, area5, base, altura, raio;

    printf("area do triangulo = ", triang_area(0.03, 1.25));base = 0.03;altura = 1.25;area2 = triang_area(base, altura);area3 = triang_area(1.6, altura);area4 = triang_area( 0.03 + base, 2 * altura);raio = base + altura;area5 = triang_area(raio, circ_area(raio));

    A ltima sentena do exemplo acima atribui a varivel area5 a rea de um tringulo cuja base igualao valor da varivel raio e a altura igual a area de um crculo de raio igual ao valor da varivel raio.

    Quando um programa executado, somente uma nica funo tem o controle em determinado momento.Falaremos mais sobre o que acontece quando uma funo chamada mais tarde nestas notas de aula.

    Variveis Locais Variveis que so definidas dentro de uma funo so variveis locais desta funo.Parmetros formais de uma funo so variveis locais da funo. Variveis locais so privativas afuno na qual so definidas. Somente esta funo pode enxerg-las (ela conhece o endereo das variveis epode usar e modificar o seu contedo). Nenhuma outra funo pode acessar variveis locais de outra funosem permisso (uma funo pode acessar variveis locais de outra se esta passar o endereo da varivellocal como argumento este assunto ser tratado em notas de aula futuras). O fato de cada funo mantervariveis locais escondidas do resto do mundo torna mais fcil a tarefa de escrever programas estruturadose modulares. Quando voc est escrevendo uma funo, voc pode dar as suas variveis locais o nome quequiser. Voc tambm no precisa se preocupar se outra pessoa escrevendo outra funo ter acesso ou alteravariveis locais a sua funo.

    Variveis locais que so definidas dentro da funo devem ser inicializadas com algum valor antesde serem usadas. Caso contrrio, o seu valor indefinido.

    J que parmetros formais (argumentos) so variveis locais da funo, eles podem ser usados no corpoda funo. Eles no devem ser definidos dentro da funo (sua definio j est no cabealho da funo). Osparmetros formais no precisam ser inicializados. Seus valores so fornecidos pelo chamador da funoatravs dos argumentos reais.

    Considere o seguinte exemplo:

    /****************************************************************** Um programa que calcula a area de triangulos e circulos.

    * A base, altura e raio sao fornecidos pelo usuario.49

  • * A saida do programa e a area do triangulo e circulo.

    *****************************************************************/

    #include

    #define PI 3.1415

    /*******************prototipos

    *******************/float triang_area(float, float);float circ_area(float);

    /*******************definicao de funcoes

    *******************/

    main(void){

    /* definicao das variaveis locais */float base, altura, raio;

    /* dialogo de entrada */printf("\nEntre com a base e altura do triangulo: ");scanf("%f %f", &base, &altura);printf("\nEntre com o raio do circulo: ");scanf("%f", &raio);

    /* chama as funcoes e imprime o resultado */printf("Area do triagulo com base e altura %f e %f = %f\n",

    base, altura, triang_area(base, altura));printf("Area do circulo com raio %f = %f\n", raio, circ_area(raio));

    }

    /****************************************************************** funcao: triang_area

    * calcula a area de um triangulo dada a base e altura

    * Entrada: base e altura do triangulo

    * Saida: area do triangulo

    *****************************************************************/float triang_area(float base, float alt){

    return 0.5*base*alt;}

    /****************************************************************** funcao: circ_area

    * calcula a area de um circulo dado o raio

    * Entrada: raio do circulo

    * Saida: area do circulo

    50

  • *****************************************************************/float circ_area(float r){

    return PI*r*r;}

    Este programa C consiste de trs funes, main(), triang_area(), e circ_area(). main()tem variveis locais chamadas base, altura e raio; triang_area() tem como variveis locai seusparmetros formais, base e alt; circ_area() tem como varivel local seu parmetro formal r.

    Em geral, uma varivel local s existe durante a execuo da funo na qual ela est definida. Portanto,variveis locais existem desde o momento que a funo chamada at o momento em que a funo completada. Tais variveis so chamadas de automatic. Em C , uma varivel pode ser definida comosendo static. Neste caso, uma varivel local no visvel de fora do corpo da funo, mas ela no destruda no final da funo como variveis automticas so. Cada vez que a funo chamada, o valor dasvariveis static o valor final da varivel da chamada anterior.

    Variveis GlobaisAt este momento, todas as variveis que vimos so definidas dentro de funes (no corpo da funo

    ou como parmetros formais). possvel tambm definir variveis fora das funes. Tais variveis sochamadas de variveis globais ou externas. O formato da definio de variveis globais o mesmo dadefinio de variveis locais. A nica diferena onde a varivel definida: variveis globais so definidasfora de qualquer funo. Ao contrrio das variveis locais, variveis globais podem ser vistas por todas asfunes definidas aps a definio das variveis globais.

    Ns temos usado declaraes globais este tempo todo por exemplo, as declaraes de prottipos defunes. Elas so declaradas fora de qualquer funo e podem ser vistas por qualquer funo que esto apssua declarao.

    No exemplo seguinte, uma varivel saldo que atualizada por trs funes diferentes definida comouma varivel global. As trs funes que a atualizam no chamam uma a outra.

    /****************************************************************** Caixa eletronico simples

    * o saldo e o valor a ser alterado e entrado pelo usuario

    * a saida do programa e o saldo atualizado, incluindo juros

    *****************************************************************/

    #include

    #define JUROS 0.07

    /*******************prototipos

    *******************/void credito(float);void debito(float);void juros(void);

    /*******************globais

    *******************/float saldo; /* saldo atual;

    51

  • * Alterada em: credito(), debito(), juros(), main()

    * Lida em:

    */

    /***********************definicao de funcoes

    ***********************/

    main(void){

    float valor; /* valor a ser depositado/retirado */

    printf("Entre com o saldo atual: ");scanf("%f",&saldo);printf("Deposito: ");scanf("%f", &valor);credito(valor);printf("Retirada: ");scanf("%f", &valor);debito(valor);juros();printf("Juros 7%%.\n");printf("Saldo = : %.2f\n ", saldo);

    }

    /****************************************************************** Deposita um valor; atualiza a variavel global saldo

    * Entrada: valor a ser depositado

    * Saida: nenhum

    *****************************************************************/void credito(float val){

    saldo += val;}

    /****************************************************************** Debita um valor; atualiza a variavel global saldo

    * Entrada: valor a ser debitado

    * Saida: nenhum

    *****************************************************************/void debito(float val){

    saldo -= val;}

    /****************************************************************** Acumula juros; atualiza a variavel global saldo; juros: RATE

    * Entrada: nenhuma

    * Saida: nenhuma

    52

  • *****************************************************************/void juros(void){

    saldo += (saldo * JUROS);}

    Um exemplo de execuo do programa:

    Entre com o saldo atual: 1000Deposito: 200Retirada: 80Juros 7%.Saldo = 1198.40

    Variveis globais devem ser usadas SOMENTE quando muitas funes usam muito as mesmas vari-veis. No entanto, o uso de variveis globais perigoso (e no recomendado) porque a modularidade doprograma pode ser afetada. Uma varivel global pode ser alterada de dentro de uma funo, e esta alteraopode influir no resultado de uma outra funo, tornando-a incorreta (em um exemplo dado posteriormentenestas notas, duas chamadas a funo soma_y() com o mesmo argumento (zero) produz resultados dife-rentes, 100 e 300).

    Quando variveis globais so utilizadas, deve ser dado a elas nomes descritivos e um breve comentrioqual a finalidade da varivel e quais funes a acessam.

    Neste curso, voc utilizar variveis globais SOMENTE QUANDO FOR DADO PERMISSO PARAFAZ-LO. Caso contrrio, no permitido utiliz-las (ou seja, sero descontados pontos).

    Escopo de VariveisComo j discutimos anteriormente, uma varivel uma abstrao de dados que ns usamos em um

    programa. A varivel representa um endereo de memria onde os valores so armazenados. Durante aexecuo do programa, valores diferentes poder ser armazenados neste endereo. Quando uma varivel definida, o nome da varivel atrelada a um endereo especfico na memria. At este momento, jdiscutimos o que o nome de uma varivel, seu endereo, tipo e valor. Outra caracterstica que apresenta-resmo agora o escopo. O escopo de uma varivel refere-se a parte do programa onde podemos utilizar avarivel. Em outras, palavras, uma varivel visvel dentro do seu escopo.

    O escopo de uma varivel local a funo na qual ela definida. Os parmetros formais de uma funotambm so tratados como variveis locais.

    O escopo de uma varivel global a poro do programa depois da definio da varivel global (a partirdo ponto onde ela definida at o final do programa).

    Se o nome de uma varivel global idntico a uma varivel local de uma funo, ento dentro destafuno em particular, o nome refere-se a varivel local. (Embora tais conflitos devem ser evitados paraevitar confuso).

    Por exemplo, considere o seguinte programa:

    int valor = 3; /* definicao da variavel global */

    int main(){

    /* definicao local de valor */int valor = 4;printf("%d\n", valor);

    }53

  • A sada do programa acima ser 4 j que valor refere-se a definio local.Considere outro exemplo:

    #include

    int soma_y(int);int soma_yy(int);int y = 100; /* variavel global */

    main(void){

    int z = 0; /* variavel local */

    printf("%d\n", soma_y(z));printf("%d\n", soma_yy(z));printf("%d\n", soma_y(z));

    }

    int soma_y(int x){

    return x + y; /* x e variavel local, y e global */}

    int soma_yy(int x){

    y = 300; /* y e variavel global */return x + y; /* x e variavel local */

    }

    Vamos seguir a execuo deste programa. Primeiro, a varivel global y criada e inicializada com 100.Ento, a execuo da funo main() comeca: alocado espao na memria para a varivel local z. Estavarivel inicializada com 0. Considere a primeira sentena printf():

    printf("%d\n", soma_y(z));

    Esta uma chamada para a funo da biblioteca padro printf(). Os parmetros reais desta chamadaso o string "%d\n" e a expresso soma_y(z). A ltima expresso a chamada da funo soma_y().O valor desta expresso o resultado retornado por soma_y(). Qual o resultado? A funo soma_y chamada com o parmetro real z. Como z = 0, este o valor que ser passado para a funo soma_y;o 0 copiado para o parmetro formal x da funo soma_y(). Portanto, durante a excuo da primeirachamada a funo soma_y(), o valor da expresso x + y ser 0 + 100, que 100. Portanto, o valorda primeira chamada soma_ y(z) 100, e este nmero ser impresso com o primeiro printf() emmain(). Agora considere a segunda sentena:

    printf("%d\n", soma_yy(z));

    Quando a funo soma_yy(z) chamada, o valor de z (a varivel local z) ainda 0, portantonovamente 0 copiado para o parmetro formal int x da funo soma_yy. Quando a execuo desoma_yy() comea, ela primeiro troca o valor da varivel global y para 300 e ento retorna o valor de x+ y, que neste caso 0 + 300. Portanto, o valor desta chamada a soma_yy(z) 300, e este nmeroser impresso pelo segundo printf() em main().Por ltimo, considere a terceira sentena:

    54

  • printf("%d\n", soma_y(z));

    Quando a funo soma_y(z) chamada, o valor de z ainda 0, portanto, 0 copiada para o parmetroformal int x da funo soma_y(). Quando soma_ y() executada pela segunda vez, a varivelglobal y foi modificada para 300, portanto o valor de x + y 0 + 300. Portanto, o valor da chamadasoma_yy(z) 300, e este nmero ser impresso pelo terceiro printf() em main().

    Portanto, a sada da execuo deste programa ser

    100300300

    Neste exemplo, o escopo da varivel global y o programa todo.O escopo da varivel local z, definida dentro de maio o corpo da funo main. O escopo do parmetro

    formal x da funo soma_y o corpo de soma_y. O escopo do parmetro formal x da funo soma_yy o corpo de soma_yy.

    13.1 Outro exemplo

    Aqui apresentamos um exemplo de uma funo mais complicada. Esta funo calcula a raiz quadradainteira de um nmero (o maior inteiro menor ou igual a raiz quadrada do nmero).

    Este programa usa o algoritmo divide e calcula mdia (uma aplicao do mtodo de Newton). Eleexecuta o seguinte:

    Dado x, acharx computando sucessivamente

    an =

    {1 se n = 0

    xan1+an1

    2 caso contrriopara todo n N

    Os valores de an convergem parax a medida que n cresce.

    Para achar a raiz quadrada inteira, este algoritmo repetido at que

    a2n x < (an + 1)2

    Por exemplo, para achar a raiz quadrada inteira de 42 (usando diviso inteira que trunca a parte fracionaldo nmero)a0 = 1, a1 = (42/1 + 1)/2 = 21, a2 = (42/21 + 21)/2 = 11, a3 = (42/11 + 11)/2 = 7, a4 =(42/7 + 7)/2 = 6.Uma vez que a24 = 6

    2 = 36 42 < (a4 + 1)2 = 72 = 49, o processo termina e a resposta 6.(No necessrio voc entender por que este algoritmo funciona portanto no se preocupe se no

    conseguir entend-lo)

    55

  • int raizInteira(int); /* prototipo */

    /*************************************************************** function: raizInteira(x)

    * acao: dado x, retorna a raiz quadrada inteira de x

    * in: inteiro positivo x

    * out: raiz quadrada inteira de x

    * suposicoes: x >= 0

    * algoritmo: metodo de dividr e calcular media: comecando com

    * um palpite de 1, o proximo palpite e calculado como

    * (x/palpite_ant + palpite_ant)/2. Isso e repetido

    * ate que palpite^2 = palpite*palpite && x < (palpite+1)*(palpite+1))) {

    /* Calcula proximo palpite */palpite = (x/palpite + palpite) / 2;

    }return palpite;

    }

    Note que usando a lei de DeMorgan, podemos re-escrever a expresso teste do while em uma formaequivalente:

    x < palpite * palpite || x >= (palpite + 1) * (palpite + 1)

    Deve estar claro neste ponto a diferenca entre ao e algoritmo. Uma pessoa que quer usar esta funoprecisa saber somente a ao, no o algoritmo. tambm importante especificar os dados que so esperadospela funo e retornados por ela para outras pessoas poderem us-la. As suposies devem esclarecer asrestries da funo sobre quando a funo pode falhar ou produzir resultados errados. Neste caso, umnmero negativo produziria um erro, j que nmeros negativos no possuem raiz quadrada.

    No h necessidade de ir em muitos detalhes em qualquer parte da documentao da funo. Embora eladeva conter informao suficiente para que algum (que no possa ver o cdigo) saber utiliz-la. Detalhessobre implementao e detalhes menores sobre o algoritmo devem ser colocados como comentrios noprprio cdigo.

    56

  • 14 Estruturas de Repetio

    A linguagem C possui comandos para repetir uma sequncia de instrues. Estas estruturas de repetio,tambm conhecidas como laos (do ingls loops). A principal construo que veremos o while2

    14.1 O comando de repetio while

    O comando de repetio while tem duas partes: a expresso de teste e o corpo da repetio. O formato dowhile :

    while (expresso teste)corpo da repetio

    A expresso teste inicialmente avaliada para verificar se o lao deve terminar. Caso a expresso sejaverdadeira (isto , diferente de 0 (zero)), o corpo da repetio executado. Depois desta execuo, oprocesso repetido a partir d