🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA UBound dans Excel — Taille d'un tableau avec UBound et LBound (et le décalage d'indice)

|

VBA UBound dans Excel — Taille d'un tableau avec UBound et LBound (et le décalage d'indice)

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 que Dim a(9) contient dix éléments indexés de 0 à 9UBound vaut 9, pas 10. Ce décalage d'indice est le bug de boucle le plus courant à lui seul. La boucle qui survit toujours est For i = LBound(a) To UBound(a), et la vraie longueur est UBound(a) - LBound(a) + 1. Un tableau n'a ni .Length ni .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 UBound et LBound, 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 UBound sur 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