Baixe o app para aproveitar ainda mais
Prévia do material em texto
1 LINGUAGEM E TÉCNICA DE PROGRAMAÇÃO I Profa. Gisele Busichia Baioco gisele@ceset.unicamp.br Algoritmos Estruturados e Linguagem de Programação Estruturada Ponteiros em C Parte II – Ponteiros e Vetores 1 Introdução A linguagem C permite, essencialmente, dois métodos de acesso aos elementos de um vetor: a indexação do vetor e a aritmética dos ponteiros. A aritmética dos ponteiros é mais rápida que a indexação de vetores, pois C leva muito mais tempo para indexar um vetor do que para usar um operador *. Pode-se considerar, então, que não se deve usar a indexação de vetores pelo fato dos ponteiros serem mais eficientes. Mas isso só é verdade se o objetivo é acessar um vetor estritamente na ordem crescente ou decrescente. Caso se queira acessar um vetor de maneira aleatória, a indexação será mais fácil de usar e tão rápida quanto o ponteiro, pois o uso deste implica em um código mais complexo (mais difícil de escrever e entender). Exemplo: /* versão com vetor */ #include <stdio.h> #include <ctype.h> main() { char str[80]; int i; printf("digite uma string em letras maiúsculas: "); gets(str); printf("eis aqui a string em letras minúsculas: "); for(i = 0; str[i] != ‘\0’; i++) printf("%c", tolower(str[i])); } A seguir, usando a aritmética dos ponteiros, o programa fica: /* versão com ponteiro */ #include <stdio.h> #include <ctype.h> main() { char str[80], *p; printf("digite uma string com letras maiúsculas: "); gets(str); printf("eis aqui a string em letras minúsculas: "); 2 p = str; /* obtém o endereço de str */ while (*p != ‘\0’) { printf("%c", tolower(*p)); p++; } } Deve-se observar que o programa faz com que p aponte para o endereço do primeiro elemento do vetor str com o comando p = str. Em C, o nome de um vetor sem um índice é o endereço do início do vetor. Entretanto, para obter o endereço de um elemento específico de um vetor deve-se utilizar o operador & normalmente. Por exemplo, o comando seguinte coloca o endereço do terceiro elemento de um vetor x no ponteiro p, ou seja, p aponta para o terceiro elemento do vetor x: p = &x[2]; 2 Indexando um Ponteiro Um ponteiro pode ser indexado como se fosse um vetor. Por exemplo, o programa seguinte imprime na tela os números pares de 2 a 10: /* indexando um ponteiro */ #include <stdio.h> main() { int v[5] = {2,4,6,8,10}; int *p, i; p = v; for(i = 0; i < 5; i++) printf("%d ", p[i]); } Em C, o comando p[i] é idêntico a *(p+i). 3 Vetores de Ponteiros Pode-se fazer vetores de ponteiros da mesma maneira que se faz vetores de qualquer outro tipo de dado. Por exemplo, a declaração de um vetor x de ponteiros do tipo inteiro de tamanho 10 fica: int *x[10]; Para atribuir o endereço de uma variável do tipo inteiro var ao terceiro elemento do vetor de ponteiros x, faz-se: x[2] = &var; Para obter o valor de var indiretamente no terceiro elemento de x e atribuir a uma variável y, faz-se: y = *x[2]; /* y possui o valor do terceiro elemento do vetor */ 3 Um vetor de ponteiros é muito utilizado nas mensagens de erro. Por exemplo: #include <stdio.h> main() { char *err[] = { "mensagem1", "mensagem2", "mensagem3" }; int i; for (i = 0; i < 3; i++) puts(err[i]); } Deve-se observar que quando se inicializa o vetor de ponteiros err diretamente na declaração, pode-se omitir o número de elementos do vetor. 4 Ponteiros para Ponteiros Um ponteiro para outro ponteiro é um modo de indireção múltipla. Essa indireção pode ter a extensão que for desejada. No caso de um ponteiro para outro ponteiro, o primeiro ponteiro contém o endereço do segundo, que aponta para a variável que contém o valor desejado. Esquematicamente tem-se: endereço valor Ponteiro Variável Indireção Simples endereço endereço valor Ponteiro Ponteiro Variável Indireção Múltipla A forma geral de declaração de um ponteiro para ponteiro é a seguinte: tipo-de-dado **nome; onde: tipo-de-dado: é um tipo de dado válido em C; nome: é um identificador válido para a variável ponteiro. São os asteriscos (**) que fazem o compilador saber que é um ponteiro para outro ponteiro. Exemplo: #include <stdio.h> main() { int x, *p, **q; x = 10; p = &x; 4 q = &p; printf("%d", **q); /* imprime valor de x indiretamente */ } Tem-se que p é um ponteiro do tipo inteiro e q é um ponteiro para um ponteiro do tipo um inteiro. A chamada de printf() imprimirá o número 10 na tela. 5 Problemas com Ponteiros O maior problema é um ponteiro "perdido". Pode-se verificar esse problema no exemplo a seguir: main() { int x, *p; x = 10; *p = x; } Esse programa atribui o valor 10 a um endereço de memória desconhecido. O programa nunca atribui um valor (endereço) ao ponteiro p. Portanto, ele contém apenas “lixo”. Logo, o ponteiro não inicializado p fará com que o programa não funcione direito. Quando se executa uma operação que usa p, se estará lendo ou gravando para um pedaço desconhecido da memória. A solução para esse tipo de problema com ponteiros é sempre se certificar de que o ponteiro está apontando para algum endereço de memória válido antes de usá-lo. Outro problema com ponteiros é causado por uma má interpretação de como usar um ponteiro. No exemplo a seguir: main() { int x, *p; x = 10; p = x; printf("%d", *p); } A chamada de printf() não imprimirá o valor de x, que é 10, mas sim algum valor desconhecido. O motivo para isso é o fato da atribuição p = x estar errada, deveria ser p = &x. 6 Exercícios de Fixação 1) Escreva um programa C que declare um vetor de 100 inteiros e preencha o vetor com números de 1 a 100 usando ponteiros para endereçar seus elementos. 2) Verifique o programa abaixo. Encontre o seu erro e corrija-o para que escreva 10 na tela. #include <stdio.h> main() { int x, *p, **q; p = &x; q = &p; x = 10; printf("\n%d\n", &q); }
Compartilhar