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

VBA Cells gegen Range in Excel — Zellen per Zahl ansprechen (und warum Cells(1, 2) B1 ist, nicht A2)

|

VBA Cells gegen Range in Excel — Zellen per Zahl ansprechen (und warum Cells(1, 2) B1 ist, nicht A2)

TL;DRCells ist Range, adressiert per Zahl. Range("A1") benennt eine Zelle mit einem String in Lesereihenfolge (Spaltenbuchstabe, dann Zeile). Cells(row, column) benennt eine Zelle mit zwei Ganzzahlen in der Reihenfolge, in der Excel sie speichertZeile zuerst, dann Spalte — weshalb Cells(1, 2) gleich B1 ist, nicht A2. Weil beide Koordinaten Zahlen sind, die Sie berechnen können, ist Cells der Bezug, der für Schleifen gemacht ist. Nehmen Sie Range für Bereiche, die Sie per Name tippen, Cells für Positionen, die Sie berechnen, und Range(Cells(1, 1), Cells(n, k)), um einen Block aus berechneten Ecken zu bauen.

Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Data")
' Range benennt einen festen Bereich; Cells berechnet eine Position, Zeile zuerst.
ws.Range("A1").Value = "Header"          ' der menschliche Weg - eine getippte Adresse
ws.Cells(2, 1).Value = "First row"       ' Zeile 2, Spalte 1 = A2 (NICHT B2)

Auf Zellen zu verweisen ist das Erste, was jedes Makro tut, und Cells gegen Range ist die erste Stelle, an der man stolpert. Die Verwirrung liegt nicht darin, dass eines besser wäre — sondern darin, dass sie Zellen unterschiedlich adressieren, und wer die Reihenfolge vertauscht, schreibt stillschweigend an die falsche Stelle. Diese Anleitung ruht auf einer Idee, die den Rest vorhersagbar macht: Cells ist der numerische Zwilling von Range, und seine Argumente laufen Zeile zuerst. Sobald Sie das verinnerlicht haben, ergeben sowohl die Schleifenmuster als auch die Achsen-Vertauschungs-Bugs Sinn.

Was Sie lernen

  • Das mentale Modell — Cells ist Range, adressiert mit zwei Zahlen statt einem String
  • Die wichtigste Regel — Cells(row, column), also ist Cells(1, 2) B1, nicht A2
  • Einen Block aus berechneten Ecken bauen mit Range(Cells(...), Cells(...))
  • Warum ein blankes Cells ohne Index jede Zelle des Blatts meint
  • In einen bestehenden Bereich indizieren mit rng.Cells(i) und dessen zeilenweiser Reihenfolge
  • Wann Sie zu Range greifen und wann zu Cells — und warum Sie es nicht in einer Schleife tun

Das mentale Modell: Cells ist Range, adressiert per Zahl

Ein Zellbezug muss eine Frage beantworten — welche Zelle? — und VBA gibt Ihnen zwei Wege, das zu tun. Range("A1") antwortet mit einem String in Tabellennotation: erst der Spaltenbuchstabe, dann die Zeilennummer, genau so, wie Ihr Auge das Raster abtastet. Cells(1, 1) antwortet mit zwei Ganzzahlen: erst die Zeile, dann die Spalte.

ws.Range("B3").Value = 10    ' String-Adresse: Spalte B, Zeile 3
ws.Cells(3, 2).Value = 10    ' dieselbe Zelle als Zahlen: Zeile 3, Spalte 2

Sie zeigen auf dieselbe Zelle. Der entscheidende Unterschied ist, was Sie mit der Adresse anfangen können: ein String wie "B3" ist fester Text, aber Cells(3, 2) sind zwei Zahlen, die Sie berechnen können. Genau dafür gibt es Cells — es ist der Bezug, den Sie aus einem Zähler, einem UBound oder einer zur Laufzeit gefundenen Zeile heraus steuern können. Range ist für den Bereich, den Sie beim Namen kennen; Cells ist für die Position, die Sie im Code ermitteln.

Die wichtigste Regel: Cells ist (Zeile, Spalte), also ist Cells(1, 2) B1

Hier ist die Zeile, die jeden erwischt, der vom Tippen von "A2" kommt. Die Argumente sind erst die Zeile, dann die Spalte — nach unten vor quer — das Gegenteil der Reihenfolge „Buchstabe, dann Zahl“, die Sie auf dem Blatt lesen:

ws.Cells(1, 2).Value = "here"   ' Zeile 1, Spalte 2  =>  B1   (NICHT A2)
ws.Cells(2, 1).Value = "there"  ' Zeile 2, Spalte 1  =>  A2

