Ponteiros e const
Esta aula aborda o uso de const com ponteiros em C, explicando as diferenças entre ponteiro para const, const ponteiro e suas combinações. Inclui exemplos práticos, boas práticas e exercícios para fixação.
Em C, a palavra-chave const pode ser usada em conjunto com ponteiros para restringir a modificação do valor apontado ou do próprio ponteiro. Compreender essas variações é essencial para escrever código mais seguro e expressivo, especialmente em APIs e funções que não devem modificar dados passados como parâmetro. Nesta aula, exploraremos as três combinações principais e as boas práticas associadas.
Vamos começar com uma visão geral: um ponteiro é uma variável que armazena um endereço de memória. Quando adicionamos const, podemos proteger o valor apontado, o próprio ponteiro, ou ambos. A posição de const em relação ao * determina o que é constante.
Ponteiro para const
Um ponteiro para const é um ponteiro que aponta para um valor que não pode ser modificado através desse ponteiro. Ou seja, o valor apontado é tratado como constante. No entanto, o ponteiro em si pode ser alterado para apontar para outro local.
Sintaxe: const int *ptr; ou int const *ptr; (ambas equivalentes).
Exemplo:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
const int *ptr = &a;
// *ptr = 30; // Erro: tentativa de modificar valor constante
ptr = &b; // OK: ponteiro pode ser alterado
printf("%d\n", *ptr); // Imprime 20
return 0;
}Note que ptr aponta para um int constante, mas o próprio ptr não é constante. Isso é útil quando queremos garantir que uma função não modifique os dados apontados, como em strlen(const char *s).
const ponteiro
Um ponteiro constante é um ponteiro cujo valor (o endereço armazenado) não pode ser alterado após a inicialização. Ou seja, o ponteiro sempre apontará para o mesmo local de memória. No entanto, o valor apontado pode ser modificado (a menos que também seja const).
Sintaxe: int *const ptr;.
Exemplo:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int *const ptr = &a;
*ptr = 30; // OK: modifica o valor de a
// ptr = &b; // Erro: ponteiro é constante
printf("%d\n", *ptr); // Imprime 30
return 0;
}Isso é comum em parâmetros de funções que precisam de um buffer fixo, ou em estruturas de dados que mantêm um ponteiro fixo para um array.
Combinações
Podemos combinar as duas formas para ter um ponteiro constante que aponta para um valor constante. Isso significa que nem o ponteiro nem o valor apontado podem ser modificados.
Sintaxe: const int *const ptr; ou int const *const ptr;.
Exemplo:
#include <stdio.h>
int main() {
int a = 10;
const int *const ptr = &a;
// *ptr = 30; // Erro: valor constante
// ptr = &b; // Erro: ponteiro constante
printf("%d\n", *ptr); // Imprime 10
return 0;
}Essa combinação é usada quando queremos total imutabilidade, como em ponteiros para tabelas constantes ou em sistemas embarcados.
É importante lembrar que a regra de leitura da declaração pode ser feita da direita para a esquerda: const int *ptr → ptr é um ponteiro para int constante. int *const ptr → ptr é um ponteiro constante para int. const int *const ptr → ptr é um ponteiro constante para int constante.
Boas práticas
- Use
constsempre que possível para parâmetros de funções que não devem modificar os dados apontados. Isso documenta a intenção e permite que o compilador detecte erros. - Prefira
constem declarações de ponteiros para strings (const char *) para evitar modificações acidentais. - Use ponteiros constantes (
int *const) quando o endereço não deve mudar, como em iteradores ou buffers fixos. - Evite confusão com a sintaxe: lembre-se de que
constà esquerda de*qualifica o valor apontado; à direita, qualifica o ponteiro. - Em APIs públicas, use
constgenerosamente para indicar que a função não altera os dados de entrada.
Referências
- cppreference: const qualifier
- GNU C Manual: const
- Learn-C: Pointers
- TutorialsPoint: Pointer to Constant
- Stack Overflow: const int* vs int* const
Exercícios
Explique a diferença entre
const int *peint *const p.✓ Resposta:const int *pé um ponteiro para um inteiro constante: o valor apontado não pode ser modificado viap, masppode ser alterado para apontar para outro local. Jáint *const pé um ponteiro constante para inteiro: o ponteiro em si não pode ser alterado (sempre aponta para o mesmo endereço), mas o valor apontado pode ser modificado.Dado o código abaixo, identifique os erros e corrija-os.
int main() { int a = 5; const int *p = &a; *p = 10; return 0; }✓ Resposta: O erro está na tentativa de modificar*p(linha 4). Comopé um ponteiro paraconst int, não se pode alterar o valor apontado. Para corrigir, remova a linha ou troque a declaração paraint *p = &a;.Escreva uma declaração de ponteiro que seja constante e aponte para um valor constante do tipo
double.✓ Resposta:const double *const ptr;oudouble const *const ptr;.O que será impresso pelo seguinte código? Justifique.
#include <stdio.h> int main() { int x = 10, y = 20; int *const p = &x; *p = 30; p = &y; printf("%d %d\n", x, y); return 0; }✓ Resposta: O código não compila devido ao erro na linha 6 (p = &y;), poispé um ponteiro constante (int *const) e não pode ser alterado. Se essa linha for removida, imprimiria30 20.Crie uma função
void print_array(const int *arr, int size)que imprime os elementos de um array sem modificá-los. Implemente e teste com um array de exemplo.✓ Resposta:#include <stdio.h> void print_array(const int *arr, int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {1, 2, 3, 4, 5}; print_array(arr, 5); return 0; }