Buscar

Funções e Ponteiros em C

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 55 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 55 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 55 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Bruno Jurkovski
Fábio da Fontoura Beltrão
Felipe Augusto Chies
Kauê Soares da Silveira
Lucas Fialho Zawacki
Marcos Vinicius Cavinato
Revisão da Aula 3
� Na última aula aprendemos o que são 
funções. Estas são uma característica 
muito importante da linguagem C.
� Lembrando que funções recebem 
parâmetros, e que estes podem ser 
passados de duas maneiras:
Revisão da Aula 3
� Por valor:
/* Função que retorna o resultado em float
da divisao de a por b */
float divide (float a, float b)
{
return a / (float) b;
}
int main()
{
float x = 2, y = 3;
printf( “%f” , divide (x , y) );
}
Revisão da Aula 3
� Por referência:
/* Função que atribui à variavel resultado
o valor da divisão de a por b */
void divide_ref (float a, float b, float *resultado)
{
*resultado = a / (float) b;
}
int main()
{
float x = 2, y = 3, res;
divide_ref (x , y, &res); // passamos o endereço de res
printf( “%f” , resultado);
}
Revisão da Aula 3
� Outro aspecto importante sobre funções é
que elas possuem o seu próprio escopo.
void perde_tempo ()
{
int n = 0; //n só existe nesse escopo
while (n < 100000)
n++;
}
int main()
{
int n; // não é o mesmo n que declaramos acima
perde_tempo();
}
Ponteiros
Na aula de hoje vamos entender os 
ponteiros. Inicialmente, podem causar 
dúvidas quanto a sua real importância, 
mas com exemplos, ficará fácil de 
compreender seu funcionamento e 
utilidade.
� Toda programação com uma 
linguagem imperativa como o C 
envolve o manuseio de dados 
através de variáveis
� Uma variável, na verdade, é uma 
região de memória específica 
para guardar um determinado 
dado
Introdução
... ...
501
502
503
504
505
506
507
... ...
#include <stdio.h>
int a;
int b[5];
main(){
a = 6;
b[0] = 10;
b[4] = 25;
... 
� Toda programação com uma 
linguagem imperativa como o C 
envolve o manuseio de dados 
através de variáveis
� Uma variável, na verdade, é uma 
região de memória específica 
para guardar um determinado 
dado
Introdução
... ...
501
502
503
504
505
506
507
... ...
#include <stdio.h>
int a;
int b[5];
main(){
a = 6;
b[0] = 10;
b[4] = 25;
... 
� Toda programação com uma 
linguagem imperativa como o C 
envolve o manuseio de dados 
através de variáveis
� Uma variável, na verdade, é uma 
região de memória específica 
para guardar um determinado 
dado
Introdução
#include <stdio.h>
int a;
int b[5];
main(){
a = 6;
b[0] = 10;
b[4] = 25;
... 
... ...
501 6
502
503
504
505
506
507
... ...
� Toda programação com uma 
linguagem imperativa como o C 
envolve o manuseio de dados 
através de variáveis
� Uma variável, na verdade, é uma 
região de memória específica 
para guardar um determinado 
dado
Introdução
#include <stdio.h>
int a;
int b[5];
main(){
a = 6;
b[0] = 10;
b[4] = 25;
... 
... ...
501 6
502 10
503
504
505
506
507
... ...
� Toda programação com uma 
linguagem imperativa como o C 
envolve o manuseio de dados 
através de variáveis
� Uma variável, na verdade, é uma 
região de memória específica 
para guardar um determinado 
dado
Introdução
#include <stdio.h>
int a;
int b[5];
main(){
a = 6;
b[0] = 10;
b[4] = 25;
... 
... ...
501 6
502 10
503
504
505
506 25
507
... ...
Introdução
� Toda variável possui um endereço de memória 
associado. Esse endereço é o local onde a variável está
armazenada em memória.
... ...
501 6
502 10
503
504
505
506 25
507
... ...
Endereço da variável a: 501
Endereço da variável b: 502
Endereço da variável b[0] = 502
Endereço da variável b[3] = 505
Endereço da variável b[4] = 506
Ponteiros
� Variáveis em geral guardam determinados tipos de 
conteúdo específicos (inteiro, ponto flutuante, 
caracter…)
� Um ponteiro é uma variável que contém um endereço 
de memória.
� Esse endereço de memória é geralmente a posição de 
uma outra variável na memória.
� Se uma variável contém o endereço de uma outra, 
então diz-se que a primeira variável aponta para a 
segunda (por isso o nome Ponteiro!)
Tipo de base * Nome da variável ;
O tipo de base é importante para a Aritmética de Ponteiros
Ponteiros - Declaração
Declaração de 
variável:
Declaração de 
ponteiro:
int x;
float j;
char v;
...
int * x;
float * j;
char * v;
...
Ponteiros
... ...
501 506
502
503
504
505
506 12
507
... ...
Neste caso:
Se a variável da posição 501 não 
for ponteiro, então possui valor 
506.
Se for ponteiro, então é do tipo 
inteiro e aponta para a posição 
506(que contém o valor 12).
Ponteiros - Operadores
Existem 2 operadores especiais para ponteiros:
� &
� *
O ‘&’ é um operador unário(ou seja, requer apenas um 
operando), que devolve o endereço na memória de seu 
operando.
O ‘*’ é o complemento do ‘&’: É um operador unário que 
devolve o valor da variável localizada no endereço que 
o segue.
Ponteiros - Operadores
Um exemplo do uso do operador & para extrair o 
endereço de uma variável é a função scanf
int numero;
scanf(“%d”, &numero); 
/* Isso quer dizer: armazene o valor lido no teclado na 
variável cujo endereço eu estou lhe fornecendo */
Ponteiros - Operadores
... ...
501
502
503
504
505
506
507
... ...
#include <stdio.h>
int var1;
int *pont1;
main(){
var1 = 6;
pont1 = &var1;
*pont1 = 30;
... 
Exemplo:
Ponteiros - Operadores
... ...
501 6
502
503
504
505
506
507
... ...
#include <stdio.h>
int var1;
int *pont1;
main(){
var1 = 6;
pont1 = &var1;
*pont1 = 30;
... 
Exemplo:
Ponteiros - Operadores
... ...
501 6
502 501
503
504
505
506
507
... ...
#include <stdio.h>
int var1;
int *pont1;
main(){
var1 = 6;
pont1 = &var1;
*pont1 = 30;
... 
Exemplo:
Ponteiros - Operadores
... ...
501 30
502 501
503
504
505
506
507
... ...
#include <stdio.h>
int var1;
int *pont1;
main(){
var1 = 6;
pont1 = &var1;
*pont1 = 30;
... 
Exemplo:
Ponteiros - Operadores
#include <stdio.h>
main() {
float var0;
int var1;
int *pont1, *pont2;
pont1 = & var1;
pont2 = & var0;
... 
Exemplo de erro:
pont2 é um ponteiro para 
inteiro e var0 é float -
ERRO DE COMPILAÇÃO
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
... ...
501
502
503
504
505
506
507
... ...
Exemplo:
main(){
int a = 8, b = 98;
int *p1, *p2;
p1 = &a;
p2 = &b;
p1 = p2;
...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
... ...
501 8
502
503
504
505
506
507
... ...
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
... ...
501 8
502 98
503
504
505
506
507
... ...
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
... ...
501 8
502 98
503
504
505
506
507
... ...
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
... ...
501 8
502 98
503 501
504
505
506
507
... ...
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
... ...
501 8
502 98
503 501
504 502
505
506
507
... ...
Ponteiros - Atribuição
Ponteiros podem ser atribuídos como uma variável 
qualquer:
int a = 8, b = 98;
int *p1, *p2;
main(){
p1 = &a;
p2 = &b;
p1 = p2;
...
... ...
501 8
502 98
503 502
504 502
505
506
507
... ...
... ...
501 8
502 98
503 502
504 502
505
506
507
... ...
É importante notar que 
mesmo que declaremos 
uma variável após a outra, 
não existe garantia da 
posição em que elas 
estarão na memória. Isto 
está a cargo do 
compilador.
Ponteiros - Atribuição
Ponteiros - Atribuição
� Outra coisa importantíssima de se lembrar 
quando usamos ponteiros é que sempre 
devemos inicializá-los de antemão. Se 
usarmos ponteiros não inicializados, 
podemos acabar acessando posições de 
memória que já estão sendo usadas por 
nosso programa ou que estão protegidaspelo sistema operacional.
� Isso pode resultar em telas como essa:
Ponteiros - Atribuição
Aritmética de Ponteiros
• Existem apenas duas operações aritméticas que podem ser 
usadas com ponteiros: adição e subtração.
• A aritmética de ponteiros é relativa ao seu tipo base, ou seja, 
depende de quantos bytes o tipo ocupa na memória.
Exemplo:
Suponhamos que pont1 esteja apontando para a posição 1000.
Após realizar um pont1++ ele passa a apontar para a posição 
1004*
* Obs.: Atualmente inteiros ocupam 4 bytes de memória!
Aritmética de Ponteiros
• Manipular ponteiros dessa forma pode ser útil, principalmente 
quando estamos tratando de arrays.
• É importante notar que o nome de um array (sem um índice) já
representa o endereço do primeiro elemento do array.
int array_int[5] = {1,2,3,4,5};
float array_float[3] = {1.0,2.3,5.1};
int *p_int = array_int;
float *p_float = array_float;
...
Aritmética de Ponteiros
• Os exemplos a seguir demonstram como é possível manipular 
arrays apenas usando ponteiros.
printf (“%d” , *p_int); // imprime 1, o primeiro elemento do array
printf (“%d” , *(p_int + 1) ); // imprime o 2 o segundo elemento
printf(“%d” , p_int[0] ); // equivalente a *p_int
printf(“%d” , p_int[1] ); // equivalente a *(p_int + 1)
printf(“%f” , *(p_float + 2); // imprime 5.1 *(p_int + 1)
// e agora prestem atenção
printf(“%f” , *(p_float + 12) );
/* note que como nos arrays, podemos “desrespeitar” o tamanho 
usando essa construção * /
...
O ponteiro NULL
• Como já foi dito antes, quando declaramos uma 
variável em C ela começa com valores aleatórios 
(lixo). Para tentar impedir que nossos ponteiros 
sejam usados de maneira danosa para o nosso 
programa, é uma convenção comum em C usar o 
identificador NULL, definido na biblioteca stdlib.h .
• Na realidade o NULL é equivalente a 0. Isso facilita 
testar nossos ponteiros, visto que se ele for NULL ele 
será avaliado como falso em um teste.
O ponteiro NULL
/* Prestem atenção no próximo exemplo, primeiro declaramos dois 
ponteiros para char */
char *pont = NULL,*pont2 = NULL;
char string[100], string2[100];
int escolha = 0;
scanf(“%1d %s”,&escolha,string); //lemos um dígito e uma string
if (escolha != 0) //se o dígito for diferente de 0...
pont = string; // apontamos para a string
scanf(“%1d %s”,&escolha,string2); 
if (escolha != 0)
pont2= string2;
O ponteiro NULL
if (pont != NULL) //testa se já atribuímos pont
printf(“Primeira string: %s” , pont); /* observem que isso irá imprimir a 
variável string, já que pont contém o endereço dela */
if (pont2) // esse teste equivale a pont2 != NULL
printf(“Segunda string: %s” , pont2);
• Como podemos ver, o ponteiro NULL é muito útil 
para evitar erros comuns, decorrentes da não 
inicialização de ponteiros e afins.
Exercícios 
• Faça uma função que recebe uma string e um 
caractere, e retorna um ponteiro para a primeira 
ocorrência do caractere na string, ou NULL caso não 
o encontre.
DICA 1: Se um função deve retornar um ponteiro, ela 
tem que ser declarada da seguinte forma:
tipo* funcao(parametros)
DICA 2: Não se esqueçam que o ‘\0’ é o caractere 
terminador da string.
char * acha_char(char *string, char a) {
char *pont = NULL;
int achou = 0;
while(*string != '\0' && achou == 0) {
if (*string == a) //testa o caractere atual
{ 
pont = string;
achou = 1;
}
else string++;
}
return pont;
}
Resposta
Resposta
int main()
{
char *string = "Lucas Fialho Zawacki";
printf("%s\n", acha_char(string, 'F'));
/* imprime “Fialho Zawacki” */
}
Indireção Múltipla
• Variáveis do tipo ponteiro, também podem apontar 
para outros ponteiros. 
• Para cada novo * na declaração da variável, 
estamos adicionando mais um nível de “indireção”.
• Um exemplo bem simples seria:
int num = 30, *p, **q;
p = &num;
q = &p;
... ...
501 30
502
503
504
505
506
507
... ...
Indireção Múltipla
int num = 30, *p, **q;
p = &num;
q = &p;
... ...
501 30
502
503
504
505
506
507
... ...
Indireção Múltipla
int num = 30, *p, **q;
p = &num;
q = &p;
... ...
501 30
502 501
503
504
505
506
507
... ...
Indireção Múltipla
int num = 30, *p, **q;
p = &num;
q = &p;
... ...
501 30
502 501
503 502
504
505
506
507
... ...
Indireção Múltipla
Indireção Múltipla
• Usar mais do que um nível de ponteiros 
pode ser útil para manipular estruturas mais 
complexas como matrizes multidimensionais, 
embora seja mais recomendado utilizar a 
notação de array.
Ponteiros void
• Qualquer tipo de ponteiro pode ser convertido para 
o tipo (void*) e depois convertido de volta para o seu 
tipo, sem que haja perda de dados.
• Esse tipo de operação será usada, principalmente 
para alocar memória dinamicamente.
Alocação Dinâmica de Memória
• Existem momentos em nossos programas, em que 
precisaremos requisitar memória em tempo de 
execução, por exemplo:
• A criação de uma matriz cujo tamanho é
fornecido pelo usuário.
• A criação de listas com tamanho indefinido.
• A biblioteca stdlib.h nos oferece algumas funções 
para nos facilitar o gerenciamento dessas 
necessidades.
Alocação Dinâmica de Memória
• A função malloc será usada para alocar uma 
quantidade ‘n’ de variáveis de algum tipo.
• Seu protótipo é:
void * malloc (unsigned int num);
float *pont_f;
pont_f = (float*) malloc(sizeof(float) * 30) ;
// alocamos um array de 30 floats
Alocação Dinâmica de Memória
• Aspectos importantes do exemplo anterior:
• A função sizeof(tipo) nos retorna o tamanho em 
bytes do tipo usado como argumento. Ela nos 
será útil para que não precisemos saber o 
tamanho de cada tipo (até porque eles podem 
variar de um computador para outro).
• O ponteiro retornado é do tipo void*, então é
necessário fazer uma conversão para o tipo que 
nós iremos usar.
Alocação Dinâmica de Memória
• Podemos manipular o ponteiro resultante como 
preferirmos, ou seja, usando a notação de arrays ou 
a de ponteiros. 
int i;
for (i = 0; i < 30; i++)
printf(“%f - ” , pont_f[i]);
// imprimimos todos elementos do array
Alocação Dinâmica de Memória
• A função free é usada para liberar a mémoria que 
nós alocamos previamente em nosso programa.
• O protótipo da função é:
free (void* ptr);
free(pont_f);
// qual a importância dessa operação?
Alocação Dinâmica de Memória
• É importante liberar a memória que alocamos 
dinamicamente porque, caso não o façamos, ela 
ficará indisponível para nós até o fim do programa.
Exercício
Crie um programa com a seguinte definição:
O programa deve ter, além da main, uma outra
função void chamada DEVOLVE_PONTEIRO que
recebe um array de inteiros e o tamanho do array e
escreve na tela o maior valor contido nesse array.
Ex.:
Temos o array de tamanho 3 com os valores:
2, 4 e 5;
DEVOLVE_PONTEIRO deve imprimir 5 na tela! 
Ex: void devolve_ponteiro(int *vet, int tam);
Ex. de chamada na main:
int vetor[3] = {1,2,3} , tam = 3;
devolve_ponteiro(vetor, 3);
USAR FOR PARA ACHAR O MAIOR VALOR!

Continue navegando