TL;DR — Un array de VBA fija su tamaño en el momento en que lo declaras con
Dim—a menos que dejes los corchetes vacíos—.Dim a()declara un array dinámico que aún no tiene tamaño;ReDim a(1 To 10)le da uno. UnReDima secas descarta todos los valores que contenía, así que para ampliar un array sin perder datos usasReDim Preserve. La trampa: en un array bidimensional,ReDim Preservesolo puede redimensionar la última dimensión. Los arrays de tamaño fijo (Dim a(1 To 10)) no se pueden redimensionar conReDimnunca.
Sub GrowAnArray()
Dim a() As Long ' dinamico - aun sin tamano
ReDim a(1 To 3) ' ahora contiene 3 Longs
a(1) = 10: a(2) = 20: a(3) = 30
ReDim Preserve a(1 To 5) ' ampliar a 5, CONSERVA 10, 20, 30
a(4) = 40: a(5) = 50 ' un ReDim a secas aqui habria borrado 10-30
End Sub
ReDim es toda la historia de los arrays dinámicos. Declara el array abierto con
Dim a(), dale tamaño con ReDim, pregúntale cómo de grande es con
UBound y —para una cuadrícula— recuerda que solo la última dimensión puede
crecer (ver VBA 2D Arrays). Equivócate con ReDim y tus datos desaparecen en
silencio, así que vale la pena entender cuándo el tamaño es fijo y cuándo no.
Lo que aprenderás
- La única decisión que gobierna cada array — tamaño fijo en el
Dim, o abierto conDim a() - Por qué
ReDimda tamaño a un array dinámico, y por qué unReDima secas borra todo lo que contenía ReDim Preserve— cómo ampliar un array y conservar los datos- La trampa número uno:
ReDim Preservesolo puede redimensionar la última dimensión de un array 2D - Por qué no puedes hacer
ReDimde un array de tamaño fijo, y qué haceEraseen realidad - Por qué ampliar un array fila a fila dentro de un bucle es lento, y qué hacer en su lugar
El modelo mental: fijo en el Dim, o abierto con corchetes vacíos
Todo array de VBA es de uno de dos tipos, y eliges cuál en la declaración:
Dim fixed(1 To 10) As Long ' FIJO - 10 huecos, para siempre; el tamano es parte del tipo
Dim flex() As Long ' DINAMICO - aun sin tamano; le haras ReDim mas tarde
Un array de tamaño fijo se dimensiona una vez y no cambia nunca —el tamaño vive en la declaración,
así que VBA no te dejará hacerle ReDim más tarde (obtienes el error de compilación «Array already
dimensioned»)—. Un array dinámico se declara con corchetes vacíos: tiene un tipo pero no un tamaño, y
ReDim es como le das uno. Esa única elección —corchetes llenos o vacíos en el Dim— decide todo lo
demás de esta página. Si aún no sabes cuántos elementos tendrás, decláralo abierto.
ReDim da tamaño a un array dinámico
ReDim reserva almacenamiento nuevo para un array dinámico. Puedes hacer ReDim del mismo array tantas
veces como quieras, y cada ReDim puede incluso cambiar los límites:
Dim a() As String
ReDim a(1 To 3) ' 3 elementos, indexados 1..3
ReDim a(0 To 99) ' ahora 100 elementos, indexados 0..99
Hay una cosa que debes tener presente, y es el origen de la mayoría de los fallos de «mis datos han
desaparecido»: un ReDim a secas reinicializa el array entero. Cada elemento vuelve a su valor por
defecto —0 para los números, "" para las cadenas, Nothing para los objetos— como si lo acabaras de
crear:
Dim a() As Long
ReDim a(1 To 3)
a(1) = 10: a(2) = 20: a(3) = 30
ReDim a(1 To 5) ' a(1..3) ahora vuelven a ser 0 - los valores DESAPARECIERON
Si querías conservar los datos, para eso está exactamente Preserve.
ReDim Preserve: ampliar sin perder datos
ReDim Preserve copia los valores existentes en el array redimensionado antes de devolvértelo:
Dim a() As Long
ReDim a(1 To 3)
a(1) = 10: a(2) = 20: a(3) = 30
ReDim Preserve a(1 To 5) ' a(1..3) aun contienen 10, 20, 30; a(4), a(5) son 0
Recurre a Preserve siempre que estés extendiendo un array que ya has rellenado. Funciona cuando amplías
y cuando reduces —al reducir simplemente se descartan los elementos que quedan más allá del nuevo
límite superior—. La única regla que debes respetar es sobre las dimensiones, y es donde casi todo el
mundo cae.
La trampa número uno: Preserve solo redimensiona la última dimensión
En un array unidimensional, ReDim Preserve es libre de cambiar el límite. En un array bidimensional,
ReDim Preserve solo puede cambiar la última dimensión. Intenta cambiar la primera y VBA lanza el
error de ejecución 9, «Subscript out of range»:
Dim g() As Long
ReDim g(1 To 3, 1 To 2) ' 3 filas, 2 columnas
ReDim Preserve g(1 To 5, 1 To 2) ' error 9 - no se puede redimensionar la PRIMERA dimension
ReDim Preserve g(1 To 3, 1 To 4) ' OK - la ULTIMA dimension (columna) puede crecer
Esto no es un fallo que puedas sortear con un ReDim más ingenioso; es cómo VBA almacena los arrays en
memoria. Además choca con la intuición, porque una hoja es filas × columnas, así que el «crecer» que
normalmente quieres —añadir filas— es la primera dimensión, la que no tienes permitido tocar. Dos
salidas: declara la cuadrícula como columnas × filas para que la dimensión que amplías sea la última o,
más habitualmente, dimensiona el array una sola vez a su recuento final de filas antes del bucle y
prescinde de Preserve por completo. Si de verdad tienes que añadir filas a un array 2D existente, lo
reconstruyes (o transpones, redimensionas la última dimensión y vuelves a transponer). Hay más sobre
esto en VBA 2D Arrays.
No puedes hacer ReDim de un array de tamaño fijo
ReDim es solo para arrays declarados con corchetes vacíos. Si dimensionaste el array en su Dim, el
tamaño queda grabado en la declaración y ReDim es un error de compilación:
Dim a(1 To 10) As Long
ReDim a(1 To 20) ' error de compilacion - "Array already dimensioned"
Si te encuentras con ganas de redimensionar un array, esa es la señal de que debería haberse declarado
dinámico (Dim a()) desde el principio. Un array dinámico al que haces ReDim una sola vez, justo
después de conocer el recuento, te da lo mejor de ambos mundos: un tamaño de trabajo fijo y limpio,
elegido en tiempo de ejecución.
Erase: reiniciar o liberar
Erase hace dos cosas distintas según el tipo de array. En un array de tamaño fijo reinicia cada
elemento a su valor por defecto pero mantiene el array del mismo tamaño. En un array dinámico va más
allá —libera la memoria y devuelve el array a su estado sin tamaño, como si solo hubieras escrito
Dim a()—:
Dim fixed(1 To 3) As Long
Erase fixed ' los tres elementos vuelven a ser 0; sigue con tamano 3
Dim flex() As Long
ReDim flex(1 To 3)
Erase flex ' memoria liberada; flex vuelve a no tener tamano - haz ReDim antes de reusar
Después de hacer Erase de un array dinámico, llamar a UBound sobre él lanza el
error 9 hasta que le vuelvas a hacer ReDim —el array genuinamente no tiene límites que reportar—.
Dimensiona una vez, no amplíes de uno en uno
Como cada ReDim Preserve reserva un bloque nuevo y copia el contenido antiguo en él, ampliar un array
de uno en uno en cada pasada de un bucle convierte un trabajo O(n) en uno O(n²) —bien para 50 elementos,
doloroso para 50.000—. La solución idiomática es dimensionar el array una sola vez, de antemano, usando
un recuento que ya tienes (una última fila, el tamaño de una colección), y recortar solo al final si
hace falta:
Dim a() As Long, n As Long, i As Long
n = Cells(Rows.Count, 1).End(xlUp).Row ' cuantas filas de datos hay
ReDim a(1 To n) ' una sola reserva
For i = 1 To n
a(i) = Cells(i, 1).Value
Next i
Cuando de verdad no puedes conocer el recuento de antemano, un patrón habitual es hacer ReDim en
bloques generosos (por ejemplo, duplicar el tamaño cuando te quedas sin espacio) y ReDim Preserve hasta
el recuento exacto una sola vez al final —muchísimas menos copias que ampliar de uno en uno cada vez—.
Cómo te ayuda ExcelMaster
Toda la historia de ReDim es una decisión —¿este array es de tamaño fijo, o crece?— y los dos errores
clásicos son un ReDim a secas que borra tus datos en silencio y un ReDim Preserve que se topa con el
error 9 en la dimensión equivocada.
ExcelMaster te deja describir la tarea
—«lee la columna A en un array, conserva los valores no vacíos, escríbelos en la columna C»— y declara el
array dinámico, lo dimensiona una sola vez a partir del recuento real de filas, usa ReDim Preserve solo
donde la dimensión lo permite, y lee el rango de una sola vez en lugar de celda a celda. Tú conservas el
libro y el código.
Preguntas frecuentes
¿Qué hace ReDim en VBA?
ReDim establece o cambia el tamaño de un array dinámico —uno declarado con corchetes vacíos, como
Dim a() As Long—. ReDim a(1 To 10) da al array diez elementos. Puedes hacer ReDim del mismo array
repetidamente, y cada ReDim puede cambiar los límites. Un ReDim a secas también reinicializa cada
elemento a su valor por defecto, así que usa ReDim Preserve cuando necesites conservar los datos
existentes.
¿Cuál es la diferencia entre ReDim y ReDim Preserve?
Un ReDim a secas reserva el nuevo tamaño y borra cada elemento devolviéndolo a su valor por defecto,
descartando lo que fuera que contuviera el array. ReDim Preserve copia primero los valores existentes en
el array redimensionado, así que los datos sobreviven. Usa el ReDim a secas para el primer dimensionado,
y ReDim Preserve siempre que estés extendiendo un array que ya has rellenado.
¿Por qué ReDim Preserve da el error 9 en un array 2D?
Porque ReDim Preserve solo puede redimensionar la última dimensión de un array multidimensional.
Cambiar la primera dimensión lanza el error de ejecución 9, «Subscript out of range». Para añadir «filas»
a una cuadrícula, o bien la declaras como columnas × filas para que la dimensión que crece sea la última,
la dimensionas a su recuento final de filas antes del bucle, o reconstruyes el array.
¿Puedo hacer ReDim de un array de tamaño fijo?
No. Si declaraste el array con un tamaño, como Dim a(1 To 10), ese tamaño es parte del tipo y ReDim
es un error de compilación, «Array already dimensioned». Solo los arrays declarados con corchetes vacíos
(Dim a()) se pueden dimensionar y redimensionar con ReDim.
¿Cómo añado un elemento a un array de VBA?
Lleva tú mismo la cuenta y usa ReDim Preserve para hacer sitio: ReDim Preserve a(1 To n + 1): a(n + 1) = value: n = n + 1. Esto funciona, pero redimensionar en cada elemento es lento porque cada
ReDim Preserve copia el array entero. Para bucles grandes, dimensiona el array una sola vez a partir de
un recuento conocido, o amplíalo en bloques y recorta una vez al final. Una Collection suele ser más
sencilla cuando el recuento es de verdad desconocido.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 24/09/2026.
Guías relacionadas: VBA UBound · VBA 2D Arrays · VBA Array · VBA Dim · VBA For Loop
