Comentários

0%

Não pode faltar

Escopo e passagem de parâmetros

Vanessa Cadan Scheffer

Qual a diferença entre variáveis locais e globais?

A diferença entre elas é o local em que são definidas, que determina seu escopo e visibilidade dentro do programa.

Fonte: Shutterstock.

Deseja ouvir este material?

Áudio disponível no material digital.

Praticar para Aprender

Dando continuidade ao seu trabalho no laboratório de pesquisa multidisciplinar, após construir com êxito o programa para a equipe de nutrição, agora você trabalhará com o núcleo de estatística. Você precisa criar funções que facilitem alguns dos cálculos mais comuns usados por estatísticos: a média e a mediana. Com base nessas funções tão importantes, podemos, por exemplo, calcular a média e a mediana dos IMCs de uma determinada população. A ideia é que, a partir de um conjunto de números reais (vetor), seu programa calcule a média e a mediana desses conjuntos.

Relembrando: a média é o resultado da soma de todos os números do conjunto dividida pela quantidade de números que foram somados. Já a mediana será o número que ocupa a posição central do conjunto, considerando que o conjunto esteja crescentemente ordenado.

Para o cálculo da mediana, há uma particularidade que deve ser observada. Se a quantidade de números do conjunto for ímpar, a mediana será o elemento do meio do vetor. Por exemplo, para o vetor [21, 24, 31, 32, 32, 32, 33, 44, 65], a mediana será o número 32, que está bem no meio do vetor. Porém, se a quantidade de número do conjunto for par, então a mediana será a média aritmética dos dois valores centrais. Por exemplo, para o vetor [18, 19, 19, 22, 44, 45, 46, 46, 47, 48], a mediana será (44 + 45) / 2  89 /2, que é igual a 44,5.

Além do cálculo, seu programa deverá exibir os resultados na tela.

Com esse conhecimento seus programas ficarão mais organizados e otimizados. Vamos lá!

Roteiro para o professor

Prezado professor, antes de partir para a implementação da solução, mostre como funcionam os conceitos de mediana e média.

O aluno terá que entender como obter o(s) elemento(s) do meio de um vetor na linguagem C. Cabe lembrá-lo que o vetor, em C, é indexado a partir do 0. Ao dividir o tamanho do vetor por 2, caso o tamanho seja ímpar, o resultado será um valor real. Contudo, os índices de um vetor são números inteiros. Assim, o aluno precisará entender o mecanismo que a linguagem C usa para converter um número real em um número inteiro.

Faça perguntas aos alunos:

  • O que acontecerá com o número real ao ser convertido para um inteiro?
  • Sua parte decimal será simplesmente descartada?
  • O valor será arredondado?
  • Caso seja arredondado, como será a estratégia de arredondamento?

Há, na documentação da linguagem, respostas para essas perguntas, como em Cppreference ([s.d.]), disponível em: https://bit.ly/2Ylyf9W, contudo, encoraje os alunos a fazerem testes e observarem os resultados.

conceito-chave

Caro aluno, você sabe quantos números de linhas telefônicas ativas existem no mundo hoje? Segundo Almeida e Zanlorenssi (2018), o número de linhas ativas ultrapassa a marca de 8 bilhões. No Brasil, um número de telefone fixo é dividido em três partes: código da região, código da cidade e o número. Imagine um usuário desatento que deseja ligar para uma cidade diferente da que ele reside e ele digita 3441-1111. Essa ligação iria para qual cidade? Existem várias cidades com o código 3441 e o que as diferencia é o código da região, delimitando o escopo daquele número. O mesmo acontece com variáveis em um programa: o seu escopo definirá o limite de utilização desse recurso.

Escopo de variáveis

Variáveis são usadas para armazenar dados temporariamente na memória, porém o local em que esse recurso é definido no código de um programa determina seu escopo e sua visibilidade. Observe no Código 3.8.

Código 3.8 | Exemplo de variáveis em funções
#include<stdio.h>

int testar(){
    int x = 10;
    return x;
}
int main(){
    int x = 20;
    printf("\n Valor de x na função main() = %d", x);
    printf("\n Valor de x na função testar() = %d", testar());

    return 0;
}
Fonte: elaborado pela autora.

