Aula 24b — Arrays (Vetores) Parte 2 de 2

sizeof e pointer decay, arrays multidimensionais, exemplo completo e C vs Java

Esta é a Parte 2 da Aula 24. Se você ainda não viu a Parte 1 (declaração, acesso e verificação de limites), comece por ela.

5. 🔍 Como Saber o Tamanho de um Array — o Truque do sizeof

Em Java, todo array tem a propriedade .length. Em C, arrays não carregam seu tamanho consigo. Você precisa rastrear o tamanho manualmente — ou usar um truque com sizeof.

sizeof(array) retorna o tamanho total em bytes ocupado pelo array inteiro. sizeof(array[0]) retorna o tamanho em bytes de um único elemento. Dividindo um pelo outro, obtemos o número de elementos.
#include <stdio.h>

int main() {
    int v[] = {10, 20, 30, 40, 50};

    int bytes_total   = sizeof(v);               // 5 * 4 = 20 bytes
    int bytes_elem    = sizeof(v[0]);             // 4 bytes (um int)
    int num_elementos = sizeof(v) / sizeof(v[0]);// 20 / 4 = 5

    printf("Tamanho total: %d bytes\n",    bytes_total);
    printf("Tamanho de um elemento: %d bytes\n", bytes_elem);
    printf("Número de elementos: %d\n",    num_elementos);

    for (int i = 0; i < num_elementos; i++)
        printf("%d ", v[i]);
    printf("\n");
    return 0;
}
Tamanho total: 20 bytes
Tamanho de um elemento: 4 bytes
Número de elementos: 5
10 20 30 40 50

⚠️ Limitação crítica: o truque só funciona localmente

Esta é uma das pegadinhas mais famosas de C. O truque sizeof(v)/sizeof(v[0]) funciona somente no mesmo escopo em que o array foi declarado. Quando você passa um array para uma função, ele se transforma em ponteiro — e o sizeof passa a retornar o tamanho do ponteiro (4 ou 8 bytes), não do array inteiro!
#include <stdio.h>

void imprimirArray(int arr[], int n) {
    // sizeof(arr) aqui retorna sizeof(int*) = 8 bytes (ponteiro!)
    // NÃO use sizeof(arr)/sizeof(arr[0]) dentro de funções!
    printf("sizeof dentro da função: %zu\n", sizeof(arr)); // imprime 8, não 20!

    for (int i = 0; i < n; i++)      // por isso passamos 'n' separadamente
        printf("%d ", arr[i]);
    printf("\n");
}

int main() {
    int v[] = {10, 20, 30, 40, 50};
    int n = sizeof(v) / sizeof(v[0]); // 5 — funciona aqui, onde v foi declarado

    printf("sizeof em main: %zu\n", sizeof(v)); // imprime 20 (correto)
    imprimirArray(v, n);               // passa o tamanho explicitamente!
    return 0;
}
sizeof em main: 20
sizeof dentro da função: 8
10 20 30 40 50

Por que isso acontece? — Pointer Decay

Quando um array é passado para uma função, C não copia todos os elementos — isso seria lento e caro. Em vez disso, passa apenas o endereço do primeiro elemento: um ponteiro. Esse fenômeno chama-se pointer decay (decaimento de array para ponteiro). Com isso, o compilador perde a informação do tamanho original.

Pense assim: ao chamar imprimirArray(v, n), C entrega à função apenas o endereço de v[0] — um número de 8 bytes que aponta para o início do array. A função recebe esse endereço, mas não sabe quantos elementos existem a partir daí. Por isso toda função em C que recebe um array precisa receber o tamanho como parâmetro separado.
Contexto C Java
Obter tamanho do array sizeof(v)/sizeof(v[0]) — só funciona localmente v.length — funciona em qualquer lugar
Dentro de uma função Deve receber int n como parâmetro separado v.length continua disponível
O que é passado à função Apenas o endereço do 1º elemento (ponteiro) Referência ao objeto array (que carrega o length)
Consequência prática: Em C, toda função que recebe um array precisa receber também um parâmetro inteiro com o tamanho (int n). Você nunca consegue descobrir o tamanho de um array dentro da função que o recebeu. Essa é uma diferença fundamental em relação ao Java, onde array.length funciona em qualquer contexto.

6. Arrays Multidimensionais

C suporta arrays com mais de uma dimensão. O caso mais comum é o array bidimensional, útil para representar matrizes, tabelas e grades.

Declaração e acesso

// Matriz 3x4: 3 linhas, 4 colunas
int matriz[3][4];

// Inicialização com listas aninhadas
int m[3][4] = {
    {1,  2,  3,  4},   // linha 0
    {5,  6,  7,  8},   // linha 1
    {9, 10, 11, 12}    // linha 2
};

// Acesso: m[linha][coluna]
printf("%d\n", m[1][2]);    // 7 (linha 1, coluna 2)

