Capítulo 09: Vetores Unidimensionais Dinâmicos (ReDim, Preserve, UBound)

🎯 Objetivo da Aula

Nesta aula, você aprenderá a trabalhar com estruturas de dados na memória RAM utilizando Vetores Unidimensionais (Arrays) no VBA. Você entenderá a diferença entre vetores estáticos de tamanho fixo e vetores dinâmicos, dominará as instruções ReDim e ReDim Preserve, aprenderá a inspecionar os limites inferior e superior com as funções LBound e UBound, e liberará espaço na memória com o comando Erase.

Ao final desta aula, você terá desenvolvido o gerenciador de fila de ocorrências críticas do Centro de Controle Operacional (CCO) da FastLog S.A.


🏢 Cenário Prático (FastLog S.A.)

Empresa: FastLog Transportes & Logística Integrada S.A.
Problema: O Centro de Controle Operacional (CCO) monitora mais de 1.200 carretas em trânsito rodoviário. Durante a madrugada, caminhões enfrentam imprevistos como panes mecânicas, sinistros ou retenções em postos fiscais da SEFAZ. A cada ocorrência registrada na estrada, o operador precisa incluir a placa e o status do veículo em uma lista de contingência prioritária. Um assistente tentava fazer isso inserindo linhas diretamente na planilha toda vez que um rádio chamava; as operações constantes de leitura e gravação em células (I/O em disco) deixavam a planilha lenta e travavam o atendimento do guincho.
Sua Missão: Construir o procedimento GerenciarFilaContingencia, que lê as ocorrências, armazena as placas em um vetor dinâmico na memória RAM utilizando ReDim Preserve, filtra os veículos que exigem socorro mecânico e despeja a fila consolidada na planilha com um único comando de alta performance.


🧠 Fundamentos: A Teoria Traduzida

1. Células da Planilha vs. Memória RAM

Acessar células do Excel (Range ou Cells) é uma das operações mais lentas da computação gráfica. Quando precisamos manipular centenas de valores, é infinitamente mais rápido carregar os dados para uma variável do tipo Vetor (Array) na memória RAM do computador:

flowchart TD
    DISCO["📊 Planilha Excel (Células no Disco/Renderização)<br/>Lento: Leitura Célula por Célula"] 
    RAM["🧠 Vetor Dinâmico na Memória RAM<br/>Ultrarrápido: Milhões de operações/seg"]

    DISCO -- "1. Carrega para a RAM" --> RAM
    RAM -- "2. ReDim Preserve (Expande fila)" --> RAM
    RAM -- "3. Despeja resultado final" --> DISCO

    style DISCO fill:#217346,stroke:#fff,stroke-width:2px,color:#fff
    style RAM fill:#1a365d,stroke:#fff,stroke-width:2px,color:#fff

2. Vetores Estáticos vs. Vetores Dinâmicos

  • Vetor Estático (Tamanho Fixo na Compilação):
    1
    
    Dim arrFiliais(1 To 4) As String ' Comporta exatamente 4 elementos
  • Vetor Dinâmico (Tamanho Definido em Execução):
    1
    2
    
    Dim arrOcorrencias() As String   ' Parênteses vazios: tamanho indefinido
    ReDim arrOcorrencias(1 To 10)    ' Aloca 10 posições na memória

3. A Importância da Palavra-Chave Preserve

Se você utilizar a instrução ReDim arr(20) em um vetor que já possuía dados, o VBA apaga todos os valores existentes e recria o vetor do zero!
Para expandir o vetor mantendo intactos os dados armazenados nas posições anteriores, você deve usar obrigatoriamente:

1
ReDim Preserve arrOcorrencias(1 To novoTamanho)

4. As Funções LBound e UBound

Para descobrir com segurança os limites de um vetor sem correr o risco de erro de estouro de índice (Subscript out of range), utilizamos:

  • LBound(vetor): Retorna o índice inicial (Lower Bound), geralmente 0 ou 1.
  • UBound(vetor): Retorna o índice final (Upper Bound).

📖 Exemplo Guiado: Passo a Passo no Laboratório

No Excel, abra o VBE com Alt + F11.

Passo 1: Inserção do Módulo de Vetores

  1. No menu superior, clique em Inserir ➔ Módulo.
  2. Na janela de propriedades (F4), renomeie o módulo para: modEstruturaVetores.
  3. Confirme a presença de Option Explicit.