Na implementação do Código 3.8 temos duas variáveis chamadas “x”. Isso acarretará algum erro? A resposta, nesse caso, é não, pois mesmo as variáveis tendo o mesmo nome, elas são definidas em lugares diferentes: uma está dentro da função main() e outra dentro da testar(), e cada função terá seu espaço na memória de forma independente. Na memória, as variáveis são localizadas pelo seu endereço, portanto, mesmo sendo declaradas com o mesmo nome, seus endereços são distintos.

A partir desse exemplo, pode-se definir o escopo de uma variável como “a relação de alcance que se tem com o local onde certo recurso se encontra definido, de modo que possa ser ‘enxergado’ pelas várias partes do código de um programa” (MANZANO, 2015, p. 288). O escopo é dividido em duas categorias, local ou global (MANZANO; MATOS; LOURENÇO, 2015).

Variáveis local e global

No exemplo do Código 3.8, ambas variáveis são locais, ou seja, elas existem e podem ser vistas somente dentro do corpo da função onde foram definidas. Para definir uma variável global, é preciso criá-la fora de qualquer função, assim ela será visível por todas as funções do programa. No contexto apresentado nessa seção, elas serão criadas logo após a inclusão das bibliotecas.

No Código 3.9 é apresentado um exemplo de declaração de uma variável global, na linha 3, logo após a inclusão da biblioteca de entrada e saída padrão. Veja que na função principal não foi definida qualquer variável com o nome de “x” e mesmo assim seu valor pode ser impresso na linha 10, pois é acessado o valor da variável global. Já na linha 12 é impresso o valor da variável global modificado pela função testar(), que retorna o dobro do valor.

Código 3.9 | Exemplo de variável global
#include<stdio.h>

int x = 10;

void testar(){
    x = 2 * x;
}

