A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

ponteiros Estrutura de Dados Prof. André Cypriano M. Costa

Apresentações semelhantes


Apresentação em tema: "ponteiros Estrutura de Dados Prof. André Cypriano M. Costa"— Transcrição da apresentação:

1 ponteiros Estrutura de Dados Prof. André Cypriano M. Costa

2 introdução O correto entendimento e uso de ponteiros é crítico para uma programação bem-sucedida em C. Existem 03 motivos para isso: Ponteiros fornecem os meios pelos quais as funções podem modificar seus argumentos Eles são usados para suportar as rotinas de alocação dinâmica de C O uso de ponteiros pode aumentar a eficiência de certas rotinas

3 introdução Ponteiros são um dos aspectos mais fortes e perigosos de C.
Por exemplo: Ponteiros não-inicializados podem provocar uma quebra do sistema. Ponteiros podem gerar erros que são muito difíceis de encontrar.

4 O que são ponteiros? Um ponteiro é uma variável, cujo valor é um endereço de memória, que faz referência à posição de outra variável na memória. Diz-se que: “A primeira variável aponta para a segunda”. 1005 1000 1001 1002 1003 1004 1006 1007 *p

5 Variáveis ponteiros Para uma variável ser do tipo ponteiro, ela deve ser declarada como tal, ou seja, deve possuir um * na sua declaração. Exemplo: int* valor; OU int *valor; O tipo base do ponteiro (int, no exemplo) define o tipo de variável que o ponteiro pode apontar. A princípio qualquer tipo de ponteiro pode apontar para qualquer lugar na memória, mas é importante declarar o ponteiro corretamente para evitar erros!

6 Operadores de ponteiros
Existem 02 operadores especiais para ponteiros: * e &. O & devolve o endereço na memória da variável. Exemplo: mem = &contador //coloca em mem o endereço da memória que contém a variável contador. Leia o operador & como “o endereço de” (aponta para). Logo, pelo exemplo anterior, “mem recebe o endereço de contador” (mem aponta para contador). contador está na posição de memória 1234 e contém o valor 900. Que valor será armazenado em mem?

7 Operadores de ponteiros
O segundo operador de ponteiro é o *, que é o complemento de &. Ele devolve o valor da variável. Exemplo: x = *mem; // Qual vai ser o valor de x? x vai ter o valor 900, porque 900 é o valor armazenado na posição de memória 1234, que é o endereço armazenado em mem. Se mem aponta para contador, o conteúdo de contador é atribuído a x. Leia o operador * como “conteúdo da variável apontada por”. Logo, pelo exemplo anterior, “x recebe o valor que está no endereço mem” (x recebe o conteúdo de mem).

8 Operadores de ponteiros
OBS.: Não confundir o * com o sinal de multiplicação e nem o & com o AND lógico (&&). As variáveis ponteiros devem sempre apontar para o tipo de dado correto. O compilador não gera nenhum erro, mas o programa não executa corretamente.

9 Expressões com ponteiros
Atribuição de Ponteiros: #include<stdio.h> int main() { int x; // cria uma variável inteira int *p1, *p2; // cria dois ponteiros para inteiros p1 = &x; // p1 recebe o endereço de x na memória p2 = p1; // p2 recebe o valor que está em p1 printf(“%d\n”, p2); return 0; }

10 Expressões com ponteiros
Aritmética de Ponteiros: Existem apenas 02 operações aritméticas que podem ser usadas com ponteiros: Adição e Subtração. Exemplo: int *p1; // Suponha que p1 aponta para a posição de memória p1++; // p1 aponta para a posição de memória 2504 E se ao invés de p1++ fosse feito p--? p1--; // p1 aponta para a posição de memória 2496 Cada vez que um ponteiro é incrementado ou decrementado, ele aponta para a posição de memória do próximo elemento do seu tipo.

11 Expressões com ponteiros
Aritmética de Ponteiros: Exemplo: char *ch = 2500; int *in = 2500; ch ch+1 ch+2 ch+3 ch+4 ch+5 ch+6 ch+7 2500 2501 2502 2503 2504 2505 2506 2507 Memória in in+1

12 Expressões com ponteiros
Aritmética de Ponteiros: Exemplo: p1 = p1 + 12; // p1 aponta para o 12º elemento adiante do seu tipo. Operações que NÃO existem sobre ponteiros: Multiplicação e divisão, e p1 = p ; // Soma ou subtração de float ou double.

13 Expressões com ponteiros
Comparação de Ponteiros: É possível compara 02 ponteiros em uma expressão relacional. A comparação envolve: == , < , > , e suas variações. Comparações são usadas quando 02 ou mais ponteiros apontam para um objeto comum. Exemplo: Uma pilha. Compara-se para saber se a pilha está cheia ou vazia.

14 Ponteiros e vetores / Matrizes
Existe uma relação bem estreita entre ponteiros e vetores/matrizes. Considere o exemplo a seguir: Exemplo: char str[80], *p1; p1 = str; Neste exemplo, p1 foi inicializado com o endereço do primeiro elemento da matriz str. Para acessar o 5º elemento pode-se fazer: str[4] OU *(p1 + 4) OU p[4]

