Vetores

Imagine uma fileira de armários, cada um numerado a partir de 0, guardando itens do mesmo tipo — isso é um vetor. Ele permite gerenciar um grupo de dados do mesmo tipo sob um único nome.

Definindo e inicializando vetores unidimensionais

Um vetor é uma coleção ordenada de elementos do mesmo tipo, armazenados contiguamente na memória. Ao definir um vetor, você especifica o tipo dos elementos e o número de elementos.

C
int scores[5];

Isso define um vetor de 5 elementos int, mas o conteúdo não é inicializado e os valores são indeterminados. É recomendável inicializar o vetor na definição:

C
int scores[5] = {90, 85, 78, 92, 88};

Se a lista de inicialização for menor que o vetor, os elementos restantes são automaticamente definidos como 0:

C
int data[5] = {10, 20};

Agora data[2], data[3] e data[4] são todos 0. Usando essa propriedade, você pode zerar um vetor inteiro:

C
int zeros[100] = {0};

Se você fornecer uma lista de inicialização completa, pode omitir o comprimento do vetor e o compilador calculará automaticamente:

C
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

Acesso por índice

Os elementos do vetor são acessados por índice (subscript), começando de 0. Para um vetor de comprimento N, os índices válidos vão de 0 a N-1.

C
int scores[5] = {90, 85, 78, 92, 88};

int first = scores[0];
int last = scores[4];

scores[2] = 100;

O índice pode ser uma expressão inteira, o que torna o percurso com laços conveniente:

C
int i = 3;
int val = scores[i];
💡 Dica: Lembre-se: para um vetor de comprimento 5, o índice máximo é 4, não 5. C não verifica limites de vetores em tempo de execução. Acesso fora dos limites não produzirá erro, mas as consequências podem ser graves.

Riscos de acesso fora dos limites

C não verifica se os índices do vetor estão fora dos limites. Acessar elementos fora dos limites é comportamento indefinido — pode ler dados lixo, modificar outras variáveis ou causar falha no programa.

C
int arr[3] = {10, 20, 30};

printf("%d\n", arr[3]);
printf("%d\n", arr[-1]);

Ambas as linhas acessam posições ilegais. O compilador não avisará, mas os resultados são imprevisíveis.

⚠️ Atenção: O acesso fora dos limites é uma das fontes mais comuns de bugs em C. Ao escrever laços, sempre verifique as condições de contorno e use < em vez de <= ao comparar com o comprimento.

Percurso de vetores

Usar um laço for para processar cada elemento sequencialmente é a operação mais comum com vetores:

C
int scores[5] = {90, 85, 78, 92, 88};
int i;

for (i = 0; i < 5; i++) {
    printf("scores[%d] = %d\n", i, scores[i]);
}

Somar todos os elementos:

C
int sum = 0;
for (i = 0; i < 5; i++) {
    sum += scores[i];
}
printf("Total: %d\n", sum);

Encontrar o valor máximo:

C
int max = scores[0];
for (i = 1; i < 5; i++) {
    if (scores[i] > max) {
        max = scores[i];
    }
}
printf("Highest: %d\n", max);

Exemplo

Calcule a média das notas e a quantidade de reprovações:

C
#include <stdio.h>

int main(void) {
    double scores[] = {78.5, 92.0, 55.5, 88.0, 43.0, 67.5, 90.0};
    int len = sizeof(scores) / sizeof(scores[0]);
    double sum = 0;
    int fail = 0;
    int i;

    for (i = 0; i < len; i++) {
        sum += scores[i];
        if (scores[i] < 60.0) {
            fail++;
        }
    }

    printf("Average: %.1f\n", sum / len);
    printf("Failing: %d\n", fail);

    return 0;
}
▶ Experimente
TEXT
Average: 73.5
Failing: 2

Aqui, sizeof(scores) / sizeof(scores[0]) calcula dinamicamente o número de elementos, então você não precisa atualizar a condição do laço ao alterar o conteúdo do vetor.

Vetores como parâmetros de funções