int main(){
    printf("\nValor de x global = %d", x);
    testar();
    printf("\nValor de x global alterado em testar() = %d", x);

    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.9 utilizando a ferramenta Paiza.io.

Assimile 

A utilização de variáveis globais permite otimizar a alocação de memória, pois em vários casos o desenvolvedor não precisará criar variáveis locais. Por outro lado, essa técnica de programação deve ser usada com cautela, pois variáveis locais são criadas e destruídas ao fim da função, enquanto as globais permanecem na memória durante todo o tempo de execução.

A seguir será apresentado um exemplo da utilização do escopo global de uma variável. Vamos criar um programa que calcula a média entre duas temperaturas distintas. Observe no Código 3.10, na linha 3, em que foram declaradas duas variáveis. É importante destacar que o programa sempre começa pela função principal e a execução inicia na linha 8. Na linha 9, é solicitado ao usuário digitar duas temperaturas (em que é pedido conforme a linha 10), as quais são armazenadas dentro das variáveis globais criadas. Na linha 11, a função calcularMedia() é invocada para fazer o cálculo da média usando os valores das variáveis globais. Nesse exemplo, fica clara a utilidade dessa técnica de programação, pois as variáveis são usadas em diferentes funções, otimizando o uso da memória, pois não foi preciso criar mais variáveis locais.

Código 3.10 | Calcular média de temperatura com variável global
#include<stdio.h>

float t1, t2;

float calcularMedia(){
    return (t1 + t2) / 2;
}
int main() {
    printf("\nDigite as duas temperaturas: ");
    scanf("%f %f", &t1, &t2);
    printf("\nA temperatura média é %.2f", calcularMedia());

    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.10 utilizando a ferramenta Paiza.io.

Exemplificando 

É possível criar variáveis com mesmo nome em diferentes funções, pois o escopo delas é local. Entretanto, se existir uma variável global e uma local com mesmo nome, por exemplo:

Código 3.11 | Variáveis com mesmo nome
#include<stdio.h>
int x = 10;
int main(){
  int x = -1;
  printf("\nValor de x = %d", x);
}
Fonte: elaborado pela autora.

Qual valor será impresso na variável x? A variável local sempre sobrescreverá o valor da global, portanto, nesse caso, será impresso o valor -1 na função principal.

Teste o código utilizando a ferramenta Paiza.io.

Na linguagem C, para conseguirmos acessar o valor de uma variável global, dentro de uma função que apresenta uma variável local com mesmo nome, devemos usar a instrução extern (MANZANO, 2015). No Código 3.12, veja como utilizar variáveis globais e locais com mesmo nome na linguagem C. Observe que foi necessário criar uma variável chamada “b”, com um bloco de instruções (linhas 8 – 11), que atribui à nova variável o valor “externo” de x.

Código 3.12 | Variável global e local com mesmo nome
#include<stdio.h>

int x = 10;

int main(){
  int x = -1;
  int b;
  {
    extern int x;
    b = x;
  }
  printf("\n Valor de x = %d",x);
  printf("\n Valor de b (x global) = %d",b);
  return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.12 utilizando a ferramenta Paiza.io.

Passagem de parâmetros para funções

Para criar funções usamos a seguinte sintaxe:

<tipo de retorno> <nome> (<parâmetros>) {
   <Comandos da função>
   <Retorno> (não obrigatório)
}

Com exceção dos parâmetros que uma função pode receber, todos os demais já foram apresentados, portanto, nos dedicaremos a entender esse importante recurso.

Ao definir uma função, podemos também estabelecer que ela receberá informações “de quem” a invocou. Por exemplo, ao criar uma função que calcula a média, podemos definir que “quem chamar” deve informar os valores sobre os quais o cálculo será efetuado.

Passagem por valor

Na sintaxe, para criar uma função que recebe parâmetros é preciso especificar qual o tipo de valor que será recebido. Uma função pode receber parâmetros na forma de valor ou de referência (SOFFNER, 2013). Na passagem parâmetros por valores, a função cria variáveis locais automaticamente para armazenar esses valores e, após a execução da função, essas variáveis são liberadas. Veja, no Código 3.13, um exemplo de definição e chamada de função com passagem de valores. Observe que, na linha 2, a função somar() foi definida para receber dois valores inteiros. Internamente serão criadas as variáveis “a” e “b” locais, para guardar uma cópia desses valores até o final da função. Na linha 8, a função somar() foi invocada, passando os dois valores inteiros que a função espera receber, e o resultado do cálculo será guardado na variável “result”.

Código 3.13 | Chamada de função com passagem de valores
#include<stdio.h>
int somar(int a, int b){
    return a + b;
}

int main(){
    int result;
    result = somar(10, 15);
    printf("\nResultado da soma = %d", result);

    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.13 utilizando a ferramenta Paiza.io.

Assimile

A técnica de passagem de parâmetros para uma função é extremamente usada em todas as linguagens de programação. Ao chamar uma função que espera receber parâmetros, caso os argumentos esperados não sejam informados, será gerado um erro de compilação.

Ao utilizar variáveis como argumentos na passagem de parâmetros por valores, essas variáveis não são alteradas, pois é fornecida uma cópia dos valores armazenados para a função (SOFFNER, 2013).

Para ficar clara essa importante definição, veja no Código 3.14. A execução do programa começa na linha 10, pela função principal, na qual são criadas duas variáveis “n1” e “n2”. Na linha 13, o comando determina a impressão dos valores das variáveis, na linha 16, a função testar() é invocada passando como parâmetro as duas variáveis. Nesse momento, é criada uma cópia de cada variável na memória para utilização da função. Veja que dentro da função o valor das variáveis é alterado e impresso, mas essa alteração é local, ou seja, é feita na cópia dos valores e não afetará o valor inicial das variáveis criadas na função principal. Na linha 19, imprimimos novamente os valores após a chamada da função. A Figura 3.3 apresenta o resultado desse programa.

Código 3.14 | Variáveis em chamada de função com passagem de valores
#include<stdio.h>

void testar(int n1, int n2){
    n1 = -1;
    n2 = -2;
    printf("\n\nValores dentro da função testar(): ");
    printf("\nn1 = %d e n2 = %d", n1, n2);
}

int main(){
    int n1 = 10;
    int n2 = 20;
    printf("\nValores antes de chamar a função testar(): ");
    printf("\nn1 = %d e n2 = %d", n1, n2);

    testar(n1, n2);

    printf("\n\nValores depois de chamar a função testar(): ");
    printf("\nn1 = %d e n2 = %d", n1, n2);

    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.14 utilizando a ferramenta Paiza.io.

Figura 3.3 | Resultado do Código 3.14
Valores antes de chamar a função testar () :. n1 = 10 e n2 = 20. Valores dentro da função testar () :. n1 = -1 e n2 = -2. Valores depois de chamar a função testar () :. n1 = 10 e n2 = 20.
Fonte: elaborada pela autora.

Passagem por referência

A utilização de passagem de parâmetros por referência está diretamente ligada aos conceitos de ponteiro e endereço de memória. A ideia da técnica é análoga à passagem por valores, ou seja, a função será definida de modo a receber certos parâmetros e “quem” faz a chamada do método deve informar esses argumentos. Entretanto, o comportamento e o resultado são diferentes.

Na passagem por referência não será criada uma cópia dos argumentos passados; na verdade, será passado o endereço da variável e a função trabalhará diretamente com os valores ali armazenados (SOFFNER, 2013).

Como a função utiliza o endereço (ponteiros), na sintaxe, serão usados os operadores * e & (MANZANO, 2015). Na definição da função os parâmetros a serem recebidos devem ser declarados com *, por exemplo: int testar(int* parametro1, int* parametro2). Na chamada da função, os parâmetros devem ser passados com o &, por exemplo: resultado = testar(&n1, &n2). Veja no Código 3.15 um exemplo de uma função que passa variáveis como referência. Observe que a única diferença desse código para o do Código 3.14 é a utilização dos operadores * e &, porém, o resultado é completamente diferente (Figura 3.4). Com a passagem por referência os valores das variáveis são alterados. Nas linhas 4 e 5, usamos asterisco para acessar o conteúdo guardado dentro do endereço que ele aponta, pois se usássemos somente n1 e n2 acessaríamos o endereço que eles apontam.

Código 3.15 | Variáveis em chamada de função com passagem de referência
#include<stdio.h>

void testar(int* n1, int* n2){
    *n1 = -1; 
    *n2 = -2;
    printf("\n\nValores dentro da função testar(): ");
    printf("\nn1 = %d e n2 = %d", *n1, *n2);
}

int main(){
    int n1 = 10;
    int n2 = 20;
    printf("\nValores antes de chamar a função testar(): ");
    printf("\nn1 = %d e n2 = %d", n1, n2);

    testar(&n1, &n2);

    printf("\n\nValores depois de chamar a função testar(): ");
    printf("\nn1 = %d e n2 = %d", n1, n2);

    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.15 utilizando a ferramenta Paiza.io.

Figura 3.4 | Resultado do Código 3.15
Valores antes de chamar a função testar () :. n1 = 10 e n2 = 20. Valores dentro da função testar () :. n1 = -1 e n2 = -2. Valores depois de chamar a função testar () :. n1 = -1 e n2 = -2.
Fonte: elaborada pela autora.
Roteiro para o professor 

Caro professor, um exemplo interessante para se explorar o conceito de passagem por referência é implementar a função swap, que inverte o conteúdo de suas variáveis passadas por parâmetro.

Disponibilize aos alunos (antes ou durante a aula) o trecho de código a seguir:

#include <stdio.h>

void swap(int x, int y) {
  int temp = x;
  x = y;
  y = temp;
}

int main() {  

  int n1 = 2, n2 = 3;  

  printf("\nAntes do swap: n1 = %d, n2 = %d", n1, n2);
  swap(n1, n2);
  printf("\nDepois do swap: n1 = %d, n2 = %d", n1, n2);  

  return 0;
}

Teste o código utilizando a ferramenta Paiza.io.

Teste o código utilizando a ferramenta Paiza.io.

Esse código deveria realizar o swap de duas variáveis inteiras, mas não o faz. Peça aos alunos que discutam, em grupo, o código apresentado anteriormente e que apontem as causas para o problema identificado, isto é, a não ocorrência da troca dos valores.

Por fim, eles podem corrigir o código utilizando o conceito de passagem de parâmetros por referência. Uma possível solução seria:

#include <stdio.h>

void swap(int* x, int* y) {
  int temp = *x;
  *x = *y;
  *y = temp;
}

int main() {  

  int n1 = 2, n2 = 3;  

  printf("\nAntes do swap: n1 = %d, n2 = %d", n1, n2);
  swap(&n1, &n2);
  printf("\nDepois do swap: n1 = %d, n2 = %d", n1, n2);  

  return 0;
}

Teste o código utilizando a ferramenta Paiza.io.

Passagem de vetor

Para finalizar esta seção, vamos ver como passar um vetor para uma função. Esse recurso pode ser utilizado para criar funções que preenchem e imprimem o conteúdo armazenado em um vetor, evitando a repetição de trechos de código. Na definição da função, os parâmetros a serem recebidos devem ser declarados com colchetes sem especificar o tamanho, por exemplo: int testar(int v1[], int v2[]). Na chamada da função, os parâmetros devem ser passados como se fossem variáveis simples, por exemplo: resultado = testar(n1,n2).

Na linguagem C, a passagem de um vetor é feita implicitamente por referência. Isso significa que mesmo não utilizando os operadores “*” e “&”, quando uma função que recebe um vetor é invocada, o que é realmente passado é o endereço da primeira posição do vetor.

Para entender esse conceito, vamos criar um programa que, por meio de uma função, preencha um vetor de três posições e em outra função percorra o vetor imprimindo o dobro de cada valor do vetor. Veja, no Código 3.16, o código que começa a ser executado pela linha 17. Na linha 20, a função inserir() é invocada, passando como parâmetro o vetor “numeros”. Propositalmente criamos a função na linha 2, recebendo como argumento um vetor de nome “a”, para que você entenda que o nome da variável que a função recebe não precisa ser o mesmo nome usado na chamada. Na maioria das vezes, utilizamos o mesmo nome como boa prática de programação. Na função inserir(), será solicitado ao usuário digitar os valores que serão armazenados no vetor “numeros”, pois foi passado como referência implicitamente. Após essa função finalizar, a execução vai para a linha 21 e depois para a 22, na qual é invocada a função imprimir(), novamente passando o vetor “numeros” como argumento. Mais uma vez, criamos a função na linha 10 com o nome do vetor diferente para reforçar que não precisam ser os mesmos. Nessa função o vetor é percorrido, imprimindo o dobro de cada valor. Veja na Figura 3.5 o resultado desse programa.

Código 3.16 | Função com passagem de vetor
#include<stdio.h>
void inserir(int a[]) {
    int i = 0;
    for(i = 0; i < 3; i++){
        printf("\nDigite o valor %d: ", i);
        scanf("%d", &a[i]);
    }
}

void imprimir(int b[]) {
    int i = 0;
    for(i = 0; i < 3; i++){
        printf("\nNúmero[%d] = %d", i, 2 * b[i]);
    }
}

int main(){
    int numeros[3];
    printf("\nPreenchendo o vetor... \n ");
    inserir(numeros);
    printf("\n\nDobro dos valores informados:");
    imprimir(numeros);
    return 0;
}
Fonte: elaborado pela autora.

Teste o Código 3.16 utilizando a ferramenta Paiza.io.

Figura 3.5 | Resultado do Código 3.16.
Preenchendo o vetor... . Digite o valor 0:. Digite o valor 1:. Digite o valor 2:.  Dobro dos valores informados:. Número [0] = 2. Número [1] = 4. Número [2] = 6.
Fonte: elaborada pela autora.

Com esta seção demos um passo importante no desenvolvimento de softwares, pois os conceitos apresentados são utilizados em todas as linguagens de programação. Continue estudando e se aprofundando no tema.

Roteiro para o professor 

Prezado professor, para exercitar um pouco mais o conceito de passagem por referência envolvendo vetores, proponha o seguinte desafio aos alunos: criar uma função capaz de clonar um vetor passado por parâmetro, isto é, criar uma cópia idêntica sua e retorná-la.

Muitos alunos tentarão uma abordagem simplista, como a do código a seguir:

int[] clonarVetor(int v[], int tam) {
  int copia[tam];
  copia = v;
  return copia;
}

Logo, eles vão descobrir que isso não funciona. Ajude-os a encontrar a solução dizendo que a alocação do vetor “cópia” deve ser realizada dinamicamente, pois a linguagem C não permite que funções retornem vetores diretamente. Isso deve levá-los ao seguinte código:

#include <stdio.h>
#include <stdlib.h>

int* clonarVetor(int v[], int tam) {
  int* copia = malloc(sizeof(int) * tam);
  copia = v;
  return copia;
}

int main(void){
  int v[3] = {1, 2, 3}; 
  int* clone = clonarVetor(v, 3);
  printf("\nVetor original: [%d, %d, %d]", v[0], v[1], v[2]);
  printf("\nVetor clonado: [%d, %d, %d]", clone[0], clone[1], clone[2]);
}

O código apresentado aparentemente resolveu problema, pois a saída do vetor original e do clone são as mesmas. Contudo, ao modificar o valor do vetor clonado, teremos também modificado o conteúdo do vetor original. Peça aos alunos que façam esse teste. Eis um exemplo de como isso pode ser feito:

#include <stdio.h>
#include <stdlib.h>

int* clonarVetor(int v[], int tam) {
  int* copia = malloc(sizeof(int) * tam);
  copia = v;
  return copia;
}

int main(void){
  int v[3] = {1, 2, 3}; 
  int* clone = clonarVetor(v, 3);
  printf("\nVetor original: [%d, %d, %d]", v[0], v[1], v[2]);
  printf("\nVetor clonado: [%d, %d, %d]", clone[0], clone[1], clone[2]);

  clone[0] = -10;

  printf("\n\nVetor original: [%d, %d, %d]", v[0], v[1], v[2]);
  printf("\nVetor clonado: [%d, %d, %d]", clone[0], clone[1], clone[2]);
}

Peça que os alunos discutam, em grupo, porque isso aconteceu. Após um período de discussão, apresente a seguinte dica e peça que os alunos corrijam o código: o vetor clonado e o vetor original estão apontando para o mesmo endereço de memória, por isso, quando um é alterado, o outro também é. Eis a solução final do exercício:

#include <stdio.h>
#include <stdlib.h>

int* clonarVetor(int v[], int tam) {
  int* copia = malloc(sizeof(int) * tam);
  for(int i = 0; i < 3; i++) {
    copia[i] = v[i];
  }
  return copia;
}

int main(void){
  int v[3] = {1, 2, 3}; 
  int* clone = clonarVetor(v, 3);
  printf("\nVetor original: [%d, %d, %d]", v[0], v[1], v[2]);
  printf("\nVetor clonado: [%d, %d, %d]", clone[0], clone[1], clone[2]);

  clone[0] = -10;

  printf("\n\nVetor original: [%d, %d, %d]", v[0], v[1], v[2]);
  printf("\nVetor clonado: [%d, %d, %d]", clone[0], clone[1], clone[2]);
}

Teste o código utilizando a ferramenta Paiza.io.

Faça valer a pena

Questão 1

O uso de funções permite criar programas mais organizados, sem repetição de códigos e ainda com possibilidade de reutilização, pois caso você implemente uma função de uso comum, poderá compartilhá-la com outros desenvolvedores. Em linguagens do paradigma orientado a objetos, as funções são chamadas de métodos, mas o princípio de construção e funcionamento é o mesmo.

A respeito das funções, analise cada uma das afirmativas e determine se é verdadeira ou falsa.

  1. (    ) Funções que retornam um valor do tipo float só podem receber como parâmetros valores do mesmo tipo, ou seja, float.
  2. (    ) Funções que trabalham com passagem de parâmetros por referência não criam cópias das variáveis recebidas na memória.
  3. (    ) Funções que trabalham com passagem de parâmetros por valor criam cópias das variáveis recebidas na memória.

Assinale a alternativa correta.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Correto!

  1. Incorreta, pois os parâmetros que uma função pode receber independem do seu tipo de retorno. O mesmo se aplica aos procedimentos (sub-rotinas que retornam void), que também podem receber qualquer tipo de parâmetros. 
  2. Correta, pois ao realizar uma passagem de parâmetro por referência, o endereço da variável usada na chamada da função é passado como parâmetro e não uma cópia do seu valor.
  3. Correta, pois ao realizar uma passagem de parâmetro por cópia, o computador realiza uma cópia do valor da variável usada na chamada da função.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Questão 2

Além de retornar valores, as funções também podem receber parâmetros de “quem” a chamou. Essa técnica é muito utilizada e pode economizar na criação de variáveis ao longo da função principal. Os tipos de parâmetros que uma função/procedimento pode receber são classificados em passagem por valor e passagem por referência.

Análise o código a seguir.

#include<stdio.h>

void pensar(int a, int b) {
    a = 11;
    b = 12;
}
int main() {
    int a = -11;
    int b = -12;
    pensar(a, b);
    printf("\n a = %d e b = %d", a, b);
    return 0;
}

De acordo com o código apresentado, será impresso na linha 11:

Correto!

No código foi usada a técnica de passagem de parâmetro por valor, ou seja, serão criadas cópias das variáveis a e b para que a função trabalhe. Nesse caso, após o final da execução da função as cópias são liberadas e o valor original das variáveis não é modificado.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Questão 3

Uma função pode receber parâmetros por valor ou por referência. No primeiro caso, são criadas cópias das variáveis na memória, e então o valor original não é alterado. Para trabalhar com passagem por referência é preciso recorrer ao uso de ponteiros, pois são variáveis especiais que armazenam endereços de memória.

Análise o código a seguir:

#include<stdio.h>

void pensar(int* a, int* b) {
    *a = 10;
    *b = 20;
}
int main(){
    int a = -30;
    int b = -40;
    pensar(a, b);
    printf("\n a = %d e b = %d", a, b);
    return 0;
}

De acordo com o código apresentado, será impresso na linha 11:

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Tente novamente...

Esta alternativa está incorreta, leia novamente a questão e reflita sobre o conteúdo para tentar novamente.

Correto!

Nesse código, a função foi criada usando ponteiros pensar(int* a, int* b), e com esse cenário tem-se uma função com passagem de parâmetros por referência, a qual pode alterar o valor original das variáveis. Entretanto, a função pensar() foi invocada sem passar como parâmetro os endereços das variáveis (usando o operador &), ocasionando um erro em tempo de compilação. A forma correta de invocar a função pensar() seria: pensar(&a, &b).

Referências

[C] AULA 60 - Alocação Dinâmica - Parte 1 – Introdução. [S. l.], 5 nov. 2012. 1 vídeo (5 min. 25 s.). Publicado pelo canal Linguagem C Programação Descomplicada. Disponível em: https://goo.gl/ps7VPa. Acesso em: 30 jun. 2016.

ALMEIDA, R.; ZANLORENSSI, G. A evolução do número de linhas de telefone fixo e celular no mundo. Nexo, 2 maio 2018. Disponível em: https://cutt.ly/5jSOpbP. Acesso em: 7 jul. 2018.

COUNTER, L. Lines of code of the Linux Kernel Versions. Disponível em: https://cutt.ly/zjSOt0G. Acesso em: 30 jun. 2018.

CPPREFERENCE. Implicit conversions. Cppreference, [s. l.], [s. d.]. Disponível em: https://cutt.ly/8jS1KWD. Acesso em: 10 jan. 2021.

FEOFILOFF, P. Recursão e algoritmos recursivos. Instituto de Matemática e Estatística da Universidade de São Paulo, 21 maio 2018. Disponível em: https://cutt.ly/OjSOwOH. Acesso em: 2 jan. 2018.

MANZANO, J. A. N. G. Linguagem C: acompanhada de uma xícara de café. São Paulo: Érica, 2015.

MANZANO, J. A. N. G.; MATOS, E.; LOURENÇO, A. E. Algoritmos: técnicas de programação. São Paulo: Érica, 2015.

OLIVEIRA, R. Algoritmos e programação de computadores. Notas de aula. Instituto de Computação da Universidade Estadual de Campinas – UNICAMP, [s. d.]. Disponível em: https://cutt.ly/mjSI75P. Acesso em: 16 jul. 2018.

PIRES, A. A. Cálculo numérico: prática com algoritmos e planilhas. São Paulo: Atlas, 2015.

SOFFNER, R. Algoritmos e programação em linguagem C. São Paulo: Saraiva, 2013.

Bons estudos!

AVALIE ESTE MATERIAL

OBRIGADO PELO SEU FEEDBACK!