Você está na página 1de 22

9.

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 segundo significa que a funo no tem argumentos (ela no precisa de nenhuma informao externa para ser executada). Isso no significa que a funo no faz nada. Ela pode realizar alguma ao, como imprimir uma mensagem. O exemplo abaixo mostra um programa que usa uma funo como essa: void alo(void); main() { alo(); } void alo(void) { cout << "Alo." << endl; } Neste exemplo, o programa consiste de duas funes, main() e alo(). A ordem em que as funes so 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 declarar uma funo. Um prottipo passa ao compilador informaes sobre uma funo que definida dentro de um programa em algum lugar. Prottipos so sempre colocados prximo ao incio do programa, antes do comeo da definio de funes. A funo alo() imprime a mensagem Alo. quando chamada. A sentena cout o corpo da funo. Dentro da funo main() h uma chamada a funo alo(). A funo chamada pelo seu nome seguido de () (j que a funo alo no tem argumentos, nenhuma expresso escrita dentro dos parnteses). 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 terminada por ponto e vrgula (;). alo(); Outra coisa que voc deve ter notado que main() tambm uma funo. A funo main() no difere

em nada das demais funes, com a exceo de que contm o programa principal. Alm disso, no necessrio declarar o prottipo da funo main(). 9.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 passadas para a funo cumprimenta(). A funo cumprimenta() definida de forma que ela imprimir a mensagem incluindo quaisquer iniciais passadas. 34 #include <iostream> using namespace std; void cumprimenta(char, char); int main() { char primeiro, segundo; cout << "Entre com duas iniciais (sem separacao): "; cin >> primeiro >> segundo ; cumprimenta(primeiro, segundo); } void cumprimenta(char inic1, char inic2) { cout << "Ola, " << inic1 << inic2 << "!" << endl; } A funo main() chama a funo cumprimenta(); main() passa para cumprimenta() os valores dos dois caracteres para serem impressos. Veja um exemplo de execuo do programa: Entre com duas iniciais (sem separacao): YK Alo, YK! Note que h uma correspondncia entre o nmero e tipo dos valores que main() passa (estes so chamados de parmetros reais ou argumentos reais) e os argumentos listados no cabealho da funo cumprimenta(). 9.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 programa que o chamou. Uma funo que retorna um valor tem no cabealho o nome do tipo do resultado. O valor 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 alguns clculos, e retorna o resultado (que um nico valor) para quem a chamou. A funo chamadora pode ento

usar 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 dado no cabealho da funo antes do nome da funo). Considere o seguinte exemplo. O programa consiste de duas funes: main() e quadrado. O programa pede que o usurio digite trs nmeros e verifica se eles podem ser os lados de um tringulo reto. // programa que verifica se 3 numeros podem ser os lados de um // triangulo reto. // #include <iostream> using namespace std; 35 int quadrado(int); int main() { int s1, s2, s3; cout << "Entre tres inteiros: "; cin >> 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)) ) cout << " " << s1 << " " << s2 << " " << s3 << " podem formar um triangulo reto\n"; else cout << " " << s1 << " " << s2 << " " << s3 << " nao podem formar um triangulo reto\n"; } // 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 o clculo, e tambm usamos o valor retornado pela funo em expresses. O valor de quadrado(s1) o valor que a funo quadrado() retorna quando chamado com o valor do argumento sendo igual ao valor da varivel s1. Os valores retornados pelas chamadas de funes podem ser usados em todos os lugares valores podem ser 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() { cout << "cinco = " << cinco() << endl; } int cinco(void) { return 5; 36 } A sada do programa ser cinco = 5 porque o valor de cinco() dentro da sentena cout 5. Olhando na sentena return, 5 a expresso retornada para o chamador. Outro exemplo: int obtem_valor(void); main() { int a, b; a = obtem_valor(); b = obtem_valor(); cout << "soma = " << a + b << endl; } int obtem_valor(void) { int valor; cout << "Entre um valor: "; cin >> 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: 15 Entre um valor: 4 soma = 19 9.5 Mais sobre o return Quando uma funo return executada, a funo imediatamente acaba mesmo que haja cdigo na funo aps a sentena return. A execuo do programa continua aps o ponto no qual a chamada de funo 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 retorna um nico valor. O seguinte exemplo mostra uma funo (uma verso para int da funo obtem valor) que pede para usurio um valor e se o usurio digitar um valor negativo, imprime uma mensagem e retorna um valor positivo. int obtem_valor_positivo(void) { int valor; 37 cout << "Entre um valor: "; cin >> valor; if (valor >= 0) return valor; cout << "Tornando o valor positivo..." << endl; return -valor; } Em uma funo void, return; (s com ;) pode ser usado para sair de uma funo. O exemplo seguinte, pede instrues ao usurio. Se o usurio reponder nao, a funo termina. Do contrrio, ele imprime as instrues e depois termina. void instrucoes(void) { int ch; cout << "Voce quer instrucos? (s/n): "; ch = cin.get(); /* Termina se resposta for n */ if (ch == n || ch == N) return; /* Mostra instrucoes */ cout << "As regras do jogo sao . . . "; . . . return; } O return final (antes de fechar as chaves do corpo da funo) na funo opcional. Se omitido, a funo atingir o final da funo e retornar automaticamente. Note que o return opcional somente para funes void. 9.6 Mais sobre Argumentos A comunicao entre uma funo e o chamador pode ser nas duas direes. Argumentos podem ser usados pelo chamador para passar dados para a funo. A lista de argumentos definida pelo cabealho da funo

entre 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 argumentos tem void como lista de argumento. No corpo da funo os argumentos (tambm chamados de argumentos formais ou parmetros formais) so tratados como variveis. erro defini-los dentro do corpo da funo porque eles j esto definidos no cabealho. Antes da execuo da funo os valores passados pelo chamador so atribudos aos argumentos da funo. Considere o seguinte programa com a funo abs() que calcula o valor absoluto de um nmero. int abs(int); 38 main() { int n; cout << "Entre um numero: "; cin >> n; cout << "Valor absoluto de " << n << " eh " << abs(n) << endl; } /* 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 como uma varivel x. Uma vez que abs() tem um nico argumento, quando ela chamada, h sempre um valor dentro do parnteses, 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 chamada desta 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 na mesma 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. Quando passar os argumentos, importante ter certeza de pass-los na ordem correta e que eles so do tipo correto. Se isso no for observado, pode ocorrer erro ou aviso de compilao, ou resultados incorretos podem ser gerados. 39 Uma ltima observao. Os argumentos que so passados pelo chamador podem ser expresses em geral e no somente constantes e varivies. Quando a funo chamada durante a execuo do programa, estas expresses so avaliadas, e o valor resultante passado para a funo chamada. 9.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 valor 5, 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 uma constante 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 o valor passado para quadrado(). Esta maneira de passar argumentos chamada de chamada por valor. Argumentos em C++ so passados por valor. Portanto, a funo chamada no pode alterar o valor da varivel passada pelo chamador como argumento, porque ela no sabe em que endereo de memria o valor da varivel est armazenado. 9.8 Variveis locais Como voc provavelmente j reparou em alguns exemplos, possvel definir variveis dentro de funes, da

mesma forma que temos definido variveis dentro da funo main(). A declarao de variveis feita no incio da funo. Estas variveis so restritas a funo dentro da qual elas so definidas. S esta funo pode enxergar suas prprias variveis. Por exemplo: void obtem_int(void); main() { obtem_int(); /* **** Isto esta errado **** */ cout << "Voce digitou " << x << endl; } void obtem_int(void) { int x; cout << "Entre um valor: "; cin >> x; cout << "Obrigado!\n"; } A funo main() usou um nome x, mas x no definido dentro de main; ele uma varivel local a get int(), no a main(). Este programa gera erro de compilao. 40 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 !! **** */ cout << "Voce digitou " << x << endl; } int obtem_novo_int(void) { int x; cout << "Entre um valor: "; cin >> x; cout << "Obrigado!\n"; return x; } A funo obtem novo int() usa uma varivel local chamada x para armazenar o valor digitado e retorna como resultado o valor de x. main() usa outra varivel local, tambm chamada de x para receber o resultado retornado por obtem novo int(). Cada funo tem sua prpria varivel x.