15 Ponteiros e vetores / Matrizes
Exemplo: #include<stdio.h> int main() { char str[10], *p; // cria uma string e um ponteiro para ela scanf("%s", str); // lê a string a partir do teclado p = str; // faz o ponteiro apontar para a string // imprime o 5o. caracter da string de 3 formas diferentes printf("STR[4]: %c\n", str[4]); printf("*(p + 4): %c\n", *(p + 4)); printf("p[4]: %c\n", p[4]); return 0; }

16 Ponteiros e vetores / Matrizes
Assim, para acessar os elementos de uma matriz, pode-se Usar a indexação de vetores (1º caso) ou Usar a aritmética de ponteiros (2º caso). A aritmética de ponteiros é mais eficiente e é mais utilizada, entretanto a indexação parece ser mais intuitiva. Vetor de ponteiros: Ponteiros podem ser organizados em matrizes. Exemplo: Declaração de um vetor de ponteiros int* x[10]; // Declara um vetor de ponteiros para int de tamanho 10

17 Indireção múltipla É muito comum em C ter um ponteiro que aponta para outro ponteiro que aponta para o valor final. Essa situação é chamada de indireção múltipla ou ponteiro para ponteiros. Observe a figura a seguir:

18 Indireção múltipla

19 Indireção múltipla Pode-se ter vários ponteiros para ponteiros, mas isso não é comum e nem muito recomendado, pois é propensa a erros. Para declarar um ponteiro para ponteiro, usa-se um * adicional na frente do nome da variável. Por exemplo: // Declara um vetor que aponta para strings char **vetorString; Equivalente a: char *vetorString[10];

20 Inicialização de ponteiros
Ao declarar um ponteiro, é preciso atribuir-lhe um valor antes de utilizá-lo. Caso contrário um erro acontecerá. Um ponteiro que atualmente não aponta para nada receber o valor nulo (NULL). Assim, qualquer ponteiro que é NULL não aponta para nada e não deve ser usado. Um ponteiro null é muito usado para demarcar o fim de alguma estrutura de dados. //Inicializa com null um ponteiro para inteiro int* i = NULL;

21 Variáveis (revisão!) O que é uma variável? Onde declarar as variáveis?
O que são variáveis locais? O que variáveis globais?

