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

Excel VBA の Cells と Range — セルを数値で参照する(そしてなぜ Cells(1, 2) は A2 ではなく B1 なのか)

|

Excel VBA の Cells と Range — セルを数値で参照する(そしてなぜ Cells(1, 2) は A2 ではなく B1 なのか)

TL;DRCellsRange数値でアドレス指定したものです。Range("A1") は、 読む順(列の文字、次に行番号)どおりの文字列でセルを指します。Cells(row, column) は、 Excel が格納する順 — まず行、次に列 — の 2 つの整数で 1 つのセルを指すので、 Cells(1, 2) は A2 ではなく B1 になります。どちらの座標も計算できる数値なので、 Cells はループのために作られた参照です。名前で打ち込む範囲には Range を、計算で求める 位置には Cells を使い、計算した角からブロックを組むには Range(Cells(1, 1), Cells(n, k)) を 使いましょう。

Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Data")
' Range は固定の範囲を名指しし、Cells は位置を行優先で計算する。
ws.Range("A1").Value = "Header"          ' 人間向けの書き方 - 打ち込んだアドレス
ws.Cells(2, 1).Value = "First row"       ' 行 2、列 1 = A2(B2 ではない)

セルを参照することは、どんなマクロも最初に行う作業であり、CellsRange は誰もが最初に つまずく場所でもあります。混乱の原因は、どちらが優れているかではありません — 両者はセルの アドレス指定の仕方が違い、その順番を取り違えると、無言で間違った場所に書き込んでしまうの です。本記事は、残りを予測可能にする 1 つの考えを軸にしています。CellsRange の数値版 であり、その引数は行が先に来る。 これを押さえれば、ループのパターンも、向きが入れ替わるバグ も、どちらも腑に落ちます。

この記事で学べること

  • 考え方の軸 — CellsRange を文字列ではなく 2 つの数値でアドレス指定したもの
  • 最も大事なルール — Cells(row, column) なので、Cells(1, 2) は A2 ではなく B1
  • Range(Cells(...), Cells(...)) で計算した角からブロックを組む
  • 添字のない素の Cells がシート上のすべてのセルを意味する理由
  • 既存の範囲に対する rng.Cells(i) での添字づけと、その行優先の順序
  • RangeCells のどちらに手を伸ばすか — そしてなぜループで使ってはいけないのか

考え方の軸:Cells は Range を数値でアドレス指定する

セル参照は 1 つの問い — どのセル? — に答えなければならず、VBA はその答え方を 2 つ用意して います。Range("A1") は、スプレッドシート記法の文字列で答えます。 まず列の文字、次に行番号 — ちょうど目でグリッドをたどる順です。Cells(1, 1)2 つの整数 で答えます。まず行、次に列です。

ws.Range("B3").Value = 10    ' 文字列アドレス: 列 B、行 3
ws.Cells(3, 2).Value = 10    ' 同じセルを数値で: 行 3、列 2

どちらも同じセルを指します。効いてくる違いは、そのアドレスで何ができるかです。"B3" のような 文字列は固定のテキストですが、Cells(3, 2)計算できる 2 つの数値です。それこそが Cells の存在理由のすべてです — カウンター、UBound、あるいは実行時に見つけた行から動かせる参照な のです。Range は名前で分かっている範囲のため、Cells はコードの中で割り出す位置のための ものです。

最も大事なルール:Cells は (row, column) なので Cells(1, 2) は B1

"A2" と打ち込むことに慣れた人が、誰もつまずくのがこの 1 行です。引数はまず行、次に列 — 横より先に縦 — で、シート上で読む「文字、次に数字」の順とは逆です。

ws.Cells(1, 2).Value = "here"   ' 行 1、列 2  =>  B1(A2 ではない)
ws.Cells(2, 1).Value = "there"  ' 行 2、列 1  =>  A2

「A が 1 列目で 2 が行だから」Cells(1, 2) は A2 のはず、と思ったなら、それはグリッドの順で 読んでいます。VBA は格納の順で読みます。確実な覚え方は R が先、次に C — Row(行)、そして Column(列)の順で、R1C1 記法や行列の添字と同じです。ループの中でこれを逆にすると、書き込みは すべて 1 つの軸だけずれ、シート上で行と列が入れ替わり、警告するエラーも出ません。迷ったら 毎回、「行 r、列 c」と声に出して読みましょう。

列の引数は、文字列としての列文字も受け取ります。列は分かっているけれど行を計算する場合に 便利です。

ws.Cells(lastRow + 1, "C").Value = total   ' 行は計算、列 C は既知

計算した角からブロックを組む:Range(Cells, Cells)

Cells は 1 つのセルをアドレス指定するので、それだけではブロックを表せません。動的な範囲を 可能にする定番イディオムは、2 つの Cells 呼び出しを Range の角として渡す ことです。

Dim lastRow As Long, lastCol As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row       ' A 列の一番下
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
' 計算した 2 つの角からデータブロック全体を組む:
Dim data As Range
Set data = ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol))   ' A1 から最後のセルまで

これが Cells を学ぶ見返りです。Range("A1") 単体では、文字列を継ぎ合わせる("A" & lastRow) ことなしに計算した右下の角を扱えず、しかもそれは列が Z を越えた瞬間に壊れます。 Range(Cells(1, 1), Cells(lastRow, lastCol)) は数値のままで、データの幅がどれだけあっても 気にしません。ここから先は、Resize で参照の形を変えるか、 CurrentRegion で Excel にブロックを見つけさせることができます。

素の Cells はシート全体を意味する

添字のない Cells は、エラーでも 1 つのセルでもありません — ワークシート全体のセル コレクションです。これはシート全体への操作に実際に役立ちます。

ws.Cells.ClearContents          ' シート上のすべての値を消去する
ws.Cells.Font.Name = "Calibri"  ' フォントを一度に全体へ設定する

しかしこれは罠でもあります。特定の 1 つのセルを意図した場所で素の Cells を使うと、 1,048,576 × 16,384 のすべてのセルに静かに作用します。「1 つのセルを書式設定する」はずの マクロがシート全体を再書式設定するなら、添字を失った Cells を探しましょう。安全な習慣は、 本当に全部を意味するのでない限り、Cells には必ず (row, column) を与えることです。

範囲の中の Cells と、線形の添字

Cells はワークシートのプロパティだけではありません — 範囲に対して相対的にも働き、そこ では (1, 1) は A1 ではなく、その範囲自身の左上の角になります。

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

単一添字の形 Cells(i) もあり、これは**行優先(row-major)**の順でセルをたどります — まず行を左から右へ、それから次の行へ下ります。

blk.Cells(1).Value   ' C5   (最初のセル)
blk.Cells(5).Value   ' C6   (幅 4 のブロックを 4 つ進み、次の行へ折り返す)

ここで意外なのは方向です。Cells(i)下より先に横へ数えるので、4 列のブロックでは 5 番目のセルは 5 行目ではなく 2 行目の先頭です。線形にたどっていて変な場所へ飛ぶように 見えるなら、それはほぼ必ず、列優先を期待しているのに実際は行優先だから、です。

範囲には Range、位置には Cells — そしてループで回さない

すっきりしたルールは「どちらか一方を選べ」ではありません。名前で指す範囲には Range、 計算で求める位置には Cells です。固定のレポート領域、名前付きのブロック、一度だけ打ち込む 見出し行 — それは Range("A1:D1") です。行や列を実行時に計算するセル — それは Cells(r, c) です。両者は組み合わさります。Range(Cells(...), Cells(...)) は、計算した角から名前付きのような 形のブロックを組みます。