Quando um vetor é passado para uma função, o vetor inteiro não é copiado — apenas o endereço do primeiro elemento é passado. Isso significa que a função não pode determinar o comprimento do vetor usando sizeof; o comprimento deve ser passado como um parâmetro separado.

C
void print_array(int arr[], int len) {
    int i;
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

O parâmetro int arr[] é equivalente a int *arr, o que reflete o "decaimento" para ponteiro. Modificar elementos do vetor dentro da função afeta o vetor original porque ambos operam na mesma memória.

C
void double_values(int arr[], int len) {
    int i;
    for (i = 0; i < len; i++) {
        arr[i] *= 2;
    }
}

int main(void) {
    int data[] = {1, 2, 3, 4, 5};
    double_values(data, 5);
    return 0;
}

Após a chamada, data contém {2, 4, 6, 8, 10}.

Vetores bidimensionais

Um vetor bidimensional pode ser pensado como um "vetor de vetores", comumente usado para representar matrizes ou dados tabulares.

C
int matrix[3][4];

Isso define um vetor bidimensional de 3 linhas e 4 colunas. A inicialização pode ser agrupada por linha:

C
int matrix[3][4] = {
    {1,  2,  3,  4},
    {5,  6,  7,  8},
    {9, 10, 11, 12}
};

Também pode ser escrito de forma plana — o efeito é o mesmo:

C
int matrix[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

Acesse elementos usando dois índices:

C
int val = matrix[1][2];
matrix[0][0] = 100;

Percorrer um vetor bidimensional requer um laço duplo:

C
int i, j;
for (i = 0; i < 3; i++) {
    for (j = 0; j < 4; j++) {
        printf("%4d", matrix[i][j]);
    }
    printf("\n");
}

Ao inicializar, você pode omitir o número de linhas, mas não o de colunas:

C
int m[][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8}
};

O compilador deduz 2 linhas a partir dos dados do inicializador.

Exemplo

Calcule a média de 4 disciplinas para 3 estudantes:

C
#include <stdio.h>

void student_avg(double grades[][4], int rows) {
    int i, j;
    for (i = 0; i < rows; i++) {
        double sum = 0;
        for (j = 0; j < 4; j++) {
            sum += grades[i][j];
        }
        printf("Student%d Average: %.1f\n", i + 1, sum / 4);
    }
}

int main(void) {
    double grades[3][4] = {
        {85.0, 90.0, 78.0, 92.0},
        {70.0, 65.0, 80.0, 75.0},
        {95.0, 88.0, 92.0, 97.0}
    };

    student_avg(grades, 3);

    return 0;
}
▶ Experimente
TEXT
Student1 Average: 86.2
Student2 Average: 72.5
Student3 Average: 93.0
💡 Dica: Quando um vetor bidimensional é usado como parâmetro de função, o número de colunas (tamanho da segunda dimensão) deve ser especificado; o número de linhas é passado como parâmetro separado.

❓ Perguntas Frequentes

P: Quais valores estão em um vetor definido mas não inicializado? R: Vetores locais têm conteúdo indeterminado (valores lixo na pilha); vetores globais e estáticos são automaticamente inicializados com 0.

P: Por que não se pode usar sizeof(arr) dentro de uma função para encontrar o número de elementos? R: Após um vetor ser passado como parâmetro, ele decai para um ponteiro. sizeof retorna o tamanho do ponteiro (4 ou 8 bytes), não o tamanho total do vetor.

P: Um índice de vetor pode ser negativo? R: Sintaticamente compila, mas acessa memória antes do endereço inicial do vetor, o que é acesso fora dos limites e comportamento indefinido.

P: Como os vetores bidimensionais são armazenados na memória? R: Na ordem principal de linhas, de forma contígua. Todos os elementos da linha 0 são armazenados primeiro, depois a linha 1, e assim por diante.

📖 Resumo

📝 Exercícios

  1. Escreva um programa que leia 10 inteiros em um vetor, depois imprima todos os elementos em ordem inversa.
  2. Escreva uma função que receba um vetor de inteiros e seu comprimento, e retorne o índice do valor máximo.
  3. Defina uma matriz 4x4 de inteiros, inicialize-a e calcule a soma das duas diagonais.
100%