LINGUAGEM: Linguagem C - Capítulo 2 - Parte 4


Ponteiros

Conceito

Um PONTEIRO ou APONTADOR é uma variável usada para armazenar um endereço de memória.

Normalmente, o endereço armazenado em um PONTEIRO é a posição de uma outra variável na memória. Se uma variável contém o endereço e uma outra, então a primeira variável é dita apontar para a segunda.


Declaração

De maneira geral, uma variável ponteiro de nome ID é declarada assim:
ESPECIFICADORES   *  ID = INICIALIZADOR;
onde, o = INICIALIZADOR é opcional (como em toda declaração de variável).

Operadores de Ponteiros

Existem dois operadores especiais para ponteiros: o * e o &.

Operador &

Um operador unário que devolve o endereço na memória do seu operando.
int  m;
 int *  p;

 p = &m;  /* p recebe o endereço onde se localiza a var. m */
 ...

Operador *

É o complemento de &. Quer dizer, devolve a variável localizada no endereço armazenado em um apontador.
p = &m;
 m = 3;

 printf("%p",  p);  /* imprime o endereço de m */
 printf("%d", *p);  /* imprime 3 que é o conteúdo de m */
 ...

Ponteiros e Arranjos

Há uma estreita relação entre PONTEIROS e ARRANJOS (vetores, matrizes e strings).

O nome de um ARRANJO (vetor, matriz ou string) é sempre um PONTEIRO para o primeiro elemento do ARRANJO.

char str[80],  *pstr;

 pstr = str; /* pstr aponta para str[0] */

Assim, a décima posição de um ARRANJO (vetor, matriz ou string) pode ser acessada de duas maneiras:
pstr = str; /* pstr aponta para str[0] */

 printf("%c",   str[9]  );   /* imprime o 10o elemento de str */
 printf("%c",*(pstr + 9));   /* imprime o 10o elemento de str */

Aritmética de Ponteiros

Existem apenas duas operações aritméticas que podem ser usadas com ponteiros: adição e subtração.

Cada vez que um ponteiro é incrementado, ele aponta para a posição de memória do próximo elementodo seu tipo base.

Cada vez que um ponteiro é decrementado, ele aponta para a posição de memória do elemento anterior.


Aplicações

O correto entendimento e uso de ponteiros é crítico para uma programação bem-sucedida em C. Há pelo menos três razões para isto:
  • ponteiros fornecem os meios pelos quais as funções podem modificar seus argumentos
  • formam a base para a alocação dinâmica (variáveis no heap)
  • aumenta a eficiência de certas rotinas

De agora em diante, até o final do curso, iremos explorar em variados graus de detalhes o conceito básico de ponteiros.

Atividade 1

Aplicando os conhecimentos adquiridos na última aula e nesta, iremos agora implementar uma primeira versão de uma lista de strings.

Dado o código abaixo (que pode ser obtido como projeto Dev-Cpp neste link), complemente o código do arquivo lista.c escrevendo as funções:
  • list_rem()
  • list_get()
  • list_set()

main.c

/* main.c **/

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "xcpt.h"

int main(int argc, char *argv[])
{
  while (1) {
        char str[1024];
        int  pos;
 const char * xc;
        
        printf("\nAdicionar\n");
        
        printf("  pos = "); scanf("%d",&pos);
        printf("  str = "); gets(str); gets(str);

        list_add(str,pos);
/*
        TRY(list_add(str,pos));
        
        CATCH(INDEX_OUT_OF_BOUNDS_XCPT,xc)
           printf("\npos invalida!\n");

        CATCH(LIST_FULL_XCPT,xc)
           printf("\nlista cheia!\n");

        CATCH(LINE_TOO_LONG_XCPT,xc)
           printf("\nstr muito grande!\n");
*/
        printf("\nLista\n");
        list_print();
       
  }  
}

list.h, list.c

/* list.h, Rev. 1.1
   (c) 2007, Luciano R. Coutinho <lrc@deinf.ufma.br>
   
   Implements a list of strings.
**/

#ifndef LIST_H
#define LIST_H

#define LIST_MAX_SIZE      99
#define LINE_MAX_SIZE      60

#define LIST_FULL_XCPT     "list full"
#define LINE_TOO_LONG_XCPT "line too long"

unsigned short list_size(void);

void    list_add(const char * str, unsigned short pos);
char *  list_rem(unsigned short pos);
void    list_set(const char * str, unsigned short pos);
char *  list_get(unsigned short pos);

void    list_print(void);

#endif

/* list.c, Rev. 1.1
   (c) 2007, Luciano R. Coutinho <lrc@deinf.ufma.br>
   
   Implements a list of strings.
**/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#include "xcpt.h"

/** private data */
static  char list[LIST_MAX_SIZE][LINE_MAX_SIZE+1];
static  unsigned short  size = 0;

static  char xcpt_cmsg[XCPT_CMSG_MAX_SIZE+1];

/** public functions */

unsigned short list_size(void) {
        return size;
}

