Carregando
0x90Lição 10 de 20

Ponteiros

A ideia que deixou o C famoso: uma variável que guarda o endereço de outra. Menos assustadora do que a fama.

16 min Questionário com 6 perguntas 1 exercício de código
Ao final desta lição, você saberá
  • Explicar o que são um endereço e um ponteiro
  • Usar & para 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 XP

Siga 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/2

Illustrative addresses only; real addresses vary between runs. This model never dereferences an invalid pointer.

0x100x7
0x104y12
0x108pNULL

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:

address.c
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

pointer.c
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}
Saída
30
31

Dois trabalhos diferentes para o * - é daqui que vem a maior parte da confusão:

  • Numa declaração, int *p significa "p é um ponteiro para um int".
  • Numa expressão, *p significa "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:

swap.c
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}
Saída
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).

walk.c
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}
Saída
10
20
30

Principais conclusões

  • Um ponteiro guarda um endereço. &x é o endereço de x; *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 desreferencie NULL e 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.

Exercício 1

Dois resultados de uma vez

+25 XP

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
main.c
Carregando editor…

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…