Percorrendo com loops aninhados

#include <stdio.h>

int main() {
    int m[3][4] = {
        {1,  2,  3,  4},
        {5,  6,  7,  8},
        {9, 10, 11, 12}
    };

    for (int i = 0; i < 3; i++) {          // percorre linhas
        for (int j = 0; j < 4; j++) {      // percorre colunas
            printf("%4d", m[i][j]);         // %4d: campo de 4 caracteres
        }
        printf("\n");
    }
    return 0;
}
   1   2   3   4
   5   6   7   8
   9  10  11  12

Armazenamento row-major (linha por linha)

Em C, matrizes são armazenadas na memória linha por linha (row-major order): todos os elementos da linha 0 vêm primeiro, depois os da linha 1, e assim por diante. Isso é importante para performance: percorrer coluna por coluna é muito mais lento do que percorrer linha por linha, pois prejudica o cache do processador.

Posição na memória 01234567891011
Elemento m[0][0]m[0][1]m[0][2]m[0][3] m[1][0]m[1][1]m[1][2]m[1][3] m[2][0]m[2][1]m[2][2]m[2][3]
Valor 1234 5678 9101112

7. Exemplo Completo — Estatísticas de um Vetor

Vamos escrever um programa que lê um vetor de inteiros e calcula mínimo, máximo, soma e média:

#include <stdio.h>
#define MAX 100

int main() {
    int v[MAX], n;

    /* lê o número de elementos */
    do {
        printf("Quantos elementos? (1 a %d): ", MAX);
        scanf("%d", &n);
    } while (n < 1 || n > MAX);

    /* lê os elementos */
    for (int i = 0; i < n; i++) {
        printf("v[%d]: ", i);
        scanf("%d", &v[i]);
    }

    /* calcula estatísticas */
    int min = v[0], max = v[0];
    long soma = 0;

    for (int i = 0; i < n; i++) {
        if (v[i] < min) min = v[i];
        if (v[i] > max) max = v[i];
        soma += v[i];
    }

    printf("\nMínimo: %d\n", min);
    printf("Máximo: %d\n", max);
    printf("Soma:   %ld\n", soma);
    printf("Média:  %.2f\n", (double)soma / n);   // cast para não truncar
    return 0;
}
Quantos elementos? (1 a 100): 5
v[0]: 8
v[1]: 3
v[2]: 15
v[3]: 7
v[4]: 12

Mínimo: 3
Máximo: 15
Soma: 45
Média: 9.00
Iniciamos min e max com v[0] — não com 0 ou com INT_MAX. Isso garante que o algoritmo funcione mesmo que todos os elementos sejam negativos (min = 0 seria errado nesse caso) ou muito grandes (max = 0 poderia ser menor que todos os elementos).

8. C vs Java — Comparação Completa de Arrays

Aspecto C Java
Declaração int v[5]; int[] v = new int[5];
Inicialização padrão ❌ Contém lixo de memória ✅ Zeros automáticos (int), null (objetos)
Verificação de limites ❌ Nenhuma — UB silencioso ✅ ArrayIndexOutOfBoundsException
Tamanho do array sizeof(v)/sizeof(v[0]) — só localmente v.length — em qualquer lugar
Passagem para função Decai para ponteiro; tamanho se perde — deve ser passado separado Passa referência ao objeto; .length continua acessível
Tamanho variável VLA (C99) — mas não recomendado; preferir #define ou parâmetro new int[n] — dinâmico e natural
Cópia de array memcpy(dest, src, n*sizeof(int)); — manual Arrays.copyOf(src, n); — automático
Ordenação qsort(v, n, sizeof(int), comparador); Arrays.sort(v);
Array de strings char nomes[10][50]; — matriz de char String[] nomes = new String[10];
For-each ❌ Não existe — use for (int i=0; i<n; i++) ✅ for (int x : v)

Cópia de array em C — não use =!

❌ Errado — em C, = não copia arrays:
int a[5] = {1,2,3,4,5};
int b[5];
b = a;    // ERRO DE COMPILAÇÃO em C!
✅ Correto — copiar elemento por elemento ou com memcpy:
int a[5] = {1,2,3,4,5};
int b[5];
for (int i = 0; i < 5; i++)
    b[i] = a[i];         // cópia manual

/* ou usando memcpy de <string.h>: */
memcpy(b, a, 5 * sizeof(int));

9. Exercícios de Fixação — Parte 2

Questões sobre sizeof, pointer decay, matrizes e C vs Java.

1. Dado int v[] = {3, 0, 0, 0, 0};, qual é o resultado de sizeof(v)/sizeof(v[0])?

2. Uma função recebe int arr[]. Dentro dela, sizeof(arr) retorna:

3. Em C, o que b = a; faz quando a e b são arrays do mesmo tipo e tamanho?

4. Numa matriz int m[3][4], como os elementos são armazenados na memória em C?