Wenn Sie erwartet haben, dass Cells(1, 2) A2 ist, weil „A ist Spalte 1 und 2 ist die Zeile“, dann haben Sie es in Rasterreihenfolge gelesen; VBA liest es in Speicherreihenfolge. Eine verlässliche Merkregel: R vor C — Row (Zeile), dann Column (Spalte), dieselbe Reihenfolge wie in der R1C1-Notation und bei Matrix-Indizes. Machen Sie das in einer Schleife verkehrt herum, landet jeder Schreibvorgang eine Achse daneben, quer über das Blatt transponiert, ohne dass ein Fehler Sie warnt. Sagen Sie im Zweifel jedes Mal laut „Zeile r, Spalte c“.

Das Spaltenargument akzeptiert auch einen Buchstaben als String, was praktisch ist, wenn Sie die Spalte kennen, aber die Zeile berechnen:

ws.Cells(lastRow + 1, "C").Value = total   ' Zeile ist berechnet, Spalte C ist bekannt

Einen Block aus berechneten Ecken bauen: Range(Cells, Cells)

Cells adressiert eine einzelne Zelle, kann also für sich genommen keinen Block beschreiben. Das Idiom, das dynamische Bereiche erschließt, ist, zwei Cells-Aufrufe als Ecken eines Range zu übergeben:

Dim lastRow As Long, lastCol As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row       ' unteres Ende von Spalte A
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
' Den ganzen Datenblock aus zwei berechneten Ecken bauen:
Dim data As Range
Set data = ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol))   ' A1 : letzte Zelle

Das ist der Lohn dafür, Cells zu lernen: Range("A1") allein kann keine berechnete untere rechte Ecke aufnehmen, ohne einen String zusammenzukleben ("A" & lastRow), was in dem Moment bricht, in dem Ihre Spalten über Z hinausgehen. Range(Cells(1, 1), Cells(lastRow, lastCol)) bleibt numerisch und schert sich nie darum, wie breit die Daten sind. Von hier aus können Sie den Bezug mit Resize umformen oder Excel den Block für Sie finden lassen mit CurrentRegion.

Ein blankes Cells meint das ganze Blatt

Cells ohne Index ist kein Fehler und keine einzelne Zelle — es ist die Zellauflistung des gesamten Arbeitsblatts. Das ist für blattweite Operationen wirklich nützlich:

ws.Cells.ClearContents          ' jeden Wert auf dem Blatt loeschen
ws.Cells.Font.Name = "Calibri"  ' die Schriftart ueberall auf einmal setzen

Aber es ist auch eine Falle: ein blankes Cells, wo Sie eine bestimmte Zelle meinten, wirkt stillschweigend auf alle 1.048.576 × 16.384. Wenn ein Makro, das „eine Zelle formatieren“ soll, das ganze Blatt umformatiert, suchen Sie nach einem Cells, das seinen Index verloren hat. Die sichere Gewohnheit ist, Cells immer sein (row, column) zu geben, außer Sie meinen wirklich alles.

Cells innerhalb eines Bereichs und der lineare Index

Cells ist nicht nur eine Eigenschaft des Arbeitsblatts — es funktioniert auch relativ zu einem Bereich, wobei (1, 1) die obere linke Ecke dieses Bereichs ist und nicht A1:

Dim blk As Range: Set blk = ws.Range("C5:F20")
blk.Cells(1, 1).Value = "top-left of the block"   ' C5, nicht A1

Es gibt auch eine Ein-Index-Form, Cells(i), die die Zellen in zeilenweiser Reihenfolge durchläuft — von links nach rechts durch eine Zeile, dann hinunter zur nächsten:

blk.Cells(1).Value   ' C5   (erste Zelle)
blk.Cells(5).Value   ' C6   (vier quer durch den 4 Spalten breiten Block, dann Umbruch in die naechste Zeile)

Die Überraschung hier ist die Richtung: Cells(i) zählt quer vor hinunter, in einem Block aus 4 Spalten ist Zelle Nummer 5 also der Anfang der zweiten Zeile, nicht die fünfte Zeile. Wenn ein linearer Durchlauf an die falsche Stelle zu springen scheint, ist es fast immer diese zeilenweise Reihenfolge gegen eine spaltenweise Erwartung.

Range für Bereiche, Cells für Positionen — und keine Schleife darum

Die saubere Regel lautet nicht „bevorzuge eines“. Sie lautet: nehmen Sie Range für Bereiche, die Sie benennen, und Cells für Positionen, die Sie berechnen. Ein fester Berichtsbereich, ein benannter Block, eine Kopfzeile, die Sie einmal tippen — das ist Range("A1:D1"). Eine Zelle, deren Zeile oder Spalte Sie zur Laufzeit berechnen — das ist Cells(r, c). Sie lassen sich kombinieren: Range(Cells(...), Cells(...)) baut einen benannt geformten Block aus berechneten Ecken.

