TL;DR — En VBA, on ne compte pas un tableau, on le lui demande.
UBound(a)renvoie l'indice valide le plus élevé ;LBound(a)renvoie le plus bas. Les tableaux sont indexés à partir de zéro par défaut, si bien queDim a(9)contient dix éléments indexés de0à9—UBoundvaut9, pas10. Ce décalage d'indice est le bug de boucle le plus courant à lui seul. La boucle qui survit toujours estFor i = LBound(a) To UBound(a), et la vraie longueur estUBound(a) - LBound(a) + 1. Un tableau n'a ni.Lengthni.Count.
Sub LoopSafely()
Dim a() As String
a = Split("red,green,blue", ",") ' Split renvoie un tableau base sur 0
Dim i As Long
For i = LBound(a) To UBound(a) ' fonctionne quelles que soient les bornes
Debug.Print i, a(i) ' 0 red / 1 green / 2 blue
Next i
Debug.Print "count = " & (UBound(a) - LBound(a) + 1) ' 3
End Sub
UBound est la façon de lire la forme d'un tableau, et c'est le partenaire de
ReDim : vous dimensionnez le tableau, puis vous demandez la taille qu'il a fini par
avoir. Trompez-vous sur les bornes et, ou bien vous sautez le dernier élément, ou bien vous dépassez la fin
et tombez sur l'erreur d'exécution 9. Comme différentes sources vous remettent des tableaux avec des indices
de départ différents, l'habitude de demander — plutôt que de supposer 0 ou 1 — est ce qui maintient
les boucles correctes.
Ce que vous allez apprendre
- Ce que renvoient
UBoundetLBound, et pourquoi un tableau n'a pas de propriété.Length - Pourquoi les tableaux VBA sont indexés à partir de zéro par défaut, et d'où vient le bug de décalage d'indice
- La boucle qui fonctionne toujours :
For i = LBound(a) To UBound(a) - La vraie longueur d'un tableau :
UBound(a) - LBound(a) + 1 - Obtenir la taille de chaque dimension d'un tableau 2D avec
UBound(a, 2) - Pourquoi
UBoundsur un tableau dynamique vide lève l'erreur 9, et comment s'en prémunir
UBound et LBound : demandez, ne comptez pas
UBound (upper bound, borne supérieure) renvoie le plus grand indice que vous pouvez légalement utiliser ;
LBound (lower bound, borne inférieure) renvoie le plus petit. Ensemble, ils décrivent la forme du tableau.
Les tableaux VBA n'ont délibérément ni .Length ni .Count — les bornes sont la source de vérité,
et vous les lisez à l'exécution :
Dim a(1 To 5) As Long
Debug.Print LBound(a) ' 1
Debug.Print UBound(a) ' 5
Pourquoi demander plutôt que retenir ? Parce que le tableau que vous parcourez a souvent été dimensionné
ailleurs — par un ReDim, par Split, par la lecture d'une plage — et coder en dur
la taille que vous croyez qu'il a, c'est exactement ainsi que les boucles se désynchronisent de la
réalité.
Indexé à partir de zéro par défaut : là où vit le décalage d'indice
Sauf indication contraire, un tableau VBA commence à l'indice 0. Ainsi Dim a(9) ne vous donne pas
neuf éléments — il vous en donne dix, indexés de 0 à 9 :
Dim a(9) As Long ' dix elements : a(0) .. a(9)
Debug.Print LBound(a) ' 0
Debug.Print UBound(a) ' 9 <- pas 10
C'est la racine du bug classique. For i = 1 To UBound(a) saute a(0) en silence ; For i = 0 To 10 va
un pas trop loin et tombe sur « Subscript out of range ». Vous pouvez forcer les tableaux à commencer à 1
pour tout un module avec Option Base 1, ou déclarer des bornes explicites avec Dim a(1 To 10) — mais le
vrai correctif est d'arrêter complètement de deviner le début.
La boucle qui fonctionne toujours
Écrivez la boucle en fonction des propres bornes du tableau et elle est correcte quelle que soit la façon dont le tableau a été déclaré ou d'où il vient :
Dim i As Long
For i = LBound(a) To UBound(a)
' ... utiliser a(i) ...
Next i
Cette seule habitude élimine toute la famille des erreurs de décalage d'indice. Elle fonctionne aussi bien
pour un résultat de Split basé sur 0, un tableau Range.Value basé sur 1, un module Option Base 1 et un
Dim a(5 To 12) explicite. Ne codez jamais en dur 0 ou 1 comme début d'une boucle de tableau quand
LBound vous dira la vérité gratuitement.
Longueur d'un tableau : UBound moins LBound plus un
Comme un tableau peut commencer à n'importe quel indice, sa longueur n'est pas simplement UBound + 1. La
formule toujours juste est :
Dim n As Long
n = UBound(a) - LBound(a) + 1
Pour un tableau de dix basé sur 0, cela fait 9 - 0 + 1 = 10 ; pour Dim a(1 To 10), cela fait 10 - 1 + 1 = 10. Utilisez la formule complète et la base du tableau n'a plus d'importance. (On cherche une propriété
« VBA array length » ; il n'y en a pas — cette expression est la réponse.)
Tableaux 2D : une borne par dimension
Pour un tableau multidimensionnel, UBound et LBound prennent un second argument — la dimension sur
laquelle vous vous renseignez. UBound(a, 1) est la première dimension (les lignes), UBound(a, 2) la
deuxième (les colonnes) :
Dim g(1 To 3, 1 To 4) As Long ' 3 lignes, 4 colonnes
Debug.Print UBound(g, 1) ' 3 (lignes)
Debug.Print UBound(g, 2) ' 4 (colonnes)
Dim r As Long, c As Long
For r = LBound(g, 1) To UBound(g, 1)
For c = LBound(g, 2) To UBound(g, 2)
' ... utiliser g(r, c) ...
Next c
Next r
Un UBound(g) nu, sans numéro de dimension, renvoie la première dimension. Cela compte surtout quand vous
lisez une feuille dans un tableau, car Range.Value vous remet toujours un tableau
2D basé sur 1 — demander UBound(a, 1) et UBound(a, 2) est la façon de découvrir combien de lignes et de
colonnes vous avez réellement obtenues.
Prémunissez-vous contre le tableau dynamique vide
Un tableau dynamique déclaré mais jamais ReDim-é (ou qui a été Erase-é) n'a aucune borne, et appeler
UBound sur lui lève l'erreur d'exécution 9, « Subscript out of range » :
Dim a() As Long
Debug.Print UBound(a) ' erreur 9 - le tableau n'a pas encore de taille
S'il y a la moindre chance que le tableau soit vide — disons qu'il vient d'un Filter qui n'a rien
trouvé — prémunissez-vous avant de boucler. Une petite fonction utilitaire garde le code appelant propre :
Function IsAllocated(a As Variant) As Boolean
On Error Resume Next
IsAllocated = (LBound(a) <= UBound(a))
On Error GoTo 0
End Function
Ensuite If IsAllocated(a) Then For i = LBound(a) To UBound(a) .... C'est le cousin, côté tableaux, de la
protection d'un objet avec Is Nothing avant de l'utiliser.
Comment ExcelMaster vous aide
UBound est une petite fonction avec une grande mission — dire à une boucle exactement où s'arrêter — et
les erreurs qui l'entourent (supposer 0 ou 1, oublier que le tableau est vide, coder une longueur en
dur) sont précisément celles qui font sauter la dernière ligne à une macro ou la font planter sur un cas
limite.
ExcelMaster vous laisse décrire la
tâche — « charge la plage utilisée dans un tableau, totalise chaque colonne, écris les totaux en dessous » —
et il boucle de LBound à UBound sur la bonne dimension, calcule la longueur correctement, et se prémunit
contre un tableau qui pourrait être revenu vide, si bien que la macro est juste sur la première ligne, la
dernière ligne et le cas vide. Vous gardez le classeur et le code.
Questions fréquentes
Que fait UBound en VBA ?
UBound renvoie l'indice valide le plus élevé d'un tableau — le plus grand nombre que vous pouvez utiliser
entre les crochets. Pour Dim a(1 To 5), UBound(a) vaut 5 ; pour un Dim a(9) basé sur zéro, il vaut
9. Associez-le à LBound, qui renvoie l'indice le plus bas, pour parcourir un tableau sans coder sa
taille en dur.
Comment obtenir la longueur d'un tableau en VBA ?
Un tableau VBA n'a ni propriété .Length ni .Count. Calculez le nombre d'éléments avec UBound(a) - LBound(a) + 1. La formule complète est nécessaire parce qu'un tableau VBA peut commencer à l'indice 0, 1 ou
n'importe quelle borne inférieure explicite, si bien que UBound + 1 n'est correct que pour les tableaux
basés sur zéro.
Pourquoi ai-je Subscript out of range avec UBound ?
En général parce que le tableau est vide — un tableau dynamique déclaré avec Dim a() mais jamais ReDim-é,
ou qui a été Erase-é, n'a aucune borne, si bien que UBound lève l'erreur d'exécution 9. Prémunissez-vous
avec une petite fonction utilitaire IsAllocated avant de boucler. Vous voyez aussi l'erreur 9 quand une
boucle dépasse UBound, par exemple For i = 0 To 10 sur un tableau de dix éléments basé sur zéro.
Les tableaux VBA sont-ils basés sur zéro ou sur un ?
Basés sur zéro par défaut : Dim a(9) contient dix éléments indexés de 0 à 9. Vous pouvez rendre un
module basé sur un avec Option Base 1, ou fixer des bornes explicites avec Dim a(1 To 10). Les tableaux
renvoyés par Split et Array sont basés sur zéro ; un tableau lu depuis Range.Value est basé sur un.
Comme cela varie, bouclez de LBound à UBound plutôt que de supposer.
Comment trouver la taille d'un tableau 2D en VBA ?
Passez le numéro de dimension en second argument : UBound(a, 1) pour la première dimension (les lignes) et
UBound(a, 2) pour la deuxième (les colonnes), avec LBound(a, 1) et LBound(a, 2) pour les bornes
inférieures. C'est ainsi que vous lisez la forme d'un tableau 2D renvoyé par Range.Value.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 24/09/2026.
Guides associés : VBA ReDim · VBA 2D Arrays · VBA Array · VBA For Loop · VBA Split