Passo 2: Estruturação dos Dados de Ocorrências no Excel

Na primeira aba da planilha, configure os cabeçalhos na linha 1:

  • A1: ID_Ocorrencia | B1: Placa_Carreta | C1: Tipo_Incidente | D1: Localizacao | E1: Status
  • Preencha 5 registros de teste:
    • Linha 2: OC-101 | ABC-1234 | PANE MECANICA | BR-116 KM 84 | CRITICO
    • Linha 3: OC-102 | XYZ-9988 | PARADA REFEICAO | POSTO GRAAL | NORMAL
    • Linha 4: OC-103 | BRA-2E19 | SUPERAQUECIMENTO | SP-330 KM 120 | CRITICO
    • Linha 5: OC-104 | KTM-5544 | RETENCAO FISCAL | POSTO FISCAL ITATIBA | RETIDO
    • Linha 6: OC-105 | JUR-8800 | FURO DE PNEU | BR-101 KM 310 | CRITICO

🛠️ Prática Obrigatória 1: Vetor Dinâmico com ReDim Preserve

Construiremos o algoritmo que varre os registros de ocorrência, identifica apenas os veículos com incidentes mecânicos críticos e os armazena dinamicamente na memória RAM com ReDim Preserve.

Passo a Passo no Computador:

  1. No módulo modEstruturaVetores, digite a rotina:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    
    Option Explicit
    
    Sub FiltrarOcorrenciasCriticas()
        Dim wsOrigem As Worksheet
        Dim wsDestino As Worksheet
        Dim lngUltimaLinha As Long
        Dim i As Long
        Dim strStatus As String
        Dim strPlaca As String
        Dim strIncidente As String
    
        ' Declaração do Vetor Dinâmico na RAM
        Dim arrFilaSocorro() As String
        Dim intQtdCritica As Long
    
        Set wsOrigem = ThisWorkbook.Worksheets(1)
        lngUltimaLinha = wsOrigem.Cells(wsOrigem.Rows.Count, "A").End(xlUp).Row
    
        intQtdCritica = 0
    
        ' Varredura em células apenas para coleta
        For i = 2 To lngUltimaLinha
            strStatus = UCase(Trim(wsOrigem.Cells(i, 5).Value))
    
            If strStatus = "CRITICO" Then
                intQtdCritica = intQtdCritica + 1
                strPlaca = wsOrigem.Cells(i, 2).Value
                strIncidente = wsOrigem.Cells(i, 3).Value
    
                ' Redimensiona o vetor na RAM PRESERVANDO os dados já gravados!
                ReDim Preserve arrFilaSocorro(1 To intQtdCritica)
    
                ' Armazena a informação concatenada no vetor
                arrFilaSocorro(intQtdCritica) = strPlaca & " - " & strIncidente & " (" & wsOrigem.Cells(i, 4).Value & ")"
            End If
        Next i
    
        ' Se não houver ocorrências críticas, encerra
        If intQtdCritica = 0 Then
            MsgBox "Nenhuma ocorrência crítica registrada no momento!", vbInformation, "CCO FastLog"
            Exit Sub
        End If
    
        ' 2. Despejo do Vetor na Planilha de Contingência
        On Error Resume Next
        Set wsDestino = ThisWorkbook.Worksheets("Fila_Socorro")
        On Error GoTo 0
    
        If wsDestino Is Nothing Then
            Set wsDestino = ThisWorkbook.Worksheets.Add(After:=wsOrigem)
            wsDestino.Name = "Fila_Socorro"
            wsDestino.Tab.Color = RGB(192, 57, 43) ' Vermelho Alerta
        End If
    
        wsDestino.Cells.Clear
    
        ' Cabeçalho
        wsDestino.Range("A1").Value = "POSIÇÃO FILA"
        wsDestino.Range("B1").Value = "DADOS DO SOCORRO MECÂNICO PRIORITÁRIO"
        wsDestino.Range("A1:B1").Font.Bold = True
        wsDestino.Range("A1:B1").Interior.Color = RGB(192, 57, 43)
        wsDestino.Range("A1:B1").Font.Color = RGB(255, 255, 255)
    
        ' Despeja cada item do vetor na planilha de destino
        Dim k As Long
        For k = LBound(arrFilaSocorro) To UBound(arrFilaSocorro)
            wsDestino.Cells(k + 1, 1).Value = "Prioridade " & k
            wsDestino.Cells(k + 1, 2).Value = arrFilaSocorro(k)
        Next k
    
        wsDestino.Columns("A:B").AutoFit
    
        MsgBox "Fila de contingência montada com sucesso!" & vbCrLf & _
               "Total de carretas na fila prioritária de socorro: " & UBound(arrFilaSocorro), _
               vbInformation, "CCO FastLog"
    End Sub
  2. Posicione o cursor dentro da macro e execute com F5.
  3. Veja surgir a nova aba vermelha "Fila_Socorro" contendo perfeitamente os 3 veículos em estado crítico:
    • Posição 1: ABC-1234 - PANE MECANICA (BR-116 KM 84)
    • Posição 2: BRA-2E19 - SUPERAQUECIMENTO (SP-330 KM 120)
    • Posição 3: JUR-8800 - FURO DE PNEU (BR-101 KM 310)

✅ Resultado Esperado (Prática 1):

A lista prioritária é filtrada e montada na memória RAM através do vetor dinâmico e despejada organizadamente na nova aba operacional.


🛠️ Prática Obrigatória 2: Busca Linear em Memória com Limpeza via Erase

Agora implementaremos uma rotina de busca de placas no vetor de memória, demonstrando a velocidade do processamento em RAM antes de desalocar os recursos com a instrução Erase.

Passo a Passo no Computador:

  1. No mesmo módulo, insira o procedimento de busca:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    
    Sub PesquisarPlacaNaFila()
        Dim arrPlacas() As String
        Dim lngTotal As Long
        Dim i As Long
        Dim strPlacaBusca As String
        Dim blnEncontrou As Boolean
        Dim intPosicao As Long
        Dim ws As Worksheet
    
        Set ws = ThisWorkbook.Worksheets(1)
        lngTotal = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row - 1
    
        If lngTotal <= 0 Then Exit Sub
    
        ' Dimensiona o vetor na RAM com a quantidade exata de veículos
        ReDim arrPlacas(1 To lngTotal)
    
        ' Carrega todas as placas para a memória RAM
        For i = 1 To lngTotal
            arrPlacas(i) = UCase(Trim(ws.Cells(i + 1, 2).Value))
        Next i
    
        ' Coleta a placa desejada via InputBox
        strPlacaBusca = UCase(Trim(InputBox("Digite a placa que deseja localizar na base:", "Busca CCO")))
        If strPlacaBusca = "" Then Exit Sub
    
        blnEncontrou = False
    
        ' ALGORITMO DE BUSCA LINEAR NO VETOR (RAM)
        For i = LBound(arrPlacas) To UBound(arrPlacas)
            If arrPlacas(i) = strPlacaBusca Then
                blnEncontrou = True
                intPosicao = i
                Exit For ' Interrompe a busca assim que localiza
            End If
        Next i
    
        ' Exibe o resultado da consulta
        If blnEncontrou Then
            MsgBox "VEÍCULO LOCALIZADO!" & vbCrLf & vbCrLf & _
                   "• Placa: " & strPlacaBusca & vbCrLf & _
                   "• Posição no Vetor: Índice " & intPosicao & vbCrLf & _
                   "• Linha correspondente na planilha: Linha " & (intPosicao + 1), _
                   vbInformation, "CCO Busca Rápida"
        Else
            MsgBox "A placa " & strPlacaBusca & " não consta na base de ocorrências ativas.", _
                   vbExclamation, "Não Encontrado"
        End If
    
        ' Desaloca o vetor e libera a memória RAM do computador
        Erase arrPlacas
    End Sub
  2. Execute com F5:
    • Digite a placa "BRA-2E19".
    • O sistema busca instantaneamente na memória RAM e notifica que a placa está na posição 3 (linha 4 da planilha).
    • Teste com uma placa inexistente (ex: "XYZ-0000") e verifique a mensagem de aviso.

✅ Resultado Esperado (Prática 2):

A consulta opera em memória RAM sem realizar leituras repetidas na planilha física, liberando a memória ao final com o comando Erase.


📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_09_VBA_SeuNome_SeuSobrenome.xlsm.
  2. Acesse a plataforma Microsoft Teams.
  3. Abra a tarefa: “VBA - Cap 09: Vetores Unidimensionais Dinâmicos”.
  4. Anexe a pasta de trabalho e confirme o envio.

💡 Checkpoint de Gestão & TI

Em programação profissional, a eficiência algorítmica é mensurada pela notação Big-O. Consultas e filtros executados diretamente contra a interface gráfica da planilha possuem custo elevado de acesso a hardware e renderização de vídeo. Ao transferir conjuntos de dados para arrays em memória RAM, o código passa a operar na velocidade do barramento da CPU (nanossegundos), viabilizando sistemas que processam centenas de milhares de linhas sem travamento.


🔥 Desafio de Fixação: Estatística de Retenções Fiscais

Crie uma macro complementar chamada TotalizarRetencoesFiscais:

  1. Use um vetor dinâmico arrRetidos() As String.
  2. Varra a planilha e armazene apenas os caminhões cujo status seja "RETIDO".
  3. Se houver veículos retidos, exiba com MsgBox a quantidade total utilizando UBound(arrRetidos) e liste as placas na mensagem separadas por quebra de linha (vbCrLf).

🔑 Revelar Gabarito Oficial de Laboratório (Clique para expandir)
💡 Incentivo Pedagógico: Tente resolver as práticas e o desafio de fixação por conta própria antes de abrir o gabarito. Seus erros e tentativas durante o laboratório são a chave para a consolidação real do aprendizado!

Código Consolidado (modEstruturaVetores):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Option Explicit

Sub TotalizarRetencoesFiscais()
    Dim ws As Worksheet
    Dim lngLinhaFinal As Long
    Dim i As Long
    Dim arrRetidos() As String
    Dim intContador As Long
    Dim strRelatorio As String
    
    Set ws = ThisWorkbook.Worksheets(1)
    lngLinhaFinal = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    intContador = 0
    
    For i = 2 To lngLinhaFinal
        If UCase(Trim(ws.Cells(i, 5).Value)) = "RETIDO" Then
            intContador = intContador + 1
            ReDim Preserve arrRetidos(1 To intContador)
            arrRetidos(intContador) = ws.Cells(i, 2).Value & " (" & ws.Cells(i, 4).Value & ")"
        End If
    Next i
    
    If intContador = 0 Then
        MsgBox "Nenhum veículo retido pela fiscalização!", vbInformation, "Posto Fiscal Liberado"
    Else
        strRelatorio = "ALERTA DE VEÍCULOS RETIDOS NA SEFAZ (" & intContador & " carretas):" & vbCrLf & vbCrLf
        For i = 1 To intContador
            strRelatorio = strRelatorio & "• " & arrRetidos(i) & vbCrLf
        Next i
        
        MsgBox strRelatorio, vbExclamation, "Auditoria Fiscal FastLog"
    End If
    
    Erase arrRetidos
End Sub

📝 Atividade Extra: Questionário de Fixação (Caderno)

Instruções: Responda no caderno, de próprio punho, as 10 perguntas abaixo com base no que você estudou neste capítulo. Ao concluir, apresente o caderno ao professor para visto.

  1. O que é um Vetor (Array) no VBA e por que manipular dados em vetores na memória RAM é mais rápido do que manipulá-los nas células da planilha?
  2. Qual é a diferença sintática entre a declaração de um vetor estático e a de um vetor dinâmico?
  3. Para que serve a instrução ReDim em um vetor dinâmico?
  4. O que acontece com os dados anteriormente armazenados em um array se você executar ReDim sem a palavra-chave Preserve?
  5. Qual é a função exata do comando UBound(meuVetor)?
  6. O que o comando LBound(meuVetor) retorna e qual é o seu valor habitual?
  7. Qual é a finalidade do comando Erase e quando ele deve ser executado no ciclo de vida de uma macro?
  8. No algoritmo de busca linear em memória, por que utilizamos a instrução Exit For ao localizar o elemento procurado?
  9. Como a função ReDim Preserve arrFilaSocorro(1 To intQtdCritica) permitiu construir uma fila de tamanho desconhecido a priori?
  10. O que significa o erro de tempo de execução “Subscript out of range” (Subscrito fora do intervalo) e como preveni-lo ao trabalhar com vetores?