Programador Prático

Observação: Talvez nunca nem eu nem você tenhamos que nos preocupar com operações do gênero, de tão baixo nível, ainda mais que como eu mesmo disse, isso é uma função da biblioteca padrão (ou como no caso de C++ que abole as strings de C com a classe string). Mas, estudar nunca é demais, isso ajuda a clarear ainda mais sobre ponteiros.

De modo geral (mas com várias contradições), uma string em C é basicamente um array de chars, ou especificamente um char *. Por essa razão é possível operar em strings apenas utilizando ponteiros. Um exemplo bem legal é a função strlen da biblioteca padrão. O código comenta tudo sobre o assunto, então vamos direto ao ponto.

Ponteiros de C e C++ possuem várias características avançadas e até mesmo alguns detalhes irritantes, que confundem qualquer um. Procurarei em 2 ou 3 tutoriais cobrir detalhes obscuros de ponteiros aqui no site.

Nesse artigo, vou cobrir a relação ponteiro vs. constantes:

Ponteiro:

tipo *nome;

Ponteiro não constante para dados constantes:

const tipo *nome;

Ponteiro constante para dados não constantes:

tipo *const nome;

Ponteiro e dados constantes:

const tipo *const nome;

A ideia é que se o operador * vem depois de const são assumidos os dados bases (assim, é um ponteiro para dados constantes). Se o operador vem antes de const, então é um ponteiro constante.

Isso pode ser facilmente identificado quando é feita uma leitura da direita para a esquerda:

// Leitura de declarações <-

int *x;             // x é um ponteiro para int

const int *y;       // y é um ponteiro não constante para um int constante

const int *const p; // p é um ponteiro constante para um int constante

int *const w;       // w é um ponteiro constante para um int não constante

Exemplo completo

// +——————————————————————–+

// | Ponteiro não constante para dados não constantes                   |

// +——————————————————————–+

char *p, a, b;

 

p  = &a;  // Recebe endereço de a

*p = ‘A’; // Altera conteúdo de a

p  = &b;  // Recebe endereço de b

// +——————————————————————–+

// | Ponteiro não constante para dados constantes                       |

// +——————————————————————–+

const int *p;

int i = 25, z;

// p aponta para i, o qual não pode ser alterado.

p = &i;

// Mas, p pode apontar para outra variável

p = &z;

// Esse comando gera falha, porque p vai tentar alterar

// o conteúdo de z, mas não pode pois foi declarado para

// apontar para dados constantes

// *p = 35;

// Comando válido, por não se referenciar ao ponteiro, e sim,

// diretamente na variável

i = 45;

// +——————————————————————–+

// | Ponteiro constante para dados não constantes                       |

// +——————————————————————–+

int i = 25, z;

// Como é ponteiro constante, atribuição de endereço deve ser feito

// na definição.

int *const p = &i;

// Comando inválido, não se pode alterar para onde p aponta

// p = &i;

// Comando válido, por se tratar de dados não constantes

*p = 45;

// +——————————————————————–+

// | Ponteiro constante para dados constantes                           |

// +——————————————————————–+

int i = 25, z;

// Como é ponteiro constante, atribuição de endereço deve ser feito

// na definição.

const int *const p = &i;

// Comando inválido, não se pode alterar para onde p aponta

// p = &i;

// Comando inválido, por se tratar de dados constantes

// *p = 45;

// Comando válido, por não se referenciar ao ponteiro, e sim,

// diretamente na variável

i = 45;