/*
  Add a new element str in the list at a given position pos.
  From pos to the end of the list, all existing elements are
  shifted right.
  
  Throws:
         INDEX_OUT_OF_BOUNDS_XCPT  when pos is invalid ( > size +1 )
         LIST_FULL_XCPT            when the list size equals LIST_MAX_SIZE
         LINE_TOO_LONG_XCPT        when str is greater than  LINE_MAX_SIZE
**/
void    list_add(const char * str, unsigned short pos) {
        
        sprintf(xcpt_cmsg,"@%s[%d]\n> list_ins (\"%s\",%d);\n",
    __FILE__,__LINE__,str,pos);

        if ( pos > size + 1 ) {
             THROW(INDEX_OUT_OF_BOUNDS_XCPT,xcpt_cmsg);
             return ;
        }
        
        if ( size + 1 > LIST_MAX_SIZE ) {
             THROW(LIST_FULL_XCPT,xcpt_cmsg);
             return ;
        }

        if ( strlen(str) > LINE_MAX_SIZE ) {
             THROW(LINE_TOO_LONG_XCPT,xcpt_cmsg);
        }
                
        if ( pos == 0 ) {
             strncpy(list[size],str,LINE_MAX_SIZE);
        } else {  
             int  i;

             for ( i = size ; i >= pos; i-- )
                 strcpy(list[i],list[i-1]);
             
             strncpy(list[i],str,LINE_MAX_SIZE);
        }
        size++;
}

char *  list_rem(unsigned short pos) {
}

void    list_set(const char * str, unsigned short pos) {
}

char *  list_get(unsigned short pos) {
}

void list_print(void) {     
     int i;
     
     for ( i=0; i < size; i++ )
         printf("%2d: %s\n",i+1,list[i]);

}

xcpt.h, xcpt.c

/* xcpt.h, Rev. 1.1
   (c) 2007, Luciano R. Coutinho <lrc@deinf.ufma.br>
   
   Implements an exception handling mechanism inspired in Java.
**/
#ifndef XCPT_H
#define XCPT_H

#define XCPT_NAME_MAX_SIZE   32
#define XCPT_CMSG_MAX_SIZE   1024

#define THROW(e,m)   __throw((e),(m))
#define TRY(f)     __begin_try();f;__end_try();
#define CATCH(e,m)   if(m=__catch(e))

#define NULL_POINTER_XCPT               "null pointer"
#define INDEX_OUT_OF_BOUNDS_XCPT        "index out of bounds"
#define OVERFLOW_XCPT                   "overflow"
#define UNDERFLOW_XCPT                  "underflow"
#define ILLEGAL_ARGUMENT_XCPT           "illegal argument" 

void            __begin_try(void);
void            __end_try(void);
const char *    __catch(const char *name);
void            __throw(const char *name, const char *cmsg);

#endif

/* xcpt.c, Rev. 1.1
   (c) 2007, Luciano R. Coutinho <lrc@deinf.ufma.br>
   
   Implements an exception handling mechanism inspired in Java.
**/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "xcpt.h"


static char xcpt_name[XCPT_NAME_MAX_SIZE + 1];
static char xcpt_cmsg[XCPT_CMSG_MAX_SIZE + 1];

static int trying;

/*
  Sets try_flag.
**/
void __begin_try(void) {
     trying = 1;
}

/*
  UnSets try_flag.
**/
void __end_try(void){
     trying = 0;
}

/*
  From exception name, gets the exception message thown by
  __throw(n,m). Once cautch, the exception name is cleared .
**/
const char * __catch(const char * name) {
      if ( strcmp(xcpt_name,name) == 0 ) {
         xcpt_name[0] = '\0';
         return xcpt_cmsg;
      }
      else
         return NULL;
}

/*
  Stores an exception contextual message.  
  When called outside a __begin_try(); ...; __end_try(); pair,
  the exception message is also printed to the stderr stream .
**/
void __throw(const char * name,const char * cmsg) {
     strncpy(xcpt_name,name,XCPT_NAME_MAX_SIZE);
     strncpy(xcpt_cmsg,cmsg,XCPT_CMSG_MAX_SIZE);
     
     if ( !trying )
          fprintf(stderr,"exception: %s: %s\n",xcpt_name,xcpt_cmsg);
}

Leitura recomendada

  • CCT Cap 5

Exercícios

Termine a atividade 1 acima, escrevendo as funções:
  • list_rem()
  • list_get()
  • list_set()

Bibliografia e fonte:

  • [CCT] Schildt, H. (1996) C, completo e total: 3a Ed.. São Paulo, Makron.
  • LP, UFMA; Coutinho, Lucian. Linguagem de programação para ciencia da computação da ufma.http://www.deinf.ufma.br/~lrc/2009.1/LP/
  • [K&R] KERNIGHAN, B. e RITCHIE, D. (1990) C, a linguagem de programação: padrão ANSI. Rio de Janeiro: Campus.
  • DEITEL, H. M. (1999) Como programar em C. Rio de Janeiro: LTC.
  • Módulo Consultoria e Informática (1989) Linguagem C: programação e aplicações. Rio de Janeiro: LTC.