Arrays em C++: Um Guia Visual e Prático
Aprenda arrays em C++ de forma visual: como ficam na memória, por que a contagem começa no 0, como percorrer, buscar e ordenar, a armadilha de sair dos limites, arrays 2D, std::array vs std::vector, medições reais e exercícios com respostas.

Nesta página
Imagine anotar as notas de uma turma de 30 alunos. Com variáveis comuns, você precisaria de nota1, nota2, nota3… até nota30, e somar tudo daria uma linha de código enorme. Um array (também chamado de vetor) resolve isso: um nome, muitos valores, cada um na sua caixinha numerada.
Arrays são o jeito mais antigo e mais simples de guardar uma coleção de dados, e também um dos mais rápidos. Neste guia você vai ver como eles ficam na memória, escrever laços que os percorrem, conhecer o erro que todo programador C++ comete pelo menos uma vez e terminar com exercícios para praticar.
Um nome, muitas caixas
Veja a diferença que um array faz:
![Um array é uma fileira de caixas numeradas, lado a lado na memória. Sem array, cinco variáveis separadas, de nota1 a nota5, guardam 90, 85, 77, 92 e 68, espalhadas. Com array, um nome só, notas, cobre cinco caixas em fileira com os mesmos valores. Embaixo de cada caixa estão o seu índice, de 0 a 4, e o seu endereço de memória, terminando em be0, be4, be8, bec e bf0: cada um 4 bytes depois do anterior. Todos os elementos têm o mesmo tamanho e ficam encostados, então o computador acha notas[i] na hora: endereço inicial mais i vezes 4 bytes. É por isso também que a contagem começa no 0: o primeiro elemento está a 0 passos do início](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/7e5e1e0c-0ab5-412b-b08e-3240e3a114ef.png?v=1792851094557)
Três ideias para guardar:
- Todos os elementos têm o mesmo tipo. Um array de
intguarda sóint; um array dedoubleguarda sódouble. - Os elementos são numerados a partir do 0. Esse número se chama índice. O primeiro elemento é
notas[0], e o último de um array de 5 énotas[4]. - Os elementos ficam lado a lado na memória, sem buracos. É isso que deixa os arrays tão rápidos.
Seu primeiro programa com array:
1#include <iostream>
2
3int main() {
4 int notas[5] = {90, 85, 77, 92, 68};
5
6 std::cout << "Primeira nota: " << notas[0] << "\n";
7 std::cout << "Ultima nota: " << notas[4] << "\n";
8
9 notas[2] = 80; // fez a recuperação!
10 std::cout << "A nota 3 agora é " << notas[2] << "\n";
11}Execução de exemplo:
Primeira nota: 90
Ultima nota: 68
A nota 3 agora é 80Declarando um array
O formato geral é tipo nome[tamanho];, opcionalmente seguido dos valores iniciais entre chaves:
![Lendo a declaração de um array: int notas[5] = {90, 85, 77, 92, 68};. A palavra int é o tipo do elemento: cada caixa guarda um int. A palavra notas é o nome: um nome para a fileira toda. O [5] é o tamanho: uma constante, fixada quando o programa é compilado. Os valores entre chaves são os valores iniciais: opcionais, e os que faltarem viram 0. Omita o tamanho e o compilador conta os valores para você: int notas[] = {90, 85, 77}; tem 3 elementos](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/81271732-15cb-41f4-9dc3-bc4663a10c4a.png?v=1792851094584)
O tamanho precisa ser conhecido na hora da compilação, então ele tem que ser um número ou uma constante, como const int quantidadeDeAlunos = 30;. Se você precisa de um tamanho que só se descobre durante a execução (por exemplo, digitado pelo usuário), use o std::vector, que vamos conhecer mais adiante.
Existem vários jeitos de preencher um array ao criá-lo. Aqui estão eles lado a lado, num programa de verdade:
1#include <iostream>
2
3void mostra(const char* rotulo, const int (&valores)[5]) {
4 std::cout << rotulo;
5 for (int valor : valores) {
6 std::cout << valor << " ";
7 }
8 std::cout << "\n";
9}
10
11int main() {
12 int todosListados[5] = {1, 2, 3, 4, 5};
13 int algunsListados[5] = {1, 2};
14 int chavesVazias[5] = {};
15 int tamanhoDeduzido[] = {7, 7, 7};
16
17 mostra("{1, 2, 3, 4, 5} -> ", todosListados);
18 mostra("{1, 2} -> ", algunsListados);
19 mostra("{} -> ", chavesVazias);
20 std::cout << "tamanhoDeduzido tem " << std::size(tamanhoDeduzido) << " elementos\n";
21}Execução de exemplo:
1{1, 2, 3, 4, 5} -> 1 2 3 4 5
2{1, 2} -> 1 2 0 0 0
3{} -> 0 0 0 0 0
4tamanhoDeduzido tem 3 elementos| Você escreve | O que você ganha | Bom saber |
|---|---|---|
int numeros[5]; | 5 elementos com valores desconhecidos (dentro de uma função) | O que tiver sobrado naquela memória. Não leia antes de atribuir! |
int numeros[5] = {1, 2, 3, 4, 5}; | 1 2 3 4 5 | Todos os valores listados |
int numeros[5] = {1, 2}; | 1 2 0 0 0 | Os que faltam viram 0 |
int numeros[5] = {}; | 0 0 0 0 0 | O jeito fácil de começar tudo zerado |
int numeros[] = {7, 7, 7}; | 3 elementos | O compilador conta os valores |
int numeros[2] = {1, 2, 3}; | Erro de compilação | Valores demais para o tamanho |
Por que a contagem começa no 0
Parece estranho no começo, mas o índice na verdade é uma distância: a quantos elementos do início do array você está. O primeiro elemento está a 0 passos. Para achar notas[3], o computador pega o endereço onde o array começa e anda 3 × 4 bytes para a frente (um int ocupa 4 bytes na maioria dos computadores). Uma multiplicação e uma soma, não importa o tamanho do array.
Dá para ver isso com os próprios olhos, imprimindo o endereço de cada elemento com &:
1#include <iostream>
2
3int main() {
4 int notas[5] = {90, 85, 77, 92, 68};
5
6 std::cout << "Cada int ocupa " << sizeof(int) << " bytes\n";
7 for (int indice = 0; indice < 5; indice++) {
8 std::cout << "notas[" << indice << "] = " << notas[indice]
9 << " mora em " << ¬as[indice] << "\n";
10 }
11}Execução de exemplo (os seus endereços vão ser outros, mas sempre de 4 em 4):
1Cada int ocupa 4 bytes
2notas[0] = 90 mora em 0xb9d91ffbe0
3notas[1] = 85 mora em 0xb9d91ffbe4
4notas[2] = 77 mora em 0xb9d91ffbe8
5notas[3] = 92 mora em 0xb9d91ffbec
6notas[4] = 68 mora em 0xb9d91ffbf0Os endereços estão em hexadecimal: e0, e4, e8, ec, f0 vão de 4 em 4. Certinhos, lado a lado.
Percorrendo um array com um laço
Arrays e laços são melhores amigos. Um laço for visita cada elemento por vez, então uma linha de código consegue trabalhar com 5 elementos ou com 5 milhões. Veja exatamente o que acontece, passo a passo:
![Como um laço for percorre um array, como fluxograma e execução de exemplo. Ele começa com indice = 0 e verifica indice < 5. Se sim, usa notas[indice], soma um ao indice e verifica de novo. Se não, termina. A execução de exemplo: indice 0, true, imprime 90; indice 1, true, imprime 85; indice 2, true, imprime 77; indice 3, true, imprime 92; indice 4, true, imprime 68; indice 5, false, o laço acaba. A verificação roda 6 vezes, mas o corpo só 5: o laço para assim que o índice chega ao tamanho](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/f8e0fc90-432f-454a-9372-a386684400d6.png?v=1792851094612)
O C++ moderno oferece dois estilos de laço. Use o laço clássico quando precisar do índice, e o laço baseado em intervalo (range-based for) quando só precisar dos valores:
1#include <iostream>
2#include <iterator>
3
4int main() {
5 double temperaturas[] = {21.5, 23.0, 19.8, 25.1, 24.4, 22.7, 20.9};
6
7 // 1. O laço clássico de contagem: você recebe o índice.
8 for (std::size_t dia = 0; dia < std::size(temperaturas); dia++) {
9 std::cout << "Dia " << dia + 1 << ": " << temperaturas[dia] << " C\n";
10 }
11
12 // 2. O laço baseado em intervalo: você recebe cada valor, sem índice para errar.
13 double total = 0;
14 for (double temperatura : temperaturas) {
15 total += temperatura;
16 }
17 std::cout << "Média da semana: " << total / std::size(temperaturas) << " C\n";
18}Execução de exemplo:
1Dia 1: 21.5 C
2Dia 2: 23 C
3Dia 3: 19.8 C
4Dia 4: 25.1 C
5Dia 5: 24.4 C
6Dia 6: 22.7 C
7Dia 7: 20.9 C
8Média da semana: 22.4857 CA armadilha: sair dos limites
Este é o erro que todo programador C++ comete mais cedo ou mais tarde. Digamos que o seu array tem 8 elementos. Os índices válidos vão de 0 a 7. Então o que existe em notas[8]?
![Saindo dos limites: índice 8 num array de 8 elementos. O array int notas[8] guarda 0, 2, 4, 6, 8, 10, 12 e 14 nos índices de 0 a 7. Logo depois dele está a memória de outra pessoa, e o índice 8 cai ali, marcado com interrogação e exclamação. Nenhum erro, nenhum aviso na execução: ele lê ou sobrescreve, em silêncio, o que estiver morando ali. Os índices válidos vão de 0 até tamanho menos 1. Um laço escrito com menor ou igual em vez de menor dá exatamente um passo a mais](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/111a4628-0f97-48f2-9eca-032c801e67ea.png?v=1792851094639)
O C++ confia totalmente em você. Ele não verifica se um índice é válido, então notas[8] simplesmente lê ou escreve o que estiver na memória logo depois do array. Talvez outra variável. Talvez nada importante. Talvez algo que derrube o seu programa uma hora depois, bem longe do erro de verdade. O nome oficial disso é comportamento indefinido (undefined behavior): qualquer coisa pode acontecer.
O jeito clássico de chegar lá é um único caractere, <= em vez de <:
1#include <iostream>
2
3int main() {
4 int notas[8] = {};
5 for (int indice = 0; indice <= 8; indice++) { // Ops: <= em vez de <
6 notas[indice] = indice * 2;
7 }
8 std::cout << "Pronto: " << notas[7] << "\n";
9}A boa notícia: os compiladores ficaram bem espertos para pegar isso. Compilando com os avisos ligados (g++ -Wall -O2), o GCC 14 diz:
1fora.cpp: In function 'int main()':
2fora.cpp:6:23: warning: iteration 8 invokes undefined behavior [-Waggressive-loop-optimizations]
3 6 | notas[indice] = indice * 2;
4 | ~~~~~~~~~~~~~~^~~~~~~~~~~~
5fora.cpp:5:33: note: within this loop
6 5 | for (int indice = 0; indice <= 8; indice++) { // Ops: <= em vez de <
7 | ~~~~~~~^~~~("A iteração 8 provoca comportamento indefinido, dentro deste laço.")
Três hábitos que mantêm você em segurança:
- Percorra com
indice < tamanho, nuncaindice <= tamanho. - Pegue o tamanho com
std::size(array)em vez de digitar o número. - Prefira o
for (int nota : notas)baseado em intervalo quando não precisar do índice: ele não tem como sair dos limites.
Receitas do dia a dia
A maior parte do código com arrays segue um punhado de padrões: somar tudo, achar o maior ou o menor, contar quem passa num teste. Aqui estão vários de uma vez, num pequeno boletim com um gráfico de barras em texto:
1#include <iostream>
2#include <iterator>
3
4int main() {
5 int notas[] = {90, 85, 77, 92, 68, 100, 73, 88};
6 const std::size_t quantidade = std::size(notas);
7
8 int total = 0;
9 int maior = notas[0];
10 int menor = notas[0];
11 int aprovados = 0;
12
13 for (int nota : notas) {
14 total += nota;
15 if (nota > maior) maior = nota;
16 if (nota < menor) menor = nota;
17 if (nota >= 70) aprovados++;
18 }
19
20 std::cout << "Alunos: " << quantidade << "\n";
21 std::cout << "Média: " << static_cast<double>(total) / quantidade << "\n";
22 std::cout << "Maior: " << maior << "\n";
23 std::cout << "Menor: " << menor << "\n";
24 std::cout << "Aprovados: " << aprovados << " de " << quantidade << "\n";
25
26 // Um gráfico de barras minúsculo, uma estrela a cada 10 pontos
27 for (std::size_t aluno = 0; aluno < quantidade; aluno++) {
28 std::cout << "#" << aluno + 1 << " ";
29 for (int estrela = 0; estrela < notas[aluno] / 10; estrela++) std::cout << '*';
30 std::cout << " " << notas[aluno] << "\n";
31 }
32}Execução de exemplo:
1Alunos: 8
2Média: 84.125
3Maior: 100
4Menor: 68
5Aprovados: 7 de 8
6#1 ********* 90
7#2 ******** 85
8#3 ******* 77
9#4 ********* 92
10#5 ****** 68
11#6 ********** 100
12#7 ******* 73
13#8 ******** 88Repare no static_cast<double>(total) / quantidade: sem ele, dividir dois números inteiros jogaria fora o .125.
Deixe a biblioteca padrão trabalhar
Esses padrões são tão comuns que o C++ já vem com versões prontas em <algorithm> e <numeric>. Elas funcionam com arrays comuns também, usando std::begin e std::end:
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <numeric>
5
6int main() {
7 int notas[] = {90, 85, 77, 92, 68, 100, 73, 88};
8
9 int total = std::accumulate(std::begin(notas), std::end(notas), 0);
10 int maior = *std::max_element(std::begin(notas), std::end(notas));
11 auto aprovados = std::count_if(std::begin(notas), std::end(notas),
12 [](int nota) { return nota >= 70; });
13
14 std::sort(std::begin(notas), std::end(notas));
15
16 std::cout << "Total: " << total << ", maior: " << maior
17 << ", aprovados: " << aprovados << "\nOrdenadas: ";
18 for (int nota : notas) std::cout << nota << " ";
19 std::cout << "\n";
20}Execução de exemplo:
Total: 673, maior: 100, aprovados: 7
Ordenadas: 68 73 77 85 88 90 92 100 | Tarefa | Escrevendo o laço você mesmo | Ou use |
|---|---|---|
| Somar tudo | total += valor | std::accumulate |
| Maior / menor | compara e guarda o melhor | std::max_element / std::min_element |
| Contar quem atende a uma condição | if (...) contador++ | std::count_if |
| Achar um valor | para quando encontrar | std::find |
| Ordenar | (um assunto inteiro só dele!) | std::sort |
| Inverter | troca pelas duas pontas | std::reverse |
Escrever os laços você mesmo é o melhor jeito de aprender. Usar a biblioteca é o melhor jeito de escrever código curto e correto.
Uma divertida: invertendo no lugar
Para inverter um array, troque o primeiro com o último, depois o segundo com o penúltimo, e vá caminhando para o meio até as duas pontas se encontrarem:
1#include <iostream>
2#include <utility>
3
4int main() {
5 char letras[] = {'r', 'o', 'm', 'a'};
6 const int quantidade = 4;
7 for (int esquerda = 0, direita = quantidade - 1; esquerda < direita; esquerda++, direita--) {
8 std::swap(letras[esquerda], letras[direita]);
9 }
10 for (char letra : letras) std::cout << letra;
11 std::cout << "\n";
12}Execução de exemplo:
amor"Roma" de trás para a frente é "amor". Só 2 trocas para 4 letras.
Buscando: um por um ou pela metade?
Para achar um valor num array, o jeito mais simples é a busca linear: olhar caixa por caixa até encontrar. Sempre funciona, mas num array grande é muita olhada.
Se o array estiver ordenado, dá para fazer muito melhor com a busca binária: olhe o elemento do meio. Se ele for pequeno demais, o valor só pode estar na metade da direita; se for grande demais, só na da esquerda. Cada passo descarta metade do que sobrou, igualzinho a procurar uma palavra num dicionário de papel.
1#include <iostream>
2
3int main() {
4 int ordenado[] = {3, 8, 15, 21, 34, 42, 57, 63, 71, 88};
5 int procurado = 57;
6 int inicio = 0;
7 int fim = 9;
8 int passo = 0;
9
10 while (inicio <= fim) {
11 int meio = inicio + (fim - inicio) / 2;
12 passo++;
13 std::cout << "Passo " << passo << ": olha ordenado[" << meio << "] = " << ordenado[meio];
14 if (ordenado[meio] == procurado) {
15 std::cout << " -> achou!\n";
16 return 0;
17 }
18 if (ordenado[meio] < procurado) {
19 std::cout << " -> pequeno demais, busca na metade da direita\n";
20 inicio = meio + 1;
21 } else {
22 std::cout << " -> grande demais, busca na metade da esquerda\n";
23 fim = meio - 1;
24 }
25 }
26 std::cout << "Não encontrado\n";
27}Execução de exemplo:
1Passo 1: olha ordenado[4] = 34 -> pequeno demais, busca na metade da direita
2Passo 2: olha ordenado[7] = 63 -> grande demais, busca na metade da esquerda
3Passo 3: olha ordenado[5] = 42 -> pequeno demais, busca na metade da direita
4Passo 4: olha ordenado[6] = 57 -> achou!Com 10 elementos, a vantagem é modesta. Com um milhão, é impressionante. Contamos os passos de cada busca no pior caso, quando o valor nem está lá:

Arrays e funções: onde o tamanho some
Quando você passa um array comum para uma função, o C++ não copia o array. Ele passa só o endereço do primeiro elemento, um ponteiro. A função não faz ideia do comprimento do array. Os programadores chamam isso de decaimento do array (array decay):
![Passe um array para uma função e o tamanho se perde. No main, int numeros[5] guarda de 1 a 5, e sizeof(numeros) é 20 bytes: 5 elementos vezes 4 bytes cada. Dentro de mostraTamanho(int numeros[]), o parâmetro na verdade é int* numeros, o endereço de numeros[0], apontando de volta para o primeiro elemento. Ali, sizeof(numeros) é 8 bytes: só o tamanho de um ponteiro. A função recebe só onde o array começa, não o seu comprimento. Passe a quantidade junto, ou use std::array, std::vector ou std::span](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/236f78ca-8b94-42a2-8b8b-b6e0c6555ffe.png?v=1792851094690)
Dá para ver acontecendo:
1#include <iostream>
2
3void mostraTamanho(int numeros[]) {
4 std::cout << "Dentro da função: " << sizeof(numeros) << " bytes\n";
5}
6
7int main() {
8 int numeros[5] = {1, 2, 3, 4, 5};
9 std::cout << "No main: " << sizeof(numeros) << " bytes\n";
10 mostraTamanho(numeros);
11}Execução de exemplo (num computador de 64 bits):
No main: 20 bytes
Dentro da função: 8 bytesO GCC até avisa: 'sizeof' on array function parameter 'numeros' will return size of 'int*' ("o sizeof num parâmetro array de função vai devolver o tamanho de int*"). A solução é passar o tamanho junto com o array. E como a função recebeu o endereço verdadeiro do array, as mudanças que ela faz ficam valendo:
1#include <iostream>
2#include <iterator>
3
4// Passe o array E o tamanho: lá dentro, a função só enxerga um ponteiro.
5void dobraTodos(int numeros[], std::size_t quantidade) {
6 for (std::size_t indice = 0; indice < quantidade; indice++) {
7 numeros[indice] *= 2;
8 }
9}
10
11int main() {
12 int numeros[] = {1, 2, 3, 4, 5};
13 dobraTodos(numeros, std::size(numeros));
14 for (int numero : numeros) std::cout << numero << " ";
15 std::cout << "\n";
16}Execução de exemplo:
2 4 6 8 10 Arrays bidimensionais: grades e tabelas
Os elementos de um array podem ser arrays também. Isso dá uma grade, perfeita para tabuleiros, planilhas, imagens e mapas. Você usa dois índices: primeiro a linha, depois a coluna:
![Um array 2D é uma fileira de fileiras, guardadas uma após a outra. Um tabuleiro de jogo da velha 3 por 3, char tabuleiro[3][3], com linhas de 0 a 2 e colunas de 0 a 2. A linha 0 tem X, O, X; a linha 1 tem vazio, X, O; a linha 2 tem O, vazio, X. Na memória, ele fica como uma fileira comprida de 9 casas: linha 0, depois linha 1, depois linha 2. tabuleiro[1][2], o O da linha 1, coluna 2, é o elemento 1 vezes 3 mais 2, ou seja, o elemento 5 da fileira comprida](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/1348bfe7-3463-43cd-9ea7-fe142a0d85b8.png?v=1792851094737)
1#include <iostream>
2
3int main() {
4 char tabuleiro[3][3] = {
5 {'X', 'O', 'X'},
6 {' ', 'X', 'O'},
7 {'O', ' ', 'X'},
8 };
9
10 for (int linha = 0; linha < 3; linha++) {
11 for (int coluna = 0; coluna < 3; coluna++) {
12 std::cout << ' ' << tabuleiro[linha][coluna] << ' ';
13 if (coluna < 2) std::cout << '|';
14 }
15 std::cout << "\n";
16 if (linha < 2) std::cout << "---+---+---\n";
17 }
18
19 bool venceuNaDiagonal = tabuleiro[0][0] == 'X' && tabuleiro[1][1] == 'X' && tabuleiro[2][2] == 'X';
20 std::cout << (venceuNaDiagonal ? "X venceu na diagonal!" : "Ainda sem vencedor") << "\n";
21}Execução de exemplo:
1 X | O | X
2---+---+---
3 | X | O
4---+---+---
5 O | | X
6X venceu na diagonal!Dois laços, um dentro do outro, são o jeito padrão de visitar uma grade: o laço de fora escolhe a linha, e o de dentro anda por ela.
Por que arrays são rápidos (e como mantê-los rápidos)
Como os elementos ficam lado a lado, os arrays são muito amigáveis com o processador do seu computador. A memória não é buscada um número por vez: ela chega em blocos de 64 bytes, chamados linhas de cache. Leia notas[0] e os próximos 15 int vêm junto, de graça.
Medimos isso para este artigo. Somamos todos os 16 milhões de int de um array de 64 MB, visitando-os em três ordens diferentes. Mesmo array, mesmo total, mesma quantidade de somas:

Percorrer em ordem foi 19 vezes mais rápido que em ordem aleatória, para exatamente o mesmo trabalho. A lição: sempre que puder, percorra o array do começo ao fim. Em arrays 2D, isso quer dizer o laço das linhas por fora e o das colunas por dentro, combinando com o jeito como elas ficam na memória.
C++ moderno: std::array e std::vector
Os arrays embutidos deste artigo vêm do C e têm as arestas que você viu: nenhuma verificação de limites, e o tamanho some ao passar para uma função. O C++ moderno oferece dois contêineres mais amigáveis que mantêm a mesma organização lado a lado.
O std::array é um array de tamanho fixo que sabe o próprio tamanho e oferece um .at() com verificação:
1#include <array>
2#include <iostream>
3#include <stdexcept>
4
5int main() {
6 std::array<int, 5> notas = {90, 85, 77, 92, 68};
7
8 std::cout << "Tamanho: " << notas.size() << "\n";
9 std::cout << "Primeira: " << notas.front() << ", última: " << notas.back() << "\n";
10
11 try {
12 std::cout << notas.at(5) << "\n"; // uma depois do fim
13 } catch (const std::out_of_range& erro) {
14 std::cout << "Pegou: " << erro.what() << "\n";
15 }
16}Execução de exemplo (a mensagem exata depende do compilador):
Tamanho: 5
Primeira: 90, última: 68
Pegou: array::at: __n (which is 5) >= _Nm (which is 5)Em vez de ler a memória de outra pessoa em silêncio, o .at(5) para e avisa do problema.
O std::vector é um array que pode crescer e encolher durante a execução:
1#include <iostream>
2#include <vector>
3
4int main() {
5 std::vector<int> notas = {90, 85, 77};
6 notas.push_back(92); // cresce conforme precisa
7 notas.push_back(68);
8
9 std::cout << "Agora guarda " << notas.size() << " notas: ";
10 for (int nota : notas) std::cout << nota << " ";
11 std::cout << "\n";
12}Execução de exemplo:
Agora guarda 5 notas: 90 85 77 92 68 Essas facilidades custam velocidade? Medimos isso também, somando os mesmos 16 milhões de int com cada um:
![As opções mais seguras não custam nada em velocidade. Somando 16 milhões de ints, 64 MB, medido para este artigo com GCC 14.1 -O2, execução mediana, num notebook Windows. Array embutido int[]: 4,22 milissegundos. std::array, tamanho fixo: 4,38 milissegundos. std::vector, pode crescer: 3,98 milissegundos. Os três guardam os elementos encostados, então o compilador gera o mesmo laço rápido. Diferenças tão pequenas são ruído de medição](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/bae86dc4-aea9-4b85-89f3-c9f43d48ef51.png?v=1792851094811)
Nenhuma diferença real. Os três guardam os elementos encostados, e o compilador transforma o laço no mesmo código de máquina rápido.
Qual usar?
![Que tipo de array você deve usar? Primeira pergunta: a quantidade de elementos vai mudar durante a execução? Se sim, use std::vector<int>: ele cresce e encolhe, e é o padrão do dia a dia. Se não, segunda pergunta: você vai conversar com código C ou está aprendendo como a memória funciona? Se sim, use um array embutido como int notas[5], o deste artigo. Se não, use std::array<int, 5>: tamanho fixo, sabe o próprio tamanho e tem .at()](https://nbkmundotech.us-southeast-1.linodeobjects.com/static/images/567aeb46-e1f5-4e79-b9e8-00237049b041.png?v=1792851094835)
| Array embutido | std::array | std::vector | |
|---|---|---|---|
| Exemplo | int notas[5]; | std::array<int, 5> notas; | std::vector<int> notas; |
| Tamanho | Fixo na compilação | Fixo na compilação | Pode mudar durante a execução |
| Sabe o tamanho | Só no mesmo escopo (std::size) | Sempre (.size()) | Sempre (.size()) |
| Acesso com verificação | Não | .at() | .at() |
| Mantém o tamanho ao ir para uma função | Não (vira ponteiro) | Sim | Sim |
Pode ser copiado com = | Não | Sim | Sim |
| Velocidade | Rápido | Igualmente rápido | Igualmente rápido |
Hora de praticar
Tente fazer estes antes de espiar as respostas mais abaixo. Copie cada programa num arquivo, compile com g++ -std=c++20 -Wall programa.cpp e rode.
Exercício 1: Adivinhe a saída (aquecimento). Sem rodar, o que isto imprime?
1int numeros[] = {4, 8, 15, 16, 23, 42};
2std::cout << numeros[1] + numeros[4] << " "
3 << std::size(numeros) << " "
4 << numeros[std::size(numeros) - 1] << "\n";Exercício 2: Ache o erro. Isto deveria somar os cinco valores, mas dá a resposta errada (e às vezes coisa pior). O que está errado?
1int valores[5] = {10, 20, 30, 40, 50};
2int total = 0;
3for (int indice = 1; indice <= 5; indice++) {
4 total += valores[indice];
5}Exercício 3: Conte os pares. Dado int numeros[] = {7, 12, 3, 18, 4, 9, 22, 15};, imprima quantos deles são pares. (Dica: numero % 2 == 0.)
Exercício 4: Gire para a esquerda. Desloque cada elemento uma posição para a esquerda, com o primeiro dando a volta até o fim: {1, 2, 3, 4, 5} vira {2, 3, 4, 5, 1}.
Exercício 5: Vice-campeão. Ache o segundo maior valor distinto em {72, 95, 88, 95, 61, 90}, com um único laço e sem ordenar. (A resposta não é 95!)
Exercício 6: Relatório da cafeteria (desafio). Uma cafeteria anota os cafés vendidos em 3 dias (linhas) e 4 turnos por dia (colunas):
1int vendas[3][4] = {
2 {12, 30, 25, 8},
3 {15, 28, 31, 10},
4 {9, 35, 22, 14},
5};Imprima o total de cada dia e depois descubra qual turno vendeu mais somando os três dias.
Quiz rápido
- Em
int dados[10];, qual é o índice do último elemento? - Verdadeiro ou falso: o C++ para o programa com um erro se você ler
dados[10]. - Qual linha faz os 100 elementos começarem com zero:
int dados[100];ouint dados[100] = {};? - O seu array precisa guardar quantos nomes o usuário digitar. Qual contêiner combina mais?
- Dentro de uma função
void f(int dados[]), por quesizeof(dados)não diz quantos elementos existem?
Respostas
Exercício 1: 31 6 42. numeros[1] é 8 e numeros[4] é 23, então a soma é 31; são 6 elementos; e o último, no índice 5, é 42.
Exercício 2: Dois erros numa linha só. O laço começa em 1, então pula valores[0], e usa <= 5, então lê valores[5], que está fora dos limites. O certo é for (int indice = 0; indice < 5; indice++) ou, melhor ainda, for (int valor : valores) total += valor;.
Exercício 3:
1#include <iostream>
2
3int main() {
4 int numeros[] = {7, 12, 3, 18, 4, 9, 22, 15};
5 int quantidadeDePares = 0;
6 for (int numero : numeros) {
7 if (numero % 2 == 0) quantidadeDePares++;
8 }
9 std::cout << "Números pares: " << quantidadeDePares << "\n";
10}Números pares: 4Exercício 4: Guarde o primeiro elemento, escorregue todo mundo para a esquerda e coloque o guardado no fim. Repare que o laço para um antes, então indice + 1 nunca sai dos limites.
1#include <iostream>
2#include <iterator>
3
4int main() {
5 int numeros[] = {1, 2, 3, 4, 5};
6 const std::size_t quantidade = std::size(numeros);
7
8 int primeiro = numeros[0];
9 for (std::size_t indice = 0; indice + 1 < quantidade; indice++) {
10 numeros[indice] = numeros[indice + 1];
11 }
12 numeros[quantidade - 1] = primeiro;
13
14 for (int numero : numeros) std::cout << numero << " ";
15 std::cout << "\n";
16}2 3 4 5 1 (A versão de uma linha: std::rotate(std::begin(numeros), std::begin(numeros) + 1, std::end(numeros));.)
Exercício 5: Acompanhe os dois melhores valores vistos até agora. A verificação nota < maior faz o 95 repetido não contar duas vezes.
1#include <climits>
2#include <iostream>
3
4int main() {
5 int notas[] = {72, 95, 88, 95, 61, 90};
6 int maior = INT_MIN;
7 int segundoMaior = INT_MIN;
8
9 for (int nota : notas) {
10 if (nota > maior) {
11 segundoMaior = maior;
12 maior = nota;
13 } else if (nota > segundoMaior && nota < maior) {
14 segundoMaior = nota;
15 }
16 }
17 std::cout << "Maior: " << maior << ", segundo maior: " << segundoMaior << "\n";
18}Maior: 95, segundo maior: 90Exercício 6: Os totais por dia andam por cada linha; os totais por turno descem por cada coluna.
1#include <iostream>
2
3int main() {
4 // Cafés vendidos: 3 dias (linhas) x 4 turnos (colunas)
5 int vendas[3][4] = {
6 {12, 30, 25, 8},
7 {15, 28, 31, 10},
8 {9, 35, 22, 14},
9 };
10
11 for (int dia = 0; dia < 3; dia++) {
12 int totalDoDia = 0;
13 for (int turno = 0; turno < 4; turno++) totalDoDia += vendas[dia][turno];
14 std::cout << "Total do dia " << dia + 1 << ": " << totalDoDia << "\n";
15 }
16
17 int melhorTurno = 0;
18 int totalDoMelhorTurno = 0;
19 for (int turno = 0; turno < 4; turno++) {
20 int totalDoTurno = 0;
21 for (int dia = 0; dia < 3; dia++) totalDoTurno += vendas[dia][turno];
22 if (totalDoTurno > totalDoMelhorTurno) {
23 totalDoMelhorTurno = totalDoTurno;
24 melhorTurno = turno;
25 }
26 }
27 std::cout << "Turno mais movimentado: #" << melhorTurno + 1 << " com " << totalDoMelhorTurno << " cafés\n";
28}1Total do dia 1: 75
2Total do dia 2: 84
3Total do dia 3: 80
4Turno mais movimentado: #2 com 93 cafésQuiz: (1) 9, o tamanho menos um. (2) Falso: nada impede você; é comportamento indefinido, e é exatamente por isso que é perigoso. (3) int dados[100] = {};. (4) std::vector, porque o tamanho dele pode crescer durante a execução. (5) Porque o array decaiu para um ponteiro, então o sizeof mede o ponteiro (normalmente 8 bytes), não o array.
Cola rápida
| Eu quero… | Escreva |
|---|---|
| Declarar 10 ints, todos zerados | int dados[10] = {}; |
| Declarar com valores, e o tamanho contado por mim | int dados[] = {3, 1, 4}; |
| Ler / mudar um elemento | dados[2] / dados[2] = 7; |
| Saber a quantidade de elementos | std::size(dados) |
| Visitar cada valor | for (int valor : dados) { ... } |
| Visitar cada índice | for (std::size_t indice = 0; indice < std::size(dados); indice++) |
| Ordenar | std::sort(std::begin(dados), std::end(dados)); |
| Passar para uma função | void usa(int dados[], std::size_t quantidade) |
| Uma grade 3 × 4 | int grade[3][4] = {}; e depois grade[linha][coluna] |
| Tamanho fixo, mais seguro | std::array<int, 10> dados{}; |
| Tamanho que pode mudar | std::vector<int> dados; e depois dados.push_back(5); |
Resumindo
Um array é uma fileira de valores do mesmo tipo, lado a lado na memória, todos sob um único nome. Essa organização simples explica quase tudo sobre eles:
- A contagem começa no 0, porque o índice é a distância até o início.
- Laços e arrays andam juntos:
indice < tamanho, ou umforbaseado em intervalo que não tem como errar. - Não há rede de proteção: um índice depois do fim mexe em silêncio na memória de outra pessoa, então cuidado com o
<e ligue os avisos do compilador. - Um array comum esquece o tamanho ao ir para uma função, então passe o tamanho junto.
- Acesso em ordem é rápido, até 19 vezes mais rápido que o acesso aleatório no nosso teste.
- O C++ moderno tem opções mais amigáveis,
std::arrayestd::vector, que são igualmente rápidas.
Quer entender melhor a linguagem? Leia O Que É a Linguagem de Programação C++? e, para conhecer a sua origem, O Que É a Linguagem de Programação C?.
Leia a seguir

O Que É a Linguagem de Programação Rust? Um Guia Simples da Linguagem Rápida Que Não Deixa Você Travar
Um guia simples e sem jargões sobre o Rust, a linguagem tão rápida quanto o C que impede famílias inteiras de erros de memória antes de o programa rodar. Entenda a ideia de posse, por que gigantes da tecnologia o adotam e onde ele é usado.

O Que É a Linguagem de Programação Go? Um Guia Simples da Linguagem da Nuvem
Um guia simples e sem jargões sobre o Go, a linguagem simples e rápida que o Google criou para a nuvem. Entenda o que são goroutines, por que um programa Go é um arquivo só e como o Go passou a mover o Docker, o Kubernetes e boa parte da internet.

O Que É a Linguagem de Programação Ruby? Um Guia Simples da Linguagem Feita para a Felicidade
Um guia simples e sem jargões sobre o Ruby, a linguagem de programação feita para deixar os programadores felizes. Entenda por que o código Ruby parece inglês, como o Ruby on Rails move sites como GitHub e Shopify, e onde o Ruby brilha.
Comentários
Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.