Das Einzige, dem Sie widerstehen sollten, ist zu Cells innerhalb einer Zelle-für-Zelle-Schleife zu greifen, wenn es eine Operation über den ganzen Bereich gibt. For r = 2 To lastRow: ws.Cells(r, 3).Value = ... zu schreiben fasst das Arbeitsblatt einmal pro Zeile an und ist der Hauptgrund, warum Makros kriechen. Der reife Zug ist, Cells zu nutzen, um die Ecken zu finden, den Range zu bauen und einmal auf den ganzen Block zu wirken — ein Array an Range(...).Value zuzuweisen oder eine native Methode aufzurufen (siehe WorksheetFunction). Cells ist, wie Sie die Arbeit verorten; es sollte nicht sein, wie Sie jede Einheit davon erledigen.

Wie ExcelMaster hilft

Cells gegen Range verbirgt mehr Entscheidungen, als es scheint: welches Argument die Zeile ist, ob ein blankes Cells gerade das ganze Blatt angefasst hat, ob ein linearer Index quer oder hinunter läuft und ob eine Schleife ein einziger Schreibvorgang über den ganzen Bereich hätte sein sollen. Jede falsche Abzweigung ist leise — ein Wert eine Achse daneben, eine blattweite Umformatierung, ein Makro, das kriecht.

ExcelMaster lässt Sie stattdessen das Ergebnis beschreiben. Sagen Sie „fülle Spalte C mit einer laufenden Summe bis zur letzten Datenzeile“, und es findet die letzte Zeile, baut Range(Cells(2, 3), Cells(lastRow, 3)) und schreibt die Werte in einem Durchgang — die Argumente Zeile zuerst korrekt, kein versehentliches blattweites Cells, keine Schleife pro Zelle. Sie behalten die Arbeitsmappe und den Code; Sie sparen sich den Durchgang, in dem die Schreibvorgänge transponiert landeten.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Cells und Range in Excel VBA?

Beide verweisen auf Zellen, aber sie adressieren sie unterschiedlich. Range("A1") nutzt einen String in Tabellennotation — Spaltenbuchstabe, dann Zeile. Cells(1, 1) nutzt zwei Zahlen — Zeile, dann Spalte. Weil die Argumente von Cells Zahlen sind, die Sie berechnen können, ist Cells das, was Sie in Schleifen und für zur Laufzeit ermittelte Positionen nehmen; Range ist für feste oder benannte Bereiche, die Sie beim Namen tippen. Sie kombinieren sich als Range(Cells(r1, c1), Cells(r2, c2)), um einen Block aus berechneten Ecken zu bauen.

Warum ist Cells(1, 2) die Zelle B1 und nicht A2?

Weil Cells seine Argumente erst die Zeile, dann die Spalte nimmt — das Gegenteil der Reihenfolge „Buchstabe, dann Zahl“, die Sie auf dem Raster lesen. Cells(1, 2) bedeutet Zeile 1, Spalte 2, also B1. Cells(2, 1) bedeutet Zeile 2, Spalte 1, also A2. Merken Sie sich „R vor C“ (Row, dann Column), dieselbe Reihenfolge wie in der R1C1-Notation.

Wie wähle ich mit Cells einen Zellbereich in VBA aus?

Übergeben Sie zwei Cells-Aufrufe als Ecken eines Range: Range(Cells(1, 1), Cells(10, 4)) ist A1:D10. Das ist der Standardweg, einen Block zu bauen, wenn die Ecken berechnet sind, zum Beispiel Range(Cells(2, 1), Cells(lastRow, lastCol)). Qualifizieren Sie sowohl Cells als auch den Range mit demselben Arbeitsblatt, damit der Bezug nicht auf das gerade aktive Blatt zeigt.

Was macht Cells ohne Argumente in VBA?

Ein blankes Cells (ohne Index) verweist auf jede Zelle des Arbeitsblatts. Cells.ClearContents leert das ganze Blatt, und Cells.Font.Size = 11 setzt jede Zelle. Das ist für blattweite Änderungen nützlich, bedeutet aber auch, dass ein Cells, das seinen (row, column)-Index verloren hat, stillschweigend auf das gesamte Blatt wirkt — indizieren Sie es also immer, wenn Sie eine bestimmte Zelle meinen.

Kann ich mit Cells einen Spaltenbuchstaben statt einer Zahl nutzen?

Ja. Das Spaltenargument akzeptiert einen String, Cells(2, "B") ist also dasselbe wie Cells(2, 2) (Zelle B2). Das Zeilenargument muss eine Zahl sein. Ein Buchstabe ist praktisch, wenn Sie die Spalte kennen, aber die Zeile berechnen, etwa Cells(lastRow + 1, "C").

Getestet in

Getestet in: Excel 365 (Windows 11), VBA 7.1 — zuletzt geprüft am 15.08.2026.

Verwandte Anleitungen: VBA Range · VBA Resize · VBA CurrentRegion · VBA Offset · VBA For-Schleife