Baixe o app para aproveitar ainda mais
Prévia do material em texto
PONTEIROS Definição: um ponteiro é uma variável que contém o endereço de uma outra variável. Toda variável declarada em um programa tem um endereço de memória alocado para si e o número de posições de memória alocado depende do seu tipo (como já foi visto). Ponteiros podem apontar (receber o endereço) para variáveis de qualquer um dos tipos disponíveis na linguagem. Variáveis possuem nomes, endereços e conteúdos. Quando se conhece o nome da variável, pode-se acessá-la através do nome. Eventualmente, possuímos apenas o endereço de uma variável e, para acessá-la, precisamos utilizar os ponteiros. Ponteiros são importantes para: alocação dinâmica de memória, passagem de parâmetros para funções, entre outras. Declaração: se uma variável vai conter um ponteiro (endereço), ela deve ser declarada como tal. Uma declaração de ponteiro consiste no tipo base, um * e o nome da variável. Forma Geral: < tipo > * < nome_do_ponteiro > ; Exemplo: int valor, *ponteiro_valor; No exemplo, ponteiro_valor será usado para apontar para uma variável do tipo inteiro. Um ponteiro não deve apontar para uma variável que não seja do seu tipo base. O operador &: O operador endereço & é usado para indicar o endereço de uma variável. Sempre que desejamos fazer um ponteiro apontar (receber o endereço) para uma variável temos que usar este operador. Ex.: ... ponteiro_valor = &valor; ... No exemplo acima, a variável ponteiro ponteiro_valor recebe o endereço da variável valor, ou seja, após esta atribuição o ponteiro ponteiro_valor estará apontando para a variável valor. Para se chegar ao conteúdo realmente armazenado na variável valor, através de seu ponteiro, deve-se usar agora o operador * , que significa: o valor no endereço. Ex.: ... int valor, valor_aux, *ponteiro_valor; valor = 10; ponteiro_valor = &valor; valor_aux = *ponteiro_valor; printf(“ Valor armazenado: %d \n”, valor_aux); /* ou printf(“ Valor armazenado: %d \n”, *ponteiro_valor); */ Como ponteiros são variáveis (que ao invés de conter valores, contêm endereços) podemos atribuir ponteiros para ponteiros como fazemos com variáveis comuns. Ex.: ... int valor, *ponteiro_valor, *ponteiro_novo; valor = 10; ponteiro_valor = &valor; ponteiro_novo = ponteiro_valor; printf(“Valor armazenado: %d \n”, *ponteiro_novo); ... No exemplo acima, ponteiro_novo passa a apontar para o mesmo endereço para o qual aponta ponteiro_valor (recebe o endereço que está dentro de ponteiro_valor). RESUMO: Declaração, operador &, operador * e atribuição. --» a05a.c Operações Aritméticas com Ponteiros: É possível realizar adição e subtração sobre ponteiros buscando-se endereços de memória (apontando-se para valores) que estejam acima (adição) ou abaixo (subtração) do endereço atual contido no ponteiro. Por exemplo, para um ponteiro de nome p, a operação p++ faz com que p passe a apontar para o próximo elemento, qualquer que seja o tipo de objeto para o qual p aponta. Já p += i (p = p + i), faz com que p passe a apontar i elementos além (acima) do objeto para o qual p aponta atualmente. Ex.: main () { int *ponteiro, vetor_inteiros[4] = {0, 10, 20, 30}; ponteiro = &vetor_inteiros[0]; ponteiro+= 2; /* igual a: ponteiro = &vetor_inteiros[2]; */ printf(“Valor apontado: %d \n”, *ponteiro); ... } No exemplo, ponteiro aponta para o primeiro elemento do vetor vetor_inteiros. A soma ponteiro+= 2 faz com que ponteiro passe a apontar 2 elementos acima do valor atual (no caso para o valor inteiro 20). É IMPORTANTE RESSALTAR QUE O COMPILADOR C AUTOMATICAMENTE RECONHECE O TIPO BÁSICO DO PONTEIRO E PULA A QUANTIDADE DE ENDEREÇOS RESPECTIVOS. NO EXEMPLO, A SOMA CAUSOU UM SALTO DE 4 OU 8 ENDEREÇOS ( TAMANHO EM BYTES DE UM INT). --» a05b.c Inicialização de Ponteiros: Como ponteiros também são variáveis, muitas vezes é preciso inicializá-los a fim de evitar valores iniciais inconsistentes (lixos já existentes na memória). Para ponteiros costuma-se usar a constante NULL, predefinida pela linguagem, que contém o valor zero. Ex.: ... int *ponteiro_val = NULL; ... Vetores e Ponteiros: A forma de acesso a vetores, vista anteriormente, usava um índice (vetores unidimensionais) para acessar cada elemento do vetor. Entretanto, COMO O NOME DE UM VETOR É, NA REALIDADE, UM PONTEIRO PARA O PRIMEIRO ELEMENTO DO VETOR DECLARADO (ARMAZENA O ENDEREÇO DO INÍCIO DOS DADOS DO VETOR NA MEMÓRIA), pode-se usar este nome (ponteiro) como uma forma de acesso alternativa e mais ágil que a usual (via índices). Ex.: Para acessar o primeiro elemento de um vetor de nome valores: elem = valores[0]; ou elem = *valores; Para acessar o segundo elemento: elem = valores[1]; ou elem = *(valores + 1); Pode-se acessar também cada elemento de um vetor através de um ponteiro auxiliar como foi visto na seção anterior ( exemplo a05b.c). Importante: NÃO se deve executar operações aritméticas que alterem o valor no nome do vetor, pois, caso contrário, o endereço de início do vetor na memória será perdido. Exemplo: NÃO SE FAZ valores = valores + 2. Para este tipo de situação, usa-se um ponteiro auxiliar. RESUMO: Aritmética de ponteiros, inicialização de ponteiros, e vetores e ponteiros. --» a05c.c Exercícios resolvidos sobre ponteiros: 1. Escrever um programa para alocar dinamicamente um vetor de inteiros, preencher este vetor com valores lidos do teclado e, por último, escrever o vetor. #include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> void main() { int tam, * pt_aux, * vet; int i; char aux [ 10]; printf ( "Entre com o numero de elementos do vetor: "); gets ( aux); tam = atoi ( aux); vet = ( int *) malloc ( tam * sizeof ( int)); pt_aux = vet; for ( i = 0; i < tam; i ++) { printf ( "Entre com o valor do elemento %d: ", i); gets ( aux); * pt_aux ++ = atoi ( aux); } printf ( "\n"); pt_aux = vet; for ( i = 0; i < tam; i ++) { printf ( "O valor do elemento %d eh: %d\n", i, * pt_aux + +); } free ( vet); getch ( ); } Completar este programa ( sempre usando ponteiros) para informar ao usuário: • o maior valor no vetor; • o menor valor no vetor; • o valor médio armazenado no vetor; • e o número de valores negativos no vetor. 2. Escrever um programa para imprimir, do último para o primeiro, cada um dos elementos do vetor do exemplo a05b.c, através do mesmo ponteiro auxiliar pt. 3. Escrever um programa para ler uma frase qualquer do teclado e imprimir, esta mesma frase, um caracter por vez. #include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> void main() { char frase [ 255], * aux; printf ( "Entre com uma frase qualquer: "); gets ( frase); aux = frase; while ( * aux) printf ( "%c", * aux ++); printf ( "\n"); getch ( ); } Completar este programa ( sempre usando ponteiros) para: • imprimir a frase ao contrário; • contar o número de espaços em branco na frase. Exercícios propostos sobre ponteiros: 1. Escrever um programa para imprimir as matrizes declaradas abaixo utilizando ponteiros. #include <stdio.h> main ( ) { int vetor [ 5] = { 0, 1, 2, 3, 4}; int matriz [ 5] [ 5] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; char string [ 10] = "BICAMPEAO"; } 2. Escrever um programa para alocar dinamicamenteuma área de memória para N doubles, preencher esta área com valores lidos do teclado e, por último, proporcionar uma consulta aos dados gravados. A consulta deve receber um número, que corresponde a uma das posições da área alocada, e o valor double armazenado naquela posição deve ser apresentado ao usuário. O programa deve fazer uma consistência no número informado, correspondente à posição, e apresentar uma mensagem de erro se ele estiver aquém ou além dos limites da área de memória. 3. Escrever um programa para alocar uma área de memória para armazenar 3 valores float e 3 caracteres, preencher esta área com dados provenientes do teclado e, por último, apresentá-los do último até o primeiro, isto é, de maneira inversa àquela do armazenamento. 4. Escrever um programa que recebe um nome completo e, posteriormente, armazena-o numa área de memória alocada dinamicamente. O tamanho desta área deve ser exatamente o necessário para armazenar corretamente o nome informado. Por último, o nome armazenado na área alocada deve ser impresso (usar %s no printf). 5. Escrever um programa que recebe o nome de uma disciplina do curso de Engenharia e um caracter avulso. O programa deve informar o endereço da primeira ocorrência deste caracter no nome da disciplina (usar %x no printf). Igualmente, deve ser dada uma notificação caso o caracter não seja encontrado.
Compartilhar