避けたい唯一のことは、範囲全体への操作があるのに、1 セルずつのループの中で Cells に 手を伸ばすことです。For r = 2 To lastRow: ws.Cells(r, 3).Value = ... と書くと、行ごとに 1 回 ワークシートに触れることになり、マクロが遅くなる第 1 位の原因になります。成熟したやり方は、 Cellsを見つけ、Range を組み、ブロック全体に一度で作用させることです — 配列を Range(...).Value に代入するか、ネイティブのメソッドを呼びます( WorksheetFunction を参照)。Cells は作業を見つけるための 道具であって、1 単位ずつ実行するための道具ではありません。

ExcelMaster の活用

CellsRange は、見た目以上に多くの判断を隠しています。どちらの引数が行なのか、素の Cells がたった今シート全体に触れてしまったのか、線形の添字は横に進むのか下に進むのか、 そしてループは範囲全体への 1 回の書き込みであるべきだったのか。どの選択を間違えても静かです — 1 つの軸だけずれた値、シート全体の再書式設定、遅くて仕方のないマクロ。

ExcelMaster なら、代わりに結果を 説明するだけで済みます。「C 列に、データの最終行まで累計を書き込んで」と言えば、最終行を 見つけ、Range(Cells(2, 3), Cells(lastRow, 3)) を組み、値を 1 回のパスで書き込みます — 行が先の 引数は正しく、うっかりシート全体を指す Cells もなく、1 セルずつのループもありません。ブックも コードもあなたの手元に残り、書き込みが行と列が入れ替わって着地する、あの一幕を飛ばせます。

よくある質問

Excel VBA で Cells と Range の違いは何ですか?

どちらもセルを指しますが、アドレス指定の仕方が違います。Range("A1") はスプレッドシート記法の 文字列 — 列の文字、次に行 — を使います。Cells(1, 1)2 つの数値 — 行、次に列 — を 使います。Cells の引数は計算できる数値なので、Cells はループの中や実行時に割り出す位置に 使い、Range は名前で打ち込む固定の範囲や名前付きの範囲に使います。両者は Range(Cells(r1, c1), Cells(r2, c2)) として組み合わさり、計算した角からブロックを作ります。

なぜ Cells(1, 2) は A2 ではなく B1 なのですか?

Cells は引数をまず行、次に列の順で取るからです — グリッドで読む「文字、次に数字」の順とは 逆です。Cells(1, 2) は行 1、列 2 を意味し、これは B1 です。Cells(2, 1) は行 2、列 1 を 意味し、これは A2 です。「R が先、次に C」(行、次に列)と覚えましょう。R1C1 記法と同じ順です。

VBA で Cells を使ってセル範囲を選択するには?

2 つの Cells 呼び出しを Range の角として渡します。Range(Cells(1, 1), Cells(10, 4)) は A1:D10 です。これは角を計算で求めるときにブロックを組む標準的な方法で、たとえば Range(Cells(2, 1), Cells(lastRow, lastCol)) のように書きます。参照がたまたまアクティブな シートを指さないよう、CellsRange の両方を同じワークシートで修飾しましょう。

VBA で引数なしの Cells は何をしますか?

素の Cells(添字なし)は、ワークシート上のすべてのセルを指します。Cells.ClearContents はシート全体を消去し、Cells.Font.Size = 11 はすべてのセルに設定します。これはシート全体の 変更に役立ちますが、同時に、(row, column) の添字を失った Cells はシート全体に静かに作用する ということでもあります — なので、特定のセルを意味するときは必ず添字を付けましょう。

Cells で数値の代わりに列文字を使えますか?

はい。列の引数は文字列を受け取るので、Cells(2, "B")Cells(2, 2)(セル B2)と同じです。 行の引数は数値でなければなりません。列は分かっているけれど行を計算する場合、たとえば Cells(lastRow + 1, "C") のように、文字を使うと便利です。

検証環境

検証環境: Excel 365(Windows 11)、VBA 7.1 — 最終確認 2026-08-15。

関連ガイド: VBA Range · VBA Resize · VBA CurrentRegion · VBA Offset · VBA For Loop