9.9 Prottipos Os prottipos servem para dar ao compilador informaes sobre as funes. Isso para que voc possa chamar funes 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 com uma 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 do programa. A principal vantagem de definir prottipos que erros de chamada de funes (como chamar uma funo com o nmero incorreto de argumentos, ou com argumentos de tipo errado) so detectados pelo compilador. 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 a depurao de erros mais difcil. Abaixo, mostramos duas funes e seus prottipos: float volume(float, float, float); float dinheiro(int, int, int, int); 41 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 Mais sobre funes A nfase aqui ser em como funes funcionam. O que acontece quando uma funo chamada ? A que varivel um nome est se referenciando? O tratamento em tempo de execuo de um nome de varivel em C++ simples: um nome de varivel ou uma 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. O prottipo escrito fora de qualquer funo. Desta forma, nomes de funes so visveis para todas as outras funes 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, a palavra void escrita entre os parnteses. 3. o tipo do resultado que a funo retorna atravs da sentena return ou void se a funo no retorna nenhum 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 ({ }) contendo definio de variveis e outras sentenas. Em C++ , no se pode definir uma funo dentro de outra. 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 da funo). 45 Por exemplo, suponha que triang area() e circ area() sejam funes que calculam a rea de tringulos 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 so chamadas podem ser expresses constantes, or variveis locais, ou qualquer expresso cuja avaliao resulte em valores do tipo float (inteiros so convertidos para float da mesma forma que ocorre com atribuio de inteiros para variveis do tipo float). Alguns exemplos de chamadas: float area2, area3, area4, area5, base, altura, raio; cout << "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 igual ao 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 a funo na qual so definidas. Somente esta funo pode enxerg-las (ela conhece o endereo das variveis e pode usar e modificar o seu contedo). Nenhuma outra funo pode acessar variveis locais de outra funo sem permisso (uma funo pode acessar variveis locais de outra se esta passar o endereo da varivel local como argumento este assunto ser tratado em notas de aula futuras). O fato de cada funo manter variveis locais escondidas do resto do mundo torna mais fcil a tarefa de escrever programas estruturados e modulares. Quando voc est escrevendo uma funo, voc pode dar as suas variveis locais o nome que quiser. Voc tambm no precisa se preocupar se outra pessoa escrevendo outra funo ter acesso ou altera variveis locais a sua funo. Variveis locais que so definidas dentro da funo devem ser inicializadas com algum valor antes de serem usadas. Caso contrrio, o seu valor indefinido. J que parmetros formais (argumentos) so variveis locais da funo, eles podem ser usados no corpo da funo. Eles no devem ser definidos dentro da funo (sua definio j est no cabealho da funo). Os parmetros formais no precisam ser inicializados. Seus valores so fornecidos pelo chamador da funo atravs 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. * A saida do programa e a area do triangulo e circulo. *****************************************************************/ 46 #include <iostream> using namespace std; #define PI 3.1415 /******************* prototipos *******************/ float triang_area(float, float); float circ_area(float); /******************* definicao de funcoes *******************/ main() { /* definicao das variaveis locais */ float base, altura, raio; /* dialogo de entrada */

cout << "\nEntre com a base e altura do triangulo: "; cin >> base >> altura; cout << "\nEntre com o raio do circulo: "; cin >> raio; /* chama as funcoes e imprime o resultado */ cout << "Area do triagulo com base e altura " << base << " e " << altura << " = " << triang_area(base, altura) << endl;; cout << "Area do circulo com raio " << raio << " = " << circ_area(raio) << endl; } /***************************************************************** * 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 *****************************************************************/ 47 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 seus parmetros 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 como sendo 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 das variveis static o valor final da varivel da chamada anterior. 12 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 primeira construo que veremos o while, seguida de for e de do ... while.

