Menu

Arrays em C++: declaração, indexação e armadilhas comuns

Os arrays nativos de C++ explicados: como declarar e inicializar, indexar com segurança, percorrer usando o tamanho, a armadilha da decadência de array para ponteiro e por que std::array e vector costumam ser melhores.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Uma linha de valores de tamanho fixo

Um array é um bloco contíguo de memória que armazena um número fixo de valores do mesmo tipo. Enquanto um único int guarda um número, um array de int guarda muitos lado a lado, cada um acessível por um índice inteiro.

Você declara um informando o tipo dos elementos, um nome e um tamanho entre colchetes. Adicione uma lista entre chaves para preenchê-lo:

A indexação começa em zero: o primeiro elemento é scores[0], e um array de tamanho 4 tem índices válidos de 0 a 3. O tamanho deve ser uma constante em tempo de compilação — você não pode escrever int n = readInput(); int a[n]; em C++ padrão (isso é uma extensão não portável). Quando você precisa de um tamanho decidido em tempo de execução, use um vector em vez disso.

Inicializando arrays

Há algumas formas de preencher um array, e alguns atalhos que vale a pena conhecer:

O detalhe a internalizar: quando você fornece menos inicializadores do que o tamanho, os que sobram ficam inicializados por valor (zero para tipos numéricos), e não como lixo. Mas um array sem nenhum inicializador — int e[4]; declarado como variável local — contém valores indeterminados, e lê-los antes de atribuir é comportamento indefinido.

Percorrendo um array

Como os elementos são armazenados de forma contígua, você percorre um array com um simples laço por índice. Para não sair dos limites, controle o laço com o comprimento real do array em vez de um número fixo no código:

sizeof(scores) é a contagem total de bytes de todo o array; dividir por sizeof(scores[0]) (o tamanho de um elemento) resulta na quantidade de elementos. Desde o C++17 existe uma forma mais limpa, std::size(scores), que é mais legível e se recusa a compilar se você acidentalmente passar um ponteiro. Ainda mais simples quando você só precisa dos valores: um for baseado em intervalo dispensa por completo o cálculo de índices.

A armadilha do acesso fora dos limites

C++ não faz verificação de limites em arr[i]. Indexar além do último elemento não lança exceção nem avisa — ele lê ou escreve no que quer que esteja naquela memória. Esse é o bug de array mais comum, e é um caso clássico de comportamento indefinido:

int a[3] = {1, 2, 3};
a[3] = 99;          // OOPS - valid indices are 0..2, not 3
cout << a[5];       // garbage, crash, or corruption - undefined behavior

O erro de "um a mais" geralmente se esconde na condição de um laço. Escrever i <= n em vez de i < n dá um passo a mais e toca em arr[n], que não existe:

for (int i = 0; i <= n; i++)   // BUG: when i == n, arr[i] is out of bounds
    cout << arr[i];

A correção é a disciplina da seção anterior: percorra com i < size, nunca com <=, e calcule o tamanho a partir do array em vez de reescrever um literal que sai de sincronia quando você adiciona um elemento.

Decadência de array: o ponteiro oculto

O comportamento mais traiçoeiro dos arrays em C++ é a decadência: quando você passa um array para uma função, ele se converte silenciosamente em um ponteiro para o seu primeiro elemento. A informação do tamanho é perdida, então sizeof dentro da função mede o ponteiro, não o array.

Observe que int arr[] e int* arr são idênticos como parâmetros de função — os colchetes são apenas cosméticos. Como a contagem se perde, você mesmo precisa passar o comprimento junto com o array:

int sum(const int* arr, int n) {
    int total = 0;
    for (int i = 0; i < n; i++) total += arr[i];
    return total;
}

Esse padrão de "passe um ponteiro e um comprimento, e reze para que coincidam" é exatamente o atrito que empurra a maior parte do código C++ para std::array e std::vector, que carregam o próprio tamanho e nunca decaem.

Uma palavra rápida sobre arrays multidimensionais

Você pode aninhar os colchetes para criar uma grade. Um array 2D é na verdade um array de arrays, disposto linha por linha na memória:

Indexe como grid[row][col]. Valem as mesmas ressalvas sobre limites e decadência — e elas pioram, pois passar um array 2D para uma função exige especificar todas as dimensões exceto a primeira (void f(int g[][3])). Para qualquer coisa além de uma pequena grade fixa, um vector de vectors é muito menos propenso a erros.

A seguir: Vector

Arrays nativos são rápidos e previsíveis, mas seu tamanho fixo, a falta de segurança nos limites e a decadência para ponteiro os tornam inconvenientes para o código do dia a dia. A seguir conheceremos o std::vector — um array redimensionável que cresce sob demanda, lembra o próprio tamanho e se integra diretamente com os algoritmos da STL, oferecendo quase tudo o que os arrays oferecem com muito menos maneiras de dar um tiro no próprio pé.

Perguntas frequentes

Como declarar e inicializar um array em C++?

Escreva o tipo dos elementos, um nome e o tamanho entre colchetes e, opcionalmente, uma lista entre chaves: int scores[4] = {90, 75, 100, 60};. Você pode omitir o tamanho quando fornece inicializadores: int scores[] = {90, 75, 100, 60}; deixa o compilador contá-los para você.

Como obter o comprimento de um array em C++?

Para um array real ainda dentro do escopo, use std::size(arr) (C++17) ou sizeof(arr) / sizeof(arr[0]). Isso não funciona depois que o array decai para ponteiro (por exemplo, dentro de uma função que recebeu int arr[]), onde sizeof retorna o tamanho do ponteiro, não o do array.

O que acontece se você acessar um array fora dos limites em C++?

É comportamento indefinido. C++ não faz verificação de limites em arr[i], então ler ou escrever além do fim pode travar o programa, retornar lixo ou corromper silenciosamente a memória vizinha. Mantenha sempre o índice no intervalo de 0 a size - 1.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR