Ponteiros em C: um resumo básico
Igor França
Engenharia de Computação
Juazeiro, BA Julho de 2013
PONTEIROS
1 Definição
Ponteiros são variáveis — assim como int, char etc — que contêm endereços de memória — normalmente a posição de outra variável de mesmo tipo.
2 Declaração tipo *nome;
A variável nome irá conter um ponteiro de tipo base tipo. A variável só poderá designar para outras de seu mesmo tipo, de acordo com a aritmética de ponteiros¹.
A imagem a seguir ilustra o uso de uma variável ponteiro
Figura 1: variável apontando para outra
3 Operadores
Há duas operações básicas de ponteiros: * e &. O & devolve o endereço na memória de seu operando. Por exemplo
x = &example;
Põe, em x, o endereço de memória da variável que contém example. Então, se example está na posição 81 de memória e tem valor 10, x terá o valor 81. Já o operador * funciona para devolver o valor da variável localizada no endereço que ele aponta. Daí
y = *x;
Logo, y receberá o valor 10, porque é o valor que está armazenado na posição 81, que x armazenava.
4 Indireção Múltipla
Pode-se ter um ponteiro apontando para outro ponteiro que aponta para o valor final.
Vale ressaltar que indireção múltipla difere de lista ligada², pois são conceitos diferentes.
A indireção múltipla pode ser levada a qualquer nível, porém, é complexa de seguir e sujeita a erros. Dificilmente é necessário uso de várias indireções. Para se declarar uma variável ponteiro para ponteiro deve ser declarada usando-se mais um * a frente do nome da variável, ou seja:
tipo **nome;
Ou seja, a variável nome de como tipo básico tipo irá apontar para um ponteiro de ponteiro de mesmo tipo básico. Exemplo
1. float x 2. float *p;
3. float **q;
4.
5. x = 10.0;
6. p = &x;
7. q = &p;
8.
9. printf(“&p = %d = p = %d”, &p, q);
10.printf(“**p = %f = x = %f”, **p, x);
No código acima, primeiramente, após as declarações, são feitas as atribuições de valores: x recebe 10.0 (float), p recebe o endereço de x e q recebe o endereço para que p aponta. Na tela será possível verificar que o endereço de p é igual à variável q – ponteiro para ponteiro, e que x tem o mesmo valor que q.
5 Ponteiros para Funções
Quando cada função é compilada, é criado um código-objeto a partir do código-fonte, e um é estabelecido um ponto de entrada. No momento que a função é chamada, é efetuada uma chamada ao ponto de entrada, ao tempo que o programa é executado. Logo, se um ponteiro contém esse valor de entrada da função, ele pode ser utilizado para chamar a função.
Analise o código a seguir para melhor entendimento 1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <string.h>
4. //---
6. //---
7. void main()
8. {
9. char x1[80], x2[80];
10. int (*p)();
11.
12. p = strcmp; // strcmp() é a função da biblioteca string.h
13. // que compara dois strings
14. gets(x1, x2);
15. checar(x1, x2, p);
16. }
17. //---
18. void checar(char *a, char *b, int (*cmp)(const char *, const char *))
19. {
20. printf("testando igualdade");
21.
22. if(!(*cmp)(a, b)) printf("strings iguais");
23. else printf("strings diferentes");
24. }
É necessário o uso de parênteses em (*cmp) para o entendimento do termo como função, do compilador.
6 Alocação Dinâmica
Para o uso de alocação de memória em tempo de execução, quando a quantidade de espaço utilizado é desconhecida, é necessário que o programa efetue funções de operações dinâmicas, e aí onde entram as funções de alocação dinâmica.
A memória de alocação é obtida do heap da máquina, e é desconhecido seu real tamanho. As principais funções para alocação em C são malloc( ) e free( ). Enquanto malloc() cria um espaço de memória para armazenamento dos parâmetros do código, free( ) libera. Para o uso dessas funções é necessário o uso da biblioteca stdlib.h.
A declaração de malloc( ) é da forma void *malloc(size_t num_de_bytes);
A função devolverá um ponteiro de tipo void, que assim, será possível ser utilizada qualquer espécie de ponteiro. Demos como exemplo
1. char *p;
2. p = malloc(100);
Logo, p apontará para os primeiros 100 bytes de memória livre.
Ainda é possível usar sizeof para garantir a portabilidade
1. int *p;
2. p = malloc(10*sizeof(int));
Já a função free( ) pode ser usada, a partir da alocação de malloc( ), em uma declaração geral
void free(void *p);
Onde p é o ponteiro para a memória alocada anteriormente.
Dado isso, podemos exemplificar com um código, tratando das duas funções:
primeiramente, será alocado um valor, e, em seguida, ele será liberado. Segue 1. #include <stdlib.h>
2. #include <stdio.h>
3. #define X 10
4. //--- 5. void alocar(int *p);
6. void liberar(int *p);
7. //--- 8. int main()
9. {
10. int *p;
11.
12. alocar(p);
13. liberar(p);
14. return 0;
15. }
16. //--- 17. void alocar(int *p)
18. {
19. p = malloc(sizeof(X));
20.
21. if(p == NULL) printf("sem memoria\n");
22. else printf("alocado\n");
23. }
24. //--- 25. void liberar(int *p)
26. {
27. if(p != NULL) { 28. free(p);
29. printf("liberado\n");
30. }
6 Problemas com Ponteiros
A medida que os ponteiros são de grande atribuição na linguagem, sua valia é imensa.
Mas há problemas que comumente acontecem. O principal é o ponteiro selvagem. Quando não se é iniciado um ponteiro, ao iniciar a execução no programa, pode haver uma referenciação com uma variável contendo lixo. Isso pode ser imperceptível. É aí que está o problema: encontrar um erro em um ponteiro, sendo que talvez nem seja ele, em si, o erro, e sim, a forma que foi inicializada – ou não.
Analise o código a seguir
1. #include <stdio.h>
2. #include <stdlib.h>
3. //--- 4. int main()
5. {
6. char *p;
7. char s[50];
8.
9. p = s;
10. do{
11. gets(s);
12. while(*p) printf(" %i", *p++); // imprime o valor ASCII para 13. // cada caractere
14. } while(strcmp(s, "done"));
15. }
Nesse programa, p é utilizado para apresentar os valores ASCII para cada letra da palavra de entrada. Mas há um erro: p recebe somente o primeiro valor de s, logo, após o primeiro laço, serão apresentados valores quaisquer, já contidos em memória.
REFERENCIAÇÃO
¹ Em ponteiros só podem ser feitas somas e subtrações;
² Para maiores informações sobre lista ligada, consulte o livro
CORMEN, Thomas H.. Algoritmos: teoria e prática. Rio de Janeiro: Campus, 2002 e os endereços:
http://pt.wikipedia.org/wiki/Lista_ligada
http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html
http://www.lis.ic.unicamp.br/~mc102/files/lista-ligada-exercicio.pdf BIBLIOGRAFIA
SCHILDT, Herbert. C Completo e Total. 3 ed. São Paulo, Pearson Makron Books.
http://www.cplusplus.com/