Ponteiros
A ideia que deixou o C famoso: uma variável que guarda o endereço de outra. Menos assustadora do que a fama.
- Explicar o que são um endereço e um ponteiro
- Usar
¶ obter um endereço e*para seguir um ponteiro - Escrever uma função que muda as variáveis de quem a chamou
A memória é uma longa fileira de bytes, e cada byte tem um número: o seu endereço. Toda variável mora em algum endereço. Um ponteiro é simplesmente uma variável cujo valor é um endereço - ele "aponta para" outra variável. Essa é a ideia toda; o resto é sintaxe.
Experimente
Até 15 XPSiga o endereço
Resolva duas missões de memória escolhendo para onde p aponta e depois escrevendo por meio de *p. Observe os valores nos cartões de endereço e evite desreferenciar NULL.
Mission 1: Make x = 8 while y stays 12
Pontuação 0/2Illustrative addresses only; real addresses vary between runs. This model never dereferences an invalid pointer.
Choose an address for p before writing through it.
Endereços com &
O operador & dá o endereço de uma variável. (Você já o usou com o scanf: &number dizia ao scanf onde escrever.) Os endereços são impressos com %p e vão ser diferentes cada vez que você rodar o programa:
1#include <stdio.h>
2
3int main(void) {
4 int age = 30;
5 printf("age holds %d\n", age);
6 printf("age lives at %p\n", (void *)&age);
7 return 0;
8}Declarando e seguindo um ponteiro
1#include <stdio.h>
2
3int main(void) {
4 int age = 30;
5 int *p = &age; // p holds the address of age
6
7 printf("%d\n", *p); // follow p: prints 30
8
9 *p = 31; // write through p
10 printf("%d\n", age); // age changed: prints 31
11 return 0;
12}30 31
Dois trabalhos diferentes para o * - é daqui que vem a maior parte da confusão:
- Numa declaração,
int *psignifica "p é um ponteiro para um int". - Numa expressão,
*psignifica "a coisa para a qual p aponta" - isso se chama desreferenciar.
Então *p = 31; não muda p em nada. Ele vai até o endereço guardado em p e escreve 31 ali - em age.
Por que ponteiros: mudando as variáveis de quem chamou
Lembre que as funções recebem cópias dos argumentos. Para deixar uma função mudar a variável de quem chamou, passe o endereço dela - a função recebe uma cópia do endereço, e uma cópia de um endereço continua levando ao mesmo lugar:
1#include <stdio.h>
2
3void swap(int *a, int *b) {
4 int temp = *a;
5 *a = *b;
6 *b = temp;
7}
8
9int main(void) {
10 int x = 1, y = 2;
11 swap(&x, &y);
12 printf("x = %d, y = %d\n", x, y);
13 return 0;
14}x = 2, y = 1
É exatamente assim que o scanf funciona, e também é assim que as funções em C "devolvem" mais de um valor: quem chama passa os endereços onde os resultados devem ser escritos.
NULL
NULL é um valor especial de ponteiro que significa "não aponta para nada". Ele é útil como marcador de "sem resultado", e é o valor que você deve dar a um ponteiro quando ainda não há nada válido para onde ele possa apontar. Desreferenciar NULL é comportamento indefinido - normalmente uma falha imediata ("segmentation fault"). Verifique antes de seguir um ponteiro que pode ser NULL.
Ponteiros e arrays
O nome de um array usado numa expressão vira ("decai para") um ponteiro para o primeiro elemento - é por isso que passar um array para uma função passa um endereço. Você pode fazer aritmética de ponteiros: p + 1 aponta para o próximo elemento, e não para o próximo byte, porque o compilador conhece o tamanho do elemento. Na verdade, a[i] é definido como *(a + i).
1#include <stdio.h>
2
3int main(void) {
4 int values[] = {10, 20, 30};
5 int *p = values; // same as &values[0]
6
7 printf("%d\n", *p);
8 printf("%d\n", *(p + 1));
9 printf("%d\n", p[2]);
10 return 0;
11}10 20 30
Principais conclusões
Um ponteiro guarda um endereço.
&xé o endereço dex;*pé o valor para o qual p aponta.Passe endereços (
swap(&x, &y)) quando uma função precisar mudar as variáveis de quem a chamou.Inicialize os ponteiros (com um endereço real ou
NULL), nunca desreferencieNULLe nunca guarde o endereço de uma variável local depois que a função dela retornar.
Quiz da aula
6 perguntas · aprovação com 5 acertos · até 50 XP
Ao passar, você conclui a aula e mantém sua sequência. As perguntas erradas voltarão em sessões de revisão.
Pratique: escreva código em C
Estes exercícios rodam de verdade. Escreva o programa, clique em “Executar testes” e leia o que o compilador informa: aprender a ler as mensagens do compilador é metade do aprendizado de C.
Dois resultados de uma vez
Escreva void min_max(const int values[], int length, int *min, int *max), que guarda o menor e o maior elemento por meio dos dois ponteiros. A main lê uma quantidade e essa quantidade de números, chama a sua função e imprime os resultados.
Para 5 e depois 3 9 -2 7 4, a saída é min=-2 max=9.
- Valores variados
- Um valor
Seu código é compilado com gcc 14 (-Wall -Wextra) e executado no Compiler Explorer (godbolt.org), um serviço público gratuito.
Dúvidas sobre esta lição
Travou em algum ponto? Pergunte. Descobriu algo? Compartilhe. Explicar também é uma ótima forma de aprender.
Carregando publicações…