C/Punteiros

En Galilibros, o Wikibooks en galego.
< C
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