Informática e Cultura Geral
Passagem de Parâmetros por Referência, Ponteiros e Alocação Dinâmica
Prof. Carlos Andrés Ferrero
Funções
Classificação das funções (sub-rotinas)
● Sem passagem de parâmetros e sem retorno
● Com passagem de parâmetros e sem retorno
● Sem passagem de parâmetros e com retorno
Funções
Sem passagem de parâmetros e sem retorno
#include<stdio.h>
void soma (){
int a, b, c;
printf("\nDigite o primeiro numero: "); scanf("%d%*c",&a);
printf("\nDigite o segundo numero: "); scanf("%d%*c",&b); c = a + b; printf("Resultado: %d",c); } int main(){ soma(); return 0; }
Funções
Com passagem de parâmetros e sem retorno
#include<stdio.h>
void resultadoSoma (int a, int b){ int c = a + b;
printf("Resultado: %d",c); }
int main(){ int a, b;
printf("\nDigite o primeiro numero: "); scanf("%d%*c",&a);
printf("\nDigite o segundo numero: "); scanf("%d%*c",&b);
resultadoSoma(a,b); return 0;
}
#include<stdio.h>
Funções
Sem passagem de parâmetros e com retorno
#include<stdio.h>
int soma (){ int a, b;
printf("\nDigite o primeiro numero: "); scanf("%d%*c",&a);
printf("\nDigite o segundo numero: "); scanf("%d%*c",&b); return a + b; } int main(){ int c = soma(); printf("Resultado: %d",c); return 0; }
Funções
Com passagem de parâmetros e com retorno
#include<stdio.h>
int soma (int a, int b){ return a + b;
}
int main(){ int a, b;
printf("\nDigite o primeiro numero: "); scanf("%d%*c",&a);
printf("\nDigite o segundo numero: "); scanf("%d%*c",&b);
int c = soma(a,b);
printf("Resultado: %d",c); return 0;
Passagem de parâmetros
A passagem de parâmetros pode ser por:
● Valor: quando é realizada uma cópia do conteúdo da
variável passada como parâmetro para a área de memória destinada ao uso da função;
● Referência: quando os valores dos parâmetros
passados a uma função são endereços de memória que apontam aos locais das variáveis.
Passagem de parâmetros
Dessa forma é possível uma economia de memória?
Passagem por Valor Passagem por Referência #include<stdio.h>
int soma (int a, int b){ return a + b; } int main(){ int a, b; scanf("%d%*c",&a); scanf("%d%*c",&b); int c = soma(a,b); printf("Resultado: %d",c); return 0; } #include<stdio.h>
int soma (int * a, int * b){ return (*a) + (*b); } int main(){ int a, b; scanf("%d%*c",&a); scanf("%d%*c",&b); int c = soma(&a,&b);
printf("Resultado: %d",c); return 0;
Passagem de parâmetros
Vetor como parâmetro
#include<stdio.h>
double media (double vetor[], int n){ inti; doublesoma = 0.0; for (i = 0; i < n; i++) soma += vetor[i]; return (soma / n); } int main(){ int n; scanf("%d%*c",&n); doublevalores[n]; inti; for (i = 0; i < n; i++)
scanf("%lf%*c",&valores[i]); doublem = media(valores,3); printf("\nMedia: %.2lf",m); return0;
Passagem de parâmetros
Exercícios (usando double)
● Faça uma função que leia n valores e armazene em
um vetor vet.
● Faça uma função que mostre n valores de um vetor
vet na tela.
● Faça uma função que copie n valores de um vetor
src para um vetor dest.
void vetread(double vet[], int n)
Passagem de parâmetros
Observação:
● Ao utilizar como parâmetro vet[] estamos na
realidade enviando o endereço de memória da primeira posição do vetor.
● Por exemplo, se vet inicia na posição 0xbff60a40
Posição de vet Endereço Conteúdo
0 0xbff60a40 ?
1 0xbff60a48 ?
2 0xbff60a50 ?
... ... ...
Passagem de parâmetros
Observação:
● Por esse fato, enviar para vetread o vetor valores
ou o endereço da primeira posição do vetor, tem o mesmo efeito.
● Em código
void vetread(double vet[], int n){ int i;
for (i = 0; i < n; i++)
scanf("%lf%*c",&vet[i]); } int main(){ int n; scanf("%d%*c",&n); double valores[n]; vetread(valores,n);
void vetread(double vet[], int n){ int i;
for (i = 0; i < n; i++)
scanf("%lf%*c",&vet[i]); }
int main(){ int n;
scanf("%d%*c",&n); double valores[n];
Endereços de Memória
Para mostrar um endereço de memória de uma
variável usando printf devemos usar o marcador %p
Exercício:
● Implementar uma função que mostre, além de seus
valores, valor o endereço de memória de um vetor de double. Use a seguinte assinatura de função.
● Resultado esperado
void vetShowAddress(double vet[], int n)
Vetor &vet: 0xbff60a40
v[0]: 2.40 &v[0]: 0xbff60a40 v[1]: 3.50 &v[1]: 0xbff60a48 v[2]: 2.10 &v[2]: 0xbff60a50
Ponteiros
Os ponteiros são endereços de memória que apontam para um local onde está, de fato, a informação de
interesse. 0xbff60a40 20 int ptrIdade idade #include<stdio.h> int main(){ int idade;
int * ptrIdade = &idade; idade = 5;
printf("\nValor: %d; Endereço: %p",(*ptrIdade),ptrIdade); return 0;
Ponteiros
Ponteiro para struct utilizando TPonto3D
#include<stdio.h> typedef struct { double x; double y; double z; } TPonto3D;
void lerPonto3D1(TPonto3D * ptrPonto3D){ scanf("%lf%*c", &(ptrPonto3D->x) );
scanf("%lf%*c", &(ptrPonto3D->y) ); scanf("%lf%*c", &(ptrPonto3D->z) ); }
int main(){
TPonto3D ponto3D;
lerPonto3D1(&ponto3D);
printf("\nValor: %.2lf",ponto3D.x);
printf("\nEnd.: %p",&ponto3D.x);
return 0; } #include<stdio.h> typedef struct { double x; double y; double z; } TPonto3D;
void lerPonto3D2(TPonto3D * ptrPonto3D){ scanf("%lf%*c", &((*ptrPonto3D).x));
scanf("%lf%*c", &((*ptrPonto3D).y)); scanf("%lf%*c", &((*ptrPonto3D).z)); }
int main(){
TPonto3D ponto3D;
lerPonto3D1(&ponto3D);
printf("\nValor: %.2lf",ponto3D.x);
printf("\nEnd.: %p",&ponto3D.x);
return 0; }
Ponteiros
Temos dois símbolos importantes para lembrar:
● Símbolo &: lê-se “Endereço de”
● Símbolo *: lê-se “Para onde aponta”
Exercício:
● Desenvolva uma função que retorne a Distância
Euclidiana entre dois pontos p1 e p2. Assinatura: double distanciaEuclidiana3D( TPonto3D * ptrPonto3D1,
Ponteiros
Implemente uma função para fazer uma cópia
de uma string.
Implemente uma função para fazer uma cópia
de n caracteres de uma string.
void strcpy(char *dest, char *src)
Ponteiros
Os ponteiros também podem ser incrementados e decrementados como outros variáveis numéricas inteiras (int, byte, long, etc), usando ++ e --.
Pense e explique a seguinte implementação de strcpy
void strcpy(char *dest, char *src)
{
while(*dest++ = *src++);
Alocação Dinâmica
O conceito de ponteiros leva a uma diferenciação entre alocação de memória: estática e dinâmica.
Primeiramente, alocar memória consiste em reservar um espaço de memória para armazenar um valor ou um conjunto de valores.
Quando declaramos em tempo de programação uma variável, um vetor (mesmo em tempo de execução) essa memória é alocada e a estrutura não poderá mudar o seu tamanho.
Alocação Dinâmica
Há situações em que não sabemos quantos registros serão definidos durante a execução do programa e, inclusive, se esses registros poderão set todos armazenados no
segmento de dados ou de pilha. Vejamos a estrutura da
memória de um programa em C
Alocação Dinâmica
Existe uma área de memória que podemos utilizar para alocar memória em tempo de execução, que é a Heap. Essa memória é importante, pois o segmento de dados é muito pequeno para armazenar volumes de dados
maiores e o segmento de pilha pode sobrescrever (mui provavelmente) dados alocados na execução de outras subrotinas.
Funções para alocação dinâmica de memória:
● malloc
Alocação Dinâmica
Função malloc:
● Recebe como parâmetro o tamanho do bloco de
memória, em bytes, que serão alocados na Heap.
● Retorna o endereço de memória do inicio do bloco
alocado. #include <stdio.h>
#include <stdlib.h>
int main (){ int n;
char * str;
printf ("Tamanho da string: "); scanf ("%d", &n);
str = (char*) malloc ( sizeof(char) * (n+1) ); if (str==NULL) exit (1);
// Uso de str como string
Alocação Dinâmica
Função calloc:
● Recebe como parâmetro uma quantidade de
unidades a serem alocadas e o tamanho de cada.
● Retorna o endereço de memória do inicio do bloco
alocado. #include <stdio.h>
#include <stdlib.h>
int main (){ int n;
char * str;
printf ("Tamanho da string: "); scanf ("%d", &n);
str = (char*) calloc ( (n+1), sizeof(char) ); if (str==NULL) exit (1);
// Uso de str como string
free (str); return 0; }
Alocação Dinâmica
Exercícios:
● Aloque dinamicamente um conjunto de 10 pontos
3D e preencha os seus valores x, y e z, com valores aleatórios.
● Considere esses 10 pontos como uma sequência,
calcule o comprimento dos 9 segmentos entre cada par de pontos sequenciais e mostre os