<!--
 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&lg;=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&lg;=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 &lt;stdio.h&gt;

<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>