123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- <!--
- Introdução à Programação - 2017 - Prof. Leoônidas de Oliveira Brandão
- Introdução ao uso de funções em C: variáveis locais, globais e aninhamento de funções
- LInE (Laboratory of Informatics in Education) - http://www.usp.br/line
- IME - USP
- Material didático
- Pode usar livrevemente este material para fins não comerciais, devendo sempre fazer referência à autoria.
- Sugestões/apontamento são bem vindos: leo@ime.usp.br (favor indicar no assunto "material de introducao 'a programacao")
- Prof. Leônidas de Oliveira Brandão
- http://www.ime.usp.br/~leo
- http://line.ime.usp.br
- http://www.matemtica.br
- -->
- <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
- <meta name='keywords' content='mac0122, material, professores, leonidas de oliveira brandao'>
- <link rel='stylesheet' type='text/css' href='css_img_js_conf/all.css'>
- <link rel='stylesheet' type='text/css' href='css_img_js_conf/line_introducao_programacao.css'>
- <script src="css_img_js_conf/defineLInE.js"></script> <!-- para referencias 'a documentos internos -->
- <div class="pagina">
- <p class="secao">Introdução ao uso de funções em C: variáveis locais, globais e aninhamento de funções</p>
- <p class="subsecao">Sobre o aninhamento de funções na linguagem <i>C</i></p>
- <p>
- Nesta seção apresento um conceito mais "sutil" de programação, para entendê-lo é essencial que você copie os códigos apresentados,
- "cole" em seu editor preferido e os teste até que esteja tudo claro.
- Experimente alterar os exemplos e criar outros: grave-os, compile-os e os <i>rode</i>.
- <b style="color:#0000aa">Para prender programação é preciso programar!</b>
- </p>
- <p>
- Em várias linguagens de programação, <i>C</i> em particular, é possível declarar função dentro de função (<b>aninhar</b>).
- Por exemplo, dentro de uma função de nome <i>funcao2</i>, pode-se declarar outra função de nome <i>funcao3</i>.
- O resultado é que, dentro da primeira função, pode-se invocar a segunda, mas em nenhum outro local do código seria possível
- invocar esssa função <i>funcao3</i>.
- </p>
- <p>
- Mas vale destacar que esse recurso só é efetivamente útil se a função interna (<i>funcao3</i>) só fizer sentido dentro da função que a contém.
- Pois em caso contrário, você poderia invocar a função interna em outros contextos.
- Um exemplo dessa situação é ilustrado no parágrafo seguinte, a função <i>fatorial</i> poderia ficar melhor se declarada fora da função <i>combinacao</i>.
- </p>
- <p>
- Um exemplo simples de função contendo outra função, poderia ser o caso do cálculo da combinação de <i>n</i>, tomados <i>k</i>-a-<i>k</i>:
- <i>C<sub>n,k</sub> = n!/(k!(n-k)!)</i>.
- Como para o calculo de <i>C<sub>n,k</sub></i> é necessário invocar o cálculo do fatorial 3 vezes, podemos desejar fazer um implementação que
- deixe essa dependência clara, definindo uma função de nome <i>combinacao</i> e, dentro dela, declarar a função
- <i>fatorial</i>. Vide exemplo 1.
- </p>
- <p>
- Porém, como anteriormente comentado, como a função <i>fatorial</i> tem potencial de aplicação mais amplo, ela ficaria melhor se declarada
- <b style="color:#0000aa">fora</b> da função <i>combinacao</i>
- (vide a crítica a esse organização de código logo após o exemplo 1).
- </p>
- <div class="exemplo"><i>Exemplo 1</i>. Declaração aninhada de funções.
- </div><!-- class="exemplo" -->
- <div class="codigo"><pre><verm>int</verm> combinacao (<verm>int</verm> n, <verm>int</verm> k) { <cyan>// combinacao de n, k-a-k</cyan>
- <verm>int</verm> fatorial (<verm>int</verm> n) { <cyan>// fatorial de n (supondo n natural)</cyan>
- <verm>int</verm> i, fat = 1;
- for (i=2; i≶=n; i++)
- fat *= i;
- return fat;
- }
- return fatorial(n) / (fatorial(k)*fatorial(n-k));
- }
- <verm>void</verm> main (<verm>void</verm>) :
- <verm>int</verm> n = 5, k = 3;
- <verd>printf</verd>("Combinacao %d, %d-a-%d = %d\n", n, k, k, combinacao(n,k));
- <cyan>// Problema de declarar 'fatorial()' dentro de 'combinacao()': a linha abaixo daria erro!</cyan>
- <cyan>// Erro: exemplo_funcao_aninhada.c:(.text+0xd3): undefined reference to fatorial'</cyan>
- <cyan>// <verd>printf</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d", fatorial(0), fatorial(1), fatorial(2), fatorial(3));</cyan>
- }</pre>
- </div>
- <p>
- Note que o código acima apresenta a linha comentada
- <tt><verd>printf</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d", fatorial(0), fatorial(1), fatorial(2), fatorial(3));</tt>.
- A razão é que ela resultaria erro, pois a função <i>fatorial</i> foi declarada dentro da função <i>combinacao</i>
- e portanto só pode ser usando (invocada) dentro dessa segunda!
- </p>
- <p>
- Uma vez que o uso do cálculo de fatorial é muito comum e pensando que o código acima seria parte de um maior,
- então provavelmente o desenho de código usado não é bom, pois implicaria em precisarmos definir outra função <i>fatorial</i>,
- essa fora do contexto da função <i>combinacao</i>.
- Nesse sentido, poderia ser melhor usar o código (pensando que ele seja o início de um sistema maior) do
- exemplo a seguir.
- </p>
- <div class="exemplo"><i>Exemplo 2</i>. Declaração de funções sem aninhamento.
- </div><!-- class="exemplo" -->
- <div class="codigo"><pre><verm>int</verm> fatorial (<verm>int</verm> n) { <cyan>// fatorial de n (supondo n natural)</cyan>
- <verm>int</verm> i, fat = 1;
- for (i=2; i≶=n; i++)
- fat *= i;
- return fat;
- }
- <verm>int</verm> combinacao (<verm>int</verm> n, <verm>int</verm> k) { <cyan>// combinacao de n, k-a-k</cyan>
- return fatorial(n) / (fatorial(k)*fatorial(n-k));
- }
- <verm>void</verm> main (<verm>void</verm>) :
- <verm>int</verm> n = 5, k = 3;
- <verd>printf</verd>("Combinacao %d, %d-a-%d = %d\n", n, k, k, combinacao(n,k));
- <cyan>// Note que agora pode-se invocar 'fatorial()' dentro da 'main'</cyan>
- <verd>printf</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d", fatorial(0), fatorial(1), fatorial(2), fatorial(3));
- }</pre>
- </div>
- <a name="variaveis">
- <p class="subsecao">Variáveis globais e locais</p>
- </a>
- <p>
- Outro conceito importante relacionado com funções é o de declaração de variáveis.
- Assim, uma variável é <b>local</b> se declarada dentro de uma função qualquer, quer dizer,
- essa variável será "conhecida" (poderá ser usada) apenas dentro dessa função.
- Por exemplo, no <i>exemplo 2</i> acima, a variável <i>fat</i> é conhecida apenas dentro da função
- <i>fatorial</i>, portanto seu uso deve-se restringir a esse contexto.
- </p>
- <p>
- Por outro lado, pode-se usar o mesmo nome para variáveis que estão em contextos distintos.
- Por exemplo, no código do <i>exemplo 1</i>, se fosse necessário poderíamos usar o nome de variável
- local <i>i</i> dentro da função <i>combinacao</i> e não haveria qualquer colisão com a variável
- <i>i</i> de <i>fatorial</i>.
- </p>
- <p>
- Entretanto é necessário um critério que elimine <i>ambiguidades</i>, isto é, que permita identificar
- unicamente cada uma das variáries. Para isso usa-se o <b>princípio da proximidade</b> (ou da <b>localidade</b>),
- quer dizer, ao usar uma variável considera-se como sua declarção aquela mais próxima.
- Por isso, que poderiamos usar <i>i</i> tanto em <i>combinacao</i>, quanto em <i>fatorial</i>,
- </p>
- <center>
- <img src="img/funcoes_var_locais.png" title="imagem ilustrando principio da localidade"/>
- <br/>
- <i>Fig. 1. Imagem de código ilustrando o princípio da localidade, variável <tt>var1</tt> dentro de <tt>funcao2</tt> é a declarada localmente.
- </center>
- <p>
- Já uma variável <b>global</b> pode ser acessada em qualquer ponto do código.
- Mas por essa mesma razão deve evitada, sendo necessária apenas para casos excepcionais,
- sempre com um nome significativo, que evite qualquer confusão.
- </p>
- <p>
- Em <i>C</i>, toda variável declarar fora do contexto de qualquer função, é uma variável <b>global</b>, ou seja, uma variável
- que pode ser acessada em qualquer ponto do código (em qualquer função).
- A ideia de variável global é ilustrado no próximo exemplo.
- </p>
- <div class="exemplo"><i>Exemplo 3</i>. Declaração de variável global.
- </div><!-- class="exemplo" -->
- <div class="codigo"><pre><verm>char</verm> var_global1[] = "essa variavel e' uma variavel global";
- <verm>int</verm> funcao () {
- <verd>printf</verd>("funcao1: var_global1 = %s\n", var_global1);
- }
- <verm>void</verm> main (void) {
- <verd>printf</verd>("main : var_global1 = %s\n", var_global1); <cyan>// uso da global</cyan>
- funcao();
- }</pre>
- </div>
- <p class="subsecao">Aninhando funções e variáveis locais e globais</p>
- <p>
- Deve-se notar que é possível aninhar tantas funções quantas forem necessárias e o mesmo para variáveis locais.
- O exemplo abaixo ilustra esses aninhamentos e o princípio da proximidade.
- Examine-o com atenção, copie-o em seu computador, utilizando um compilador <i>C</i>
- e altere seu código, compile-o e rode-o até que esteja certo de ter assimilado os conceitos.
- </p>
- <div class="exemplo"><i>Exemplo 4</i>. Declaração de variáveis locais, usando globais e aninhamento de funções.
- </div><!-- class="exemplo" -->
- <div class="codigo"><pre style="font-size:0.8em;">#include <stdio.h>
- <verm>char</verm> glob1[] = "glob1: variavel global, conhecida em qualquer local";
- <verm>void</verm> funcao1 () {
- <verm>char</verm> loc1[] = "loc1: conhecida apenas dentro da funcao 'funcao1'";
- <verm>char</verm> glob1[] = "funcao1.glob1: declarada dentro de 'funcao1' => uma variavel local `a funcao 'funcao1'";
- <verd>printf</verd>("funcao1: loc1 = %s\n", loc1); <cyan>// note que: pode haver m</cyan>
- <verd>printf</verd>("funcao1: glob1 = %s\n\n", glob1);
- }
- <verm>void</verm> funcao2 (param1) {
- <verm>char</verm> loc1[] = "loc1: conhecida apenas dentro da funcao 'funcao2 - NAO sou a 'funcao1.loc1'!'";
- <verm>char</verm> loc2[] = "loc2: conhecida apenas dentro da funcao 'funcao2'";
- <verm>void</verm> funcao3 () { <cyan>// essa funcao so' e' conhecida dentro de 'funcao2'!</cyan>
- <verm>char</verm> loc1[] = "loc1: conhecida apenas dentro da funcao 'funcao3' - NAO sou a 'funcao1.loc1' e nem a 'funcao2.loc1'!";
- <verm>char</verm> glob1[] = "funcao3.glob1: declarada dentro de 'funcao3' => var. local `a funcao 'funcao3' - NAO e' global 'glob1' e nem 'funcao1.glob1'!";</cyan> <!-- " -->
- <verd>printf</verd>("funcao3: loc1 = %s\n", loc1); <cyan>// note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
- <verd>printf</verd>("funcao3: loc2 = %s\n", loc2); <cyan>// note que: e' local `a funcao 'funcao2' - variavel declarada fora de funcao3!</cyan>
- <verd>printf</verd>("funcao3: glob1 = %s\n", glob1);
- }
- <verd>printf</verd>("funcao2: param1 = %s\n", param1);
- <verd>printf</verd>("funcao2: loc1 = %s\n", loc1); <cyan>// note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
- <verd>printf</verd>("funcao2: loc2 = %s\n", loc2); <cyan>// note que: e' local</cyan>
- <verd>printf</verd>("funcao2: glob1 = %s\n", glob1);
- <verd>printf</verd>("funcao2: chama funcao3\n\n");
- funcao3();
- <verd>printf</verd>("funcao2: chama funcao1\n\n");
- funcao1();
- }
- <verm>void</verm> main () {
- <verm>char</verm> loc1[] = "loc1: conhecida apenas dentro da funcao 'main'";
- <verd>printf</verd>("main : loc1 = %s\n", loc1); <cyan>// note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
- <verd>printf</verd>("main : glob1 = %s\n", glob1);
- <verd>printf</verd>("main : chama funcao1\n\n");
- funcao1();
- <verd>printf</verd>("main : chama funcao2\n\n");
- funcao2("parametro efetivo passado para a funcao 'funcao2'");
- <cyan>// Atencao: como a funcao 'funcao3' foi declarada dentro da funcao 'funcao2', entao ela so' pode se invocada em 'funcao2'</cyan>
- <cyan>// Por exemplo, a linha abaixo resultaria no erro: sobre_variaveis_global_local.c:(.text+0x4d2): undefined reference to funcao3'</cyan>
- <cyan>// funcao3();</cyan>
- }</pre>
- </div>
- <p class="autoria">
- <a href="https://www.ime.usp.br/~leo" target="_blank" title="seguir para a pagina do prof. Leônidas">Leônidas de Oliveira Brandão</a><br/>
- <a href="http://www.ime.usp.br/~leo" target="_blank" title="seguir para a página do LInE">http://line.ime.usp.br</a>
- </p>
- <p class="rodape">
- <b>Alterações</b>:<br/>
- 2020/08/15: novo formato, pequenas revisões<br/>
- 2020/08/09: formato, revisão geral;<br/>
- 2018/05/22: pequenas alterações<br/>
- 2018/05/21: pequenas alterações
- </p>
- </div>
|