22 Escopo das variáveis Exemplo: void func2() {
int count; // variavel local for(count = 1; count < 10; count++) printf("%d\n", count); } int main() { // inicializa o valor da var. global count = 100; // cria e inicializa a var. local int x = 50; // chama a função func1() func1(x); return 0; Exemplo: #include<stdio.h> int count; // variável global void func1(int y) { int x = y; // temp recebe o valor de count int temp = count + y; // chama a função func2() func2(); // imprime o valor de count printf("Count eh %d\n", count); }

23 Variáveis estáticas x variáveis dinâmicas
Até o presente momento, lidamos com variáveis que tiveram de ser criadas antes de se executar um programa. São variáveis que existem o tempo todo (enquanto o programa está em execução), ou seja, são variáveis estáticas. Portanto, a alocação de memória para esse tipo de variável é feita antes da execução do programa (em tempo de compilação).

24 Variáveis estáticas x variáveis dinâmicas
Quando usar variáveis estáticas e variáveis dinâmicas? Variáveis dinâmicas são usadas quando o programa manipula grandes quantidades de dados e essa quantidade é muito variável. Além do mais, usam-se variáveis dinâmicas em programas que são executados em dispositivos que possuem pouca memória (ex: celular, palmtop, etc.). Portanto, as vantagens de se utilizar variáveis dinâmicas são: Economizar memória; e Evitar desperdício da mesma.

25 Variáveis estáticas x variáveis dinâmicas
Quando usar variáveis estáticas e variáveis dinâmicas? A grande desvantagem das variáveis estáticas é o fato de que uma vez criada, o espaço de memória que elas ocupam não pode mais ser alterado. As variáveis dinâmicas podem ser criadas e/ou destruídas durante a execução de um programa, e esta é a grande vantagem delas sobre as estáticas.

26 variáveis estáticas x variáveis dinâmicas
Como declarar variáveis dinâmicas? As variáveis dinâmicas podem ser obtidas através de um tipo pré-definido de variável que em C é chamada de Ponteiro (pointer). A declaração de variáveis dinâmicas é chamada de Alocação Dinâmica, que é o meio pelo qual um programa pode obter memória enquanto está em execução. As variáveis globais são alocadas em tempo de compilação. Variáveis locais usam a pilha. (Mas nenhuma das duas pode ser acrescentada durante o tempo de execução).

27 variáveis estáticas x variáveis dinâmicas
Como declarar variáveis dinâmicas? As variáveis dinâmicas são alocadas pelo sistema de alocação dinâmica e ficam armazenadas na heap do programa. A heap é uma região livre que está entre o programa, a área de armazenamento permanente e a pilha. A parte mais importante do sistema de alocação dinâmica são as funções de malloc() e free() (apesar de existirem outras). Essas funções operam sobre a heap e estão na biblioteca stdlib.h.

28 Alocação dinâmica Malloc()  Aloca memória.
void* malloc(TAM_EM_BYTES_MEM); O espaço de memória alocado pode ser atribuído a qualquer variável do tipo ponteiro (void*). Essa variável recebe a primeira posição de memória alocada do heap. Se não há memória disponível, ocorre uma falha de alocação e a função devolve NULL.

29 Alocação dinâmica Exemplo: Aloca 1000 bytes de espaço
Aloca espaço para 50 inteiros

30 Alocação dinâmica Operador sizeof():
sizeof() é um operador que retorna o tamanho, em bytes, de uma variável. Importância desse operador  gerar código portátil!

31 Alocação dinâmica Free()  libera memória, ou seja, é o oposto do malloc(). Devolvida a memória, ela pode ser utilizada pelo malloc() novamente. void free(void *p); p é uma variável do tipo ponteiro para memória alocada anteriormente pelo malloc(). O sistema de alocação dinâmica é usado junto com ponteiros para suportar uma variedade de estruturas de dados de programas, como listas encadeadas e árvores binárias.

32 Alocação dinâmica Exemplo: #include<stdio.h>
#include<stdlib.h> int main() { // aloca uma string de tamanho 20 char *str = (char*)malloc(20 * sizeof(char)); printf("Digite uma palavra: "); scanf("%s", str); // lê a string digitada no teclado printf("Palavra digitada: %s\n", str); // imprime a string free(str); // desaloca o espaço reservado para a string return 0; }

33 Operador . E  Os operadores . (ponto) e  (seta) referenciam campos de estruturas e uniões. Estruturas e uniões são tipos de dados compostos que podem ser referenciados segundo um único nome. O operador ponto é usado quando se está referenciando a estrutura real. O operador seta é usado quando um ponteiro para a estrutura é usado.

34 Operador . E  Exemplo: typedef struct empregado { char nome[80];
int idade; float salario; } Empregado;

35 Operador . E  Exemplo: // Criando uma struct sem usar ponteiros
Empregado emp; // Criando uma struct usando ponteiros Empregado *p = &emp; OU Empregado *p = (Empregado*)malloc(sizeof(Empregado));

36 Operador . E  Para atribuir o valor 3500 para o campo salario da estrutura emp, basta escrever: emp.salario = 3500; A mesma atribuição usando um ponteiro para emp é: p->salario = 3500;

37 Operador . E  Exemplo: #include<stdio.h>
#include<stdlib.h> // definição da estrutura de dados typedef struct empregado { char nome[80]; int idade; float salario; } Empregado;

38 Operador . E  Exemplo (continuação): int main() { Empregado emp1;
printf("Preenchendo as informacoes do empregado 1 sem usar ponteiros\n"); printf("Digite o nome do empregado: "); scanf("%s", emp1.nome); printf("Digite a idade do empregado: "); scanf("%d", &emp1.idade); printf("Digite o salario do empregado: "); scanf("%f", &emp1.salario);

39 Operador . E  Exemplo (continuação): Empregado emp2;
Empregado *p = &emp2; printf("\nPreenchendo as informacoes do empregado 2 usando ponteiros\n"); printf("Digite o nome do empregado: "); scanf("%s", p->nome); printf("Digite a idade do empregado: "); scanf("%d", &p->idade); printf("Digite o salario do empregado: "); scanf("%f", &p->salario);

40 Operador . E  Exemplo (continuação):
printf("\nImprimindo as informacoes do empregado 1\n"); printf("Nome: %s\n", emp1.nome); printf("Idade: %d\n", emp1.idade); printf("Salario: %.2f\n", emp1.salario); printf("\nImprimindo as informacoes do empregado 2\n"); printf("Nome: %s\n", p->nome); printf("Idade: %d\n", p->idade); printf("Salario: %.2f\n", p->salario); return 0; }

41 exercícios Criar um vetor de 5 inteiros. Alocar espaço para esse vetor, preenchê-lo e depois imprimir todos os seus elementos. Criar um vetor de ponteiros para strings. Alocar espaço para esse vetor, preenchê-lo e depois imprimir todos os seus elementos. A 1ª string tem tamanho de 3, a 2ª de 4 e a 3ª de 5 caracteres. Crie uma estrutura com os seguintes campos: nome, idade, telefone. Alocar espaço para essa estrutura, preenchê-la e depois imprimir os dados. Faça o mesmo programa, mas usando um vetor de 10 estruturas.

42 bibliografia SCHILDT, Herbert. C Completo e Total. 3ª ed. São Paulo: Pearson Makron Books, 2006, Cap. 5.


Carregar ppt "ponteiros Estrutura de Dados Prof. André Cypriano M. Costa"

Apresentações semelhantes


Anúncios Google