12.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 do while : while (expresso teste ) corpo da repetio A expresso teste inicialmente avaliada para verificar se o lao deve terminar. Caso a expresso seja verdadeira (isto , diferente de 0 (zero)), o corpo da repetio executado. Depois desta execuo, o processo repetido a partir da expresso teste. O corpo do lao, por sua vez, pode ser uma sentena simples ou composta. O exemplo abaixo mostra o uso do comando de repetio while: int contador = 0; while( contador < 5 ) { cout << "contador = " << contador << endl; contador += 1; } cout << "ACABOU !!!!\n"; Sada: contador = 0 contador = 1 contador = 2 contador = 3 contador = 4 ACABOU !!!! Neste exemplo, a expresso de teste contador < 5, e o corpo do lao a sentena cout. 54 Se examinarmos cuidadosamente este exemplo, veremos que a varivel contador inicializada com 0 (zero) quando definida. Depois disso, a expresso de teste verificada e, como 0 < 5 verdadeiro, o corpo da repetio executado. Assim, o programa imprime contador = 0, e incrementa contador de um (atravs do ps-decremento indicado no argumento de cout ). Em seguida, a expresso de teste verificada novamente e todo o processo se repete at que contador seja 4 e contador = 4 seja impresso.

Depois disso, contador incrementado para 5 e o teste executado. Mas desta vez, 5 < 5 falso, ento o lao no continua. A execuo do programa continua na sentena que segue o lao (no caso, imprimir a frase ACABOU !!!). Aps a execuo do while, a varivel contador tem valor 5. No exemplo acima, h uma sentena simples no corpo da repetio. Quando este for definido por uma sentena composta (bloco), no se deve esquecer de usar as chaves ( { e }) para delimitar o bloco da sentena composta. O exemplo seguinte mostra um uso mais apropriado do comando while: Em situaes onde o nmero de repeties no conhecido antes do inico do comando while: Exemplo 1: Este programa pede nmeros ao usurio at que a soma de todos os nmeros digitados for pelo menos 20. #include <iostream> using namespace std; int main( ){ int total, num; total = 0; while( total < 20 ) { cout << "Total = " << total << endl; cout << "Entre com um numero: "; cin >> num; total += num; } cout << "Final total = " << total << endl; } Exemplo de sada: Total = 0 Entre com um numero: 3 Total = 3 Entre com um numero: 8 Total = 11 Entre com um numero: 15 Final total = 26 Inicialmente, dado o valor 0 varivel total, e o teste verdadeiro ( 0 < 20). Em cada iterao, o total impresso e o usurio digita um nmero que somado a total. Quanto total for maior ou igual a 20, o teste do while torna-se falso, e a repetio termina. 55 12.2 Estilo de formatao para estruturas de repetio A regra principal ser consistente. Assim, seu programa ser mais legvel. 12.2.1 Colocao das chaves H trs estilos comuns de colocar as chaves: while (expressao) {

sentenca; } while (expressao) { sentenca; } while (expressao) { sentenca; } APENAS UM DESTES ESTILOS deve ser consistentemente usado para as sentenas for, while e do ... while. Use o estilo com o qual voc se sentir mais confortvel. 12.2.2 Necessidade ou no das chaves Foi mencionado anteriormente que as chaves ( { e }) podem ser omitidas quando o corpo da repetio contiver apenar uma sentena. Por exemplo: while( i < 5 ) i += 1; Embora as chaves possam ser omitidas, h uma nica razo para coloc-las sempre: while( i < 5 ) { i += 1; } Quando voc adicionar algo ao programa, voc poder adicionar uma sentena para um lao com apenas uma sentena. Se voc fizer isso, vital que voc tambm adicione chaves. Se voc no fizer isso, a segunda sentena do lao no ser considerada como parte do lao. Por exemplo: while( i < 5 ) i += 1; j += 1; na verdade o mesmo que: while( i < 5 ) i += 1; j += 1; 56 enquanto a inteno era na realidade: while( i < 5 ) { i += 1; j += 1; } 12.2.3 Uso de espao em branco A outra questo de formato se deve ser colocado um espao em branco depois do while e antes do abre parnteses ( (). Por exemplo: while (i<5) ou while (i<5) ou while( i < 5 )

Isto tambm uma escolha pessoal. Porm seja consistente em sua escolha ! 12.2.4 Laos aninhados possvel colocar um lao dentro de outro (lao aninhado). Exemplo 2: #include <iostream> #include <iomanip> using namespace std; int main( ){ int linha, coluna; linha = 1; while (linha < 5) { coluna = 1; while (coluna < 5) { cout << setw(3) << linha * coluna; coluna += 1; } linha += 1; } cout << endl; } Sada: 57 1234 2468 3 6 9 12 4 8 12 16 No exemplo acima, para cada iterao do lao externo, o lao interno imprime uma linha com nmeros e depois pula de linha. Exemplo 3: Este exemplo parecido com o anterior, exceto que o cout colocado dentro do lao interno. Como era de se esperar uma nova linha impressa aps cada valor ao invs de ser depois de 4 valores. #include <iostream> #include <iomanip> using namespace std; int main( ){ int linha, coluna; linha = 1; while (linha < 5) { coluna = 1; while (coluna < 5) { cout << setw(3) << linha * coluna; cout << endl; coluna += 1; }

linha += 1; } } Sada: 1 2 3 4 2 4 6 8 3 6 9 12 4 8 12 16 58 Exemplo 4: #include <iostream> using namespace std; int main( ){ int linha, coluna; cout << endl; linha = 1; while (linha < 8) { cout << "\t"; coluna = 1; while (coluna < linha) { cout << "*"; coluna += 1; } cout << endl; linha += 1; } } Sada: * ** *** **** ***** ****** ******* ********

59 13 Ativao de funo Uma funo comea sua execuo assim que for chamada. Cada execuo da funo chamada de ativao da funo. Como j mencionamos em notas de aula anteriores, variveis locais so locais a ativao da funo: cada ativao possui suas prprias variveis locais. No comeo da ativao, memria alocada para as variveis locais e no final da execuo, elas so dealocadas. Definies de funes em C++ no podem ser aninhadas, mas ativaes de funo podem: uma funo, digamos A, pode chamar uma outra funo, digamos B (dizemos que A chama B). Nos referimos a A como o chamador e B como a funo chamada. O que acontece quando uma funo chama outra (quando A chama B)? Um registro especial, chamado registro de ativao criado. A informao neste registro necessria para a ativao da funo chamada e para a reativao do chamador depois que a execuo da funo chamada termina. 1. C++ usa chamada-por-valor, ou seja, o chamador avalia as expresses que so os parmetros reais e passa seus valores para a funo chamada. 2. A informao necessria para reiniciar a execuo da funo chamadora guardada em um registro de ativao. Tal informao inclui o endereo da instruo do chamador que ser executada depois que a funo chamada termine. 3. A funo chamada aloca espao na memria para suas variveis locais. 4. O corpo da funo chamada executado. 5. O valor retornado para a funo chamadora atravs de um return colocado em um lugar especial para que a funo chamadora possa encontr-lo. O controle retorna a funo chamadora. O fluxo de controle atravs de ativao de funes da forma ltimo-queentra-primeiro-que-sai. Se A chama B e B chama C: A ativado primeiro, ento B ativado (um registro de ativao para A chama B criado e armazenado, A temporariamente suspenso), ento C ativado (um registro de ativao de B chama C criado e armazenado, A e B so suspensos); C o ltimo a iniciar execuo, mas o primeiro a terminar (ltimo-a-entrar-primeiro-a-sair). Depois que C termina, B reativado. O registro de ativao B chama C foi criado por ltimo, mas o primeiro a ser destrudo (no momento que o controle retornada para B). Depois que B termina, A reativado. O registro de ativao correspondente a A chama B destrudo no momento em que o controle retorna para A. 14 Mais sobre funes: Quando return no suficiente

Considere o programa abaixo que pede ao usurio dois inteiros, armazena-os em duas variveis, troca seus valores, e os imprime. #include <iostream> using namespace std; main() { int a, b, temp; cout << "Entre dois numeros: "; cin >> a >> b; cout << "Voce entrou com " << a << " e " << b << endl; 60 /* Troca a com b */ temp = a; a = b; b = temp; cout << "Trocados, eles sao " << a << " e " << b << endl; } Aqui est um exemplo de execuo do programa: Entre dois numeros: 3 5 Voce entrou 3 e 5 Trocados, eles sao 5 e 3 O seguinte trecho do programa executa a troca de valores das variveis a e b: temp = a; a = b; b = temp; possvel escrever uma funo que executa esta operao de troca? Considere a tentativa abaixo de escrever esta funo: #include <iostream> using namespace std; void troca(int x, int y) { int temp; temp = x; x = y; y = temp; } main() { int a, b; cout << "Entre dois numeros: "; cin >> a >> b; cout << "Voce entrou com " << a << " e " << b << endl; // Troca a com b troca(a, b); cout << "Trocados, eles sao " << a << " e " << b << endl; } 61 Se voc executar este programa, ver que ele no funciona:

Entre dois numeros: 3 5 Voce entrou 3 e 5 Trocados, eles sao 3 e 5 Como voc j viu nas notas anteriores, em C++ os argumentos so passados por valor. Uma vez que somente os valores das variveis so passados, no possvel para a funo troca() alterar os valores de a e b porque troca() no sabe onde na memria estas variveis esto armazenadas. Alm disso, troca() no poderia ser escrito usando a sentena return porque s podemos retornar um valor (no dois) atravs da sentena return. 14.1 Usando referncia A soluo para o problema acima ao invs de passar os valores de a e b, passar uma referncia s variveis a e b. Desta forma, troca() saberia que endereo de memria escrever, portanto poderia alterar os valores de a e b. Lembre-se que em C++ a cada varivel est associado: (i) um nome; (ii) um tipo; (iii) um valor; e (iv) um endereo. Assuma que existam as seguintes definies de variveis. int i = 5; char c = G; Na memria, eles podem estar armazenados da forma abaixo: A varivel inteira i est armazenada no endereo 1342. Ela usa dois bytes de memria (quando um objeto usa mais de um byte, seu endereo onde ele comea neste caso, 1342 e no 1343). A varivel do tipo char c est armazenada no endereo 1346 e usa um byte de memria. O compilador que controla do local de armazenamento destas variveis em memria. 14.2 Argumentos por referncia em funes Considere novamente o exemplo da funo troca(). Quando a e b so passados como argumentos para troca(), na verdade, somente seus valores so passados. A funo no podia alterar os valores de a e b porque ela no conhece os endereos de a e b. Mas se referncias para a e b forem passados como argumentos ao invs de a e b, a funo troca() seria capaz de alterar seus valores; ela saberia ento em que endereo de memria escrever. Na verdade, a funo no sabe que os endereos de memria so associados com a e b, mas ela pode modificar o contedo destes endereos. Portanto, passando uma varivel 62 por referncia (ao invs da varivel), habilitamos a funo a alterar o contedo destas variveis na funo chamadora. Uma vez que endereos de variveis so do tipo apontador, a lista de parmetros formais da funo deve

refletir isso. A definio da funo troca() deveria ser alterada, e a lista de parmetros formais deve ter argumentos no do tipo int, mas referncias para int, ou seja, int& . Quando chamamos a funo troca(), ns continuamos passando parmetros reais a e b, mas desta vez, o compilador sabe que o que ser passado para a funo troca() so as referncias a estas variveis, e no seus valores. Dentro da funo troca() no dever haver mudanas. Uma vez que agora os parmetros formais so referncias, o acesso aos objetos deve ser escrito normalmente, mas deve-se ter em mente que qualquer alterao nos valores dos parmetros formais da funo implica em alterar o valor dos argumentos passados na funo chamadora. Assim, a funo troca() capaz de alterar os valores de a e b remotamente. O programa abaixo a verso correta do problema enunciado para a funo troca(): #include <iostream> using namespace std; /* function troca(px, py) * acao: troca os valores inteiros apontados por px e py * entrada: apontadores px e py * saida: valor de *px e *py trocados * suposicoes: px e py sao apontadores validos * algoritmo: primeiro guarda o primeiro valor em um temporario e * troca */ void troca(int& px, int& py) { int temp; temp = px; px = py; py = temp; } main() { int a, b; cout << "Entre dois numeros: "; cin >> a >> b; cout << "Voce entrou com " << a << " e " << b << endl; // Troca a com b -- passa argumentos por referencia troca(a, b); cout << "Trocados, eles sao " << a << " e " << b << endl; } A sada deste programa : Entre dois numeros: 3 5 63 Voce entrou com 3 e 5 Trocados, eles sao 5 e 3

Basicamente, se a funo precisa alterar o valor de uma varivel da funo chamadora, ento passamos o nome da varivel como parmetro real, e escrevemos a funo de acordo, ou seja, com um parmetro formal de sada.

Você também pode gostar