linguagem c ponteiros -...

50
Linguagem C – ponteiros IF61A/IF71A - Computação 1 Prof. Leonelo Almeida Universidade Tecnológica Federal do Paraná

Upload: vutu

Post on 12-Dec-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Linguagem C – ponteiros

IF61A/IF71A - Computação 1

Prof. Leonelo Almeida

Universidade Tecnológica Federal do Paraná

Até agora ...

• Introdução à linguagem C

▫ ...

▫ Vetores

▫ Matrizes

▫ Funções

▫ Recursão

▫ Registros

Aula de hoje

• E se eu quiser uma função que retorne dois valores. Um inteiro e um ponto flutuante?

Aula de hoje

• E se eu quiser uma função que retorne dois valores. Um inteiro e um ponto flutuante?

▫ Funções retornam somente um valor simples

Aula de hoje

• E se eu quiser uma função que retorne dois valores. Um inteiro e um ponto flutuante?

▫ Funções retornam somente um valor simples

• E se eu quiser uma função que altere as variáveis simples que forem passadas como parâmetro?

Aula de hoje

• E se eu quiser uma função que retorne dois valores. Um inteiro e um ponto flutuante?

▫ Funções retornam somente um valor simples

• E se eu quiser uma função que altere as variáveis simples que forem passadas como parâmetro?

▫ Funções não alteram as variáveis externas simples passadas como parâmetro

Aula de hoje

Ponteiros

Passagem por Valor e por Referência

Ponteiros

• São tipos especiais de dados usados para armazenar endereços de memória

• Armazena o endereço de memória de outra variável do tipo informado na declaração

• Declaração: tipo *nome_variavel;

• Exemplo: int *memA;

float *memB;

Armazena o endereço de memória de uma variável do tipo int

Armazena o endereço de memória de uma variável do tipo float

Operadores relacionados a ponteiros

• O operador &

▫ Retorna o endereço de memória de uma variável. Exemplo: int *memA;

int a=90;

memA = &a;

• O operador *

▫ Retorna o conteúdo do endereço apontado. Exemplo: printf(“%d”, *memA);

Organização

Endereço Valor

320954354 Abc

320954355 30

320954356 1

320954357 12e4545

320954358 90

320954359

a memA Memória

• Quando você usa a variável “a”, o programa retorna o valor contido na memória

• Quando você usa a variável “memA”, o programa retorna o endereço de memória

Exemplo #include <stdio.h>

int main(void) {

int *memA;

int a=90;

memA = &a;

printf(" %d --- %d", *memA, memA);

*memA = a;

printf("\n %d --- %d", *memA, memA);

memA = a;

printf("\n %d --- %d", *memA, memA);

return 0;

}

O que será impresso na tela?

Exemplo #include <stdio.h>

int main(void) {

int *memA;

int a=90;

memA = &a;

printf(" %d --- %d", *memA, memA);

*memA = a;

printf("\n %d --- %d", *memA, memA);

memA = a;

printf("\n %d --- %d", *memA, memA);

return 0;

}

90 --- um endereço

90 --- um endereço

Erro em tempo de execução: Segmentation fault

Exemplo 2

#include <stdio.h>

int main(void){

int b;

int *c;

b=10;

c=&b;

*c=11;

printf("%d",b);

}

O que será impresso na tela?

Exemplo 2

#include <stdio.h>

int main(void){

int b;

int *c;

b=10;

c=&b;

*c=11;

printf("%d",b);

}

11 Pois ambas as

variáveis apontam para o mesmo endereço

de memória

Exemplo 3

#include <stdio.h>

int main(void){

int num, q=1;

int *p;

num=100;

p = &num;

q = *p;

printf(“%d",q);

}

O que será impresso na tela?

Exemplo 4

...

int a, b;

int *c;

b = 10;

*c = 13;

...

Em que endereço a constante será armazenada?

Exemplo 4

...

int a, b;

int *c;

b = 10;

*c = 13;

...

Correto seria se, antes da atribuição da constante, um endereço fosse atribuído a “c”

...

int a, b;

int *c;

b = 10;

c = &a;

*c = 13;

...

Atenção

...

int a, b, c;

int *d;

b = 10;

c = 5;

d = &c;

a = b * d;

...

O operador * é usado em ponteiros e multiplicações

Atenção

...

int a, b, c;

int *d;

b = 10;

c = 5;

d = &c;

a = b * d;

...

O bloco à esquerda dará um erro de compilação. O correto seria ...

...

int a, b, c;

int *d;

b = 10;

c = 5;

d = &c;

a = b * (*d);

...

Exemplo 5

#include <stdio.h>

int main(void){

double b,a;

int *c;

b=10.89;

c=&b;

a=*c;

printf("%lf\n",a);

}

O que será impresso na tela?

Exemplo 5

#include <stdio.h>

int main(void){

double b,a;

int *c;

b=10.89;

c=&b;

a=*c;

printf("%lf\n",a);

}

Atribuição de tipos de dados incorreta.

Mensagem do compilador:

warning: assignment from incompatible pointer type

Vai imprimir um número diferente de 10.89

Resumindo ...

• Três usos para o operador *

• Na declaração de ponteiros:

▫ Exemplo: int *pont;

• No acesso ao valor apontado pelo ponteiro:

▫ Exemplo: printf(“%d”, *pont);

• Multiplicação de números:

▫ Exemplo: 10 * (*pont);

Indireção múltipla • Podemos ter um ponteiro que aponta para outro

ponteiro que aponta para um endereço. Isso também podem ser expandido para diversos níveis de indireção

• Apesar de possível é um conceito raro de ser usado e propenso a erros

• Exemplo: float **peso;

endereço endereço valor

ponteiro valor ponteiro

Operações com ponteiros int main(void){

double *a,*b, c, d;

b=&c;

a=&d;

if(b < a)

printf("\nO endereço apontado por b é menor: %p e %p", b, a);

else if(a < b)

printf("\nO endereço apontado por a é menor:%p e %p", a, b);

else if(a == b)

printf("Mesmo endereço");

if(*a == *b)

printf("Mesmo conteúdo: %lf", *a);

}

Operações com ponteiros int main(void){

double *a,*b, c, d;

b=&c;

a=&d;

if(b < a)

printf("\nO endereço apontado por b é menor: %p e %p", b, a);

else if(a < b)

printf("\nO endereço apontado por a é menor:%p e %p", a, b);

else if(a == b)

printf("Mesmo endereço");

if(*a == *b)

printf("Mesmo conteúdo: %lf", *a);

}

Para imprimir um ponteiro usamos a

máscara %p.

Operações com ponteiros

• Enquanto o ponteiro não estiver associado a um endereço é uma boa prática atribuir o valor NULL a ele

• Isto facilita as comparações para se saber se o ponteiro já tem um endereço válido associado

• Exemplo: ...

double *a = NULL, *b = NULL;

a = &c;

if (a != NULL) {

...

Passagem de parâmetros

• Passagem por valor

▫ Variáveis e constantes passadas por parâmetro para funções têm seus valores copiados para os parâmetros das funções (que são locais)

▫ Alterações nos parâmetros dentro da função não alteram as variáveis que foram passadas às funções

Exemplo de passagem por valor

...

void troca(int x, int y) {

int aux;

aux = x;

x = y;

y = aux;

}

int main(){

int x=4, y=5;

troca(x,y);

printf (“x = %d e y = %d”, x, y);

}

Exemplo de passagem por valor

...

void troca(int x, int y) {

int aux;

aux = x;

x = y;

y = aux;

}

int main(){

int x=4, y=5;

troca(x,y);

printf (“x = %d e y = %d”, x, y);

}

Será impresso: “x = 4 e y = 5”

Isso porque a troca ocorreu

com variáveis locais à função troca e, portanto, não afetam as variáveis da função main.

Passagem de parâmetros

• Passagem de argumentos por referência

▫ Em C só existe passagem de parâmetros por valor

▫ Em outras linguagens pode haver a passagem de parâmetros por referência

▫ Nesse tipo de passagem valores por referência podem ser alterados pela função que foi chamada

Passagem de parâmetros

• Algo parecido pode ser feito em C utilizando ponteiros

▫ Para isso basta passar como argumento de uma função o endereço da variável e não o seu valor

▫ Assim, alterações no valor contido no endereço que forem feitas pela função chamada afetarão a variável mesmo fora da função

Passagem de argumentos por referência #include <stdio.h>

void troca(int *end_x, int *end_y) {

int aux;

if(end_x != NULL && end_y != NULL){

aux = *end_x;

*end_x = *end_y;

*end_y = aux;

}

}

int main(){

int x=4, y=5;

troca(&x, &y);

printf("x = %d e y = %d\n", x, y);

}

Imprimirá: “x = 5 e y = 4”

Exemplo #include <stdio.h>

void maxAndMin(int vet[], int tam, int *min, int *max);

int main(){

int v[] = {10, 80, 5, -10, 45, -20, 100, 200, 10};

int min, max;

maxAndMin(v, 9, &min, &max);

printf("O menor é: %d \nO maior é: %d \n",min, max);

}

void maxAndMin(int vet[], int tam, int *min, int *max){

int i;

*max = vet[0];

*min = vet[0];

for(i = 0; i < tam; i++){

if(vet[i] < *min)

*min = vet[i];

if(vet[i] > *max)

*max = vet[i];

}

}

Ponteiros e Vetores

• Um vetor ocupa um espaço contíguo de memória do tamanho do tipo de dados do vetor multiplicado pelo número de posições de vetor

• O vetor funciona como um ponteiro que aponta para a primeira posição

• Por isso que vetores passados como argumento podem ser alterados pelas funções chamadas

Ponteiros e Vetores

• Como uma variável do tipo vetor é um endereço, é possível atribuí-la a um ponteiro. Exemplo: int a[] = {1, 2, 3, 4, 5};

int *p;

p = a;

• Após a atribuição é possível usar o ponteiro p como um vetor. Exemplo: for(i=0; i<5; i++)

p[i] = i*i;

Atenção

• Vetores ocupam endereços fixos de memória

• Não é possível atribuir um endereço a um vetor

• Exemplo errado: int a[] = {1, 2, 3, 4, 5}, b[5], i;

b = a;

• Exemplo correto: int a[] = {1, 2, 3, 4, 5}, *b, i;

b = a;

Ponteiros e Registros

#include <stdio.h>

struct Coordenada{

double x;

double y;

};

typedef struct Coordenada Coordenada;

int main(){

Coordenada c1, c2, *c3;

c3 = &c1;

...

Ponteiros e registros #include <stdio.h>

struct Coordenada{

double x;

double y;

};

typedef struct Coordenada Coordenada;

int main(){

Coordenada c1, c2, *c3;

c3 = &c1;

c1.x = -1;

c1.y = -1.5;

c2.x = 2.5;

c2.y = -5;

*c3 = c2;

printf("Coordenadas de c1: (%lf,%lf)\n",c1.x, c1.y);

}

O que será impresso na tela?

Acessando valores de um ponteiro de

registro • Duas maneiras: (*ponteiroReg).campo;

ponteiroReg->campo;

• Exemplo: Coordenada c1, *c3;

c3 = &c1;

c3->x = 1.5;

(*c3).y = 2.5;

Exemplo int main(){

Coordenada c1, c2, *c3, *c4;

c3 = &c1;

c4 = &c2;

c1.x = -1;

c1.y = -1.5;

c2.x = 2.5;

c2.y = -5;

(*c3).x = 1.5;

(*c3).y = 1.5;

c4->x = -1;

c4->y = -1;

printf("Coord. de c1: (%lf,%lf)\n",c1.x, c1.y);

printf("Coord. de c2: (%lf,%lf)\n",c2.x, c2.y);

}

O que será impresso na tela?

Exemplo • Cadastro de alimentos. O programa deve ter

opções para incluir/excluir um alimento do cadastro.

struct Food{

char nome[80];

double pesoMedio;

double calorias;

short usado;

};

typedef struct Food Food;

• Usaremos um vetor para cadastro dos alimentos.

• O campo “usado” de Food, serve para indicar se no vetor uma posição está em uso (1) ou não (0).

Exemplo - Funções

• void leFood(Food *f);

▫ Lê dados de um alimento passado como ponteiro.

• void imprimeFood(Food f);

▫ Imprime dados de um alimento. • void imprimeFoods(Food vet[], int tam);

▫ Imprime dados de um cadastro inteiro de alimentos.

• int insereFood(Food vet[], int tam, Food f);

▫ Insere um alimento no cadastro se houver espaço! • int removeFood(Food vet[], int tam, char nome[]);

▫ Remove um alimento pelo nome, se este estiver cadastrado!

Exemplo

void leFood(Food *f){

printf(" ------Lendo Alimento-------\n");

printf("Digite o nome do alimento:");

scanf("%s", f->nome);

printf("Digite o peso médio do alimento:");

scanf("%lf", &(f->pesoMedio));

printf("Digite a quantidade de calorias do alimento:");

scanf("%lf", &(f->calorias));

}

Exemplo

void imprimeFood(Food f){

printf(" \n\n--- Imprimindo Alimento ---\n");

printf("Nome: %s\n",f.nome);

printf("Peso médio: %lf\n", f.pesoMedio);

printf("Calorias: %lf\n", f.calorias);

}

void imprimeFoods(Food vet[], int tam){

int i;

for(i=0; i<tam; i++){

if(vet[i].usado == 1)

imprimeFood(vet[i]);

}

}

Exemplo

int insereFood(Food vet[], int tam, Food f){

int i;

for(i=0; i<tam; i++){

if(vet[i].usado == 0){

vet[i] = f;

vet[i].usado = 1;

return 1;

}

}

return 0; //cadastro está cheio

}

Exemplo

int removeFood(Food vet[], int tam, char nome[]){

int i;

for(i=0; i<tam; i++){

//strcmp retorna 0 se iguais

if( strcmp(vet[i].nome , nome) == 0){

vet[i].usado = 0;

return 1;

}

}

return 0; //alimento não cadastrado

}

Atividades

• Crie a função principal do cadastro de alimentos, de maneira a utilizar todas as funções apresentadas.

▫ Considere que o usuário é quem escolhe a quantidade máxima de alimentos a serem armazenados.

Atividades

• Escreva uma função que recebe um vetor de inteiros vet e retorna a média dos valores de vet e o valor mais frequente (i.e. a moda estatística)

• Exemplo: vet = {1,2,3,3,5,2,10,2,4,2}, media=3.4,

moda=2

• Escreva uma função que recebe uma string s1, contendo um nome completo e retorna o primeiro nome firstn e o último lastn.

Atividades

• Crie um programa de anotações de aula. O programa deve ter um registro do tipo: ▫ Código do tema: int ▫ Tema da aula: string ▫ Observações do aluno: string ▫ Nível de dificuldade: int (1-3), onde 1 significa

fácil, 2 - normal e 3 – difícil.

• O aluno pode cadastrar até 15 temas (registros) por disciplina. O aluno deve ter a opção de cadastrar, apagar e listar os temas cadastrados.

Atividades

• Escreva uma função “intercala” que recebe duas strings s1 e s2 e retorna uma string s3 que é a intercalação das duas primeiras

• Exemplo: ▫ s1 = “JÃSLA”, s2 = “OOIV”, s3 = “JOÃOSILVA”

• Agora faça uma nova versão de intercala que

recebe dois vetores v1 e v2 de inteiros ordenados e retorna um terceiro vetor v3 também ordenado que contém os valores de v1 e v2. Obs.: não se esqueça de verificar se o vetores estão ordenados.

• Exemplo: ▫ v1 = {1,4,9,11}, v2 = {2,3,7,10, 13}, v3 =

{1,2,3,4,7,9,10,11,13}