C
← Volver a Enumeracións Punteiros Seguir con Nomear tipos


Os punteiros son un tipo de variable que non contén un valor ou valores, senón un enderezo de memoria. Neste enderezo de memoria é onde residen os valores, mentres que o punteiro será simplemente un enderezo. Hai que aprender a traballar tanto co valor que contén o punteiro (o enderezo de memoria) como co valor do espazo de memoria sinalado polo punteiro.

Declaración

editar

Para declarar un punteiro, sitúase na declaración da variable un asterisco, «*», entre o tipo e mailo identificador da variable. A sintaxe fundamental da declaración dun punteiro é a seguinte:

tipo * identificador;

Onde:

tipo é o tipo de dato ao que sinala o punteiro,
* sinala que se trata dun punteiro, e
identificador é o identificador (nome) do punteiro.

Identificador

editar

Ao elixir identificadores para punteiros, non sería mala idea seguir unha sintaxe fixa que permita ao que lea o código saber que unha variable é un punteiro tan só con ler o seu identificador.

Algúns programadores optan por prefixar ou sufixar os identificadores dos punteiros con algunha combinación de caracteres (coma p, pt ou punt).

Inicialización

editar

Considérase unha boa práctica inicializar os punteiros co valor nulo (NULL) para que se saiba que non se reservou aínda espazo en memoria para o enderezo de memoria ao que sinala o punteiro. Isto ademais evita problemas con algunhas funcións, coma realloc(), usada para traballar con memoria dinámica.

Punteiro a un punteiro

editar

Se ben a algúns lles resulta difícil comprender isto, pódese declarar un punteiro a un punteiro. Para facelo bastará con engadir á declaración un asterisco adicional. Vexamos un exemplo:

float * * punteiro_a_un_punteiro;

Traballo con punteiros

editar

Valor nulo

editar

O valor nulo nos punteiros escríbese NULL, non 0. Asignándolle este valor a un punteiro, este deixa de apuntar a un enderezo de memoria. Queda baleiro. Vexamos como se lle dá o valor nulo a un punteiro:

punteiro = NULL;

Tamaño

editar

O tamaño dos punteiros, o que ocupan en memoria, non ven dado polo tipo de dato especificado na declaración do punteiro. O tipo de dato da declaración corresponde ao tipo de dato ao que sinala o punteiro.

O verdadeiro tamaño do punteiro, posto que o punteiro garda un enderezo de memoria, dependerá da arquitectura do sistema operativo, xa que esta define a forma en que o procesador traballa coa memoria. Así, nun sistema de 32 bits, este será o tamaño do punteiro (32 bits = 4 bytes), e nun de 64 bits o tamaño será de 8 bytes.

Traballar co valor sinalado

editar

Se queremos traballar ou asignarlle un valor ao espazo de memoria ao que sinala un punteiro (e non ao espazo de memoria que ocupa o punteiro), precédese o identificador do punteiro cun asterisco. Véxanse os seguintes exemplos:

*punteiro = 0; // Asígnaselle o valor 0 ao espazo de memoria sinalado
resultado = *punteiro_ao_primeiro_operando + *punteiro_ao_segundo_operando;

Traballar cos enderezos doutras variables

editar

Mediante o símbolo «&» pode obterse o enderezo de memoria dunha variable que non sexa un punteiro, o cal pode resultar moi útil á hora de traballar con punteiros. Véxase o seguinte exemplo:

// Declaramos unha variable de tipo int:
int variable;

// Declaramos unha variable punteiro para recoller o
// enderezo de memoria en que se garda a variable:
int * punteiro;

// Ao choio:
punteiro = &variable;

// Agora "punteiro" sinala ao enderezo de memoria
// en que está gardada "variable".

Punteiros a matrices

editar

As matrices non son máis que unha forma especial de traballar con punteiros. Unha matriz é en realidade un punteiro cuxo valor (o enderezo de memoria ao que sinala) non pode cambiar, e para o que se reserva un certo espazo en memoria estática ao declaralo ─que dependerá do tipo de datos e a cantidade deles que leve a matriz─.

Se se lle asigna a un punteiro “normal” o enderezo de memoria dunha matriz, poderase traballar co punteiro do mesmo xeito que se fai coa matriz.

Matrices de punteiros

editar

Pódense declarar matrices de punteiros. Vexamos un exemplo:

char * lista[66];

Isto será unha matriz con 66 celas, cada unha das cales é un punteiro a un dato de tipo carácter (char).

Operadores

editar

Hai certos operadores que presentan, para o noso ben, un comportamento lixeiramente distinto cos punteiros do que presentan con outro tipo de variables.

  • «punteiro++» equivale a «punteiro = punteiro + sizeof(tipo)».
  • «punteiro--» equivale a «punteiro = punteiro - sizeof(tipo)».
  • «punteiro = punteiro + número» equivale a «punteiro = punteiro + número * sizeof(tipo)».

Estes comportamentos especiais para punteiros permiten moverse comodamente por matrices de datos, etc.

Nota: lémbrese que o “tipo” é o tipo de dato da que sinala o punteiro, xa que o punteiro non ten un tipo definido.

Programa de resumo

editar

Cómpre comprender por riba o funcionamento do seguinte código, que amosa claramente o principio do funcionamento dos punteiros.

// Ficheiros de cabeceira
#include <stdio.h>
  // Para utilizar:
  // printf()
#include <stdlib.h>
 // Para usar:
 // free()
 // malloc()

// FUNCIÓN PRINCIPAL
int main(void)
{
  // Declaración de variables
  int * punteiro;
  
  // Facémoslle espazo en memoria ao enteiro...
  punteiro = (int *) malloc(sizeof(int));
  
  // Operacións
  *punteiro = 666; // Ao "int" ao que sinala en memoria o punteiro dámoslle o valor 666.
  
  // Impresións en pantalla dos datos interesantes
  printf("Punteiro:\n");
    printf("\tValor:\t\t%p\n",punteiro); // Valor do punteiro, un enderezo de memoria
    printf("\tEnderezo:\t\t%p\n",&punteiro); // Enderezo de memoria en que se garda o punteiro
    printf("\tTamaño:\t\t%d bytes\n",sizeof(punteiro));
  printf("Espazo de memoria apuntado:\n");
    printf("\tValor:\t\t%d\n",*punteiro); // Valor ao que sinala o punteiro
    printf("\tEnderezo:\t\t%p\n",&(*punteiro)); // Enderezo, que debería coincidir co valor do punteiro
    printf("\tTamaño:\t\t%d bytes\n",sizeof(*punteiro));
  
  // Liberamos a memoria reservada para o punteiro (este paso é obrigatorio)
  free(punteiro);
  
  // Saída normal do programa
  return 0;
}

O programa debería permitirnos comprender a diferencia entre o punteiro e o dato ao que apunta. Cómpre copiar o código nun ficheiro de texto, compilalo e executalo. Un posible resultado sería o seguinte:

Punteiro:
        Valor:          0x1104010
        Enderezo:       0x7fff9f9b42e8
        Tamaño:         8 bytes
Espazo de memoria apuntado:
        Valor:          666
        Enderezo:       0x1104010
        Tamaño:         4 bytes

Véxase tamén

editar
  • stdlib.h contén funcións para traballar con punteiros e a memoria dinámica.


C
← Volver a Enumeracións Punteiros Seguir con Nomear tipos