配列のインデックス付けがCではゼロで始まり、1ではないのはなぜですか?
配列のインデックス付けがCではゼロで始まり、1ではないのはなぜですか?
回答:
Cでは、配列の名前は基本的にポインタ[コメントを参照]であり、メモリロケーションへの参照であるため、式array[n]
はn
開始要素から離れたメモリロケーション要素を参照します。これは、インデックスがオフセットとして使用されることを意味します。配列の最初の要素は、配列が参照するメモリ位置(0要素離れている)に正確に含まれているため、と表記する必要がありますarray[0]
。
詳細については:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
sizeof arr
ポインターのサイズではなく、配列オブジェクトのサイズを生成します。
sizeof
、または&
配列の初期化に使用される文字列リテラル、タイプ" array "の式を除くof type "は、配列オブジェクトの最初の要素を指し、左辺値ではないタイプ" pointer to type "の式に変換されます。配列オブジェクトにレジスターストレージクラスがある場合、動作は未定義です。 "
この質問は1年以上前に投稿されましたが、これは...
一方でダイクストラの記事(以前今-削除で参照答えは)数学的な観点から理にかなって、それが関連するようではありません、それはプログラミングに来るとき。
言語仕様とコンパイラ設計者による決定は、コンピュータシステム設計者が0からカウントを開始するという決定に基づいています。
ダニー・コーエンによる「平和のための嘆願」からの引用。
基数bの場合、最初のb ^ N の負でない整数は、番号付けが0から始まる場合にのみ、正確にN桁(先行ゼロを含む)で表されます。
これは非常に簡単にテストできます。base-2では、2^3 = 8
8番目の数値は次のとおりです。
111
3
ビットを使用して表現できます1000
が、追加のビット(4ビット)が必要になります。
コンピュータのメモリアドレスには2^N
、N
ビットでアドレス指定されたセルがあります。ここで、1から数え始めると、2^N
セルにはN+1
アドレス行が必要になります。正確に1つのアドレスにアクセスするには、追加ビットが必要です。(1000
上記の場合)。それを解決する別の方法は、最後のアドレスにアクセスできないままにして、N
アドレス行を使用することです。
どちらも次の最適解ではありません。カウントを0から開始すると、正確にN
住所行を使用してすべての住所にアクセスできるようになるからです。
カウントを開始するという決定0
は、その上で実行されているソフトウェアを含むすべてのデジタルシステムに浸透しました。これにより、基になるシステムが解釈できるものにコードを簡単に変換できるようになるためです。そうでない場合は、アレイへのアクセスごとに、マシンとプログラマの間で1つの不要な変換操作が発生します。コンパイルが簡単になります。
論文からの引用:
a[b]
同じよう*(a+b)
に実装されました。今日でも、の2[a]
代わりに書くことができますa[2]
。インデックスは0から開始しなかった場合、さてa[b]
に変わるでしょう*(a+b-1)
。これは、CPUに0の代わりに2つの追加を必要とし、速度が半分になります。明らかに望ましくない。
0ベースのインデックスでは...
array[index]
...として実装される...
*(array + index)
インデックスが1から始まる場合、コンパイラーは以下を生成する必要があり*(array + index - 1)
ます。この "-1"はパフォーマンスを低下させます。
コンパイラとリンカがよりシンプルになった(書くのが簡単になった)ため。
参照:
「...アドレスとオフセットによってメモリを参照することは、事実上すべてのコンピュータアーキテクチャ上のハードウェアで直接表されるため、このCの設計の詳細により、コンパイルが容易になります。」
そして
「...これにより、実装が簡単になります...」
配列インデックスは常にゼロから始まりますarr[i] = *(arr+i)
。ベースアドレスが2000であると仮定します。さてif i= 0
、これは*(2000+0
)がベースアドレスまたは配列の最初の要素のアドレスに等しいことを意味します。このインデックスはオフセットとして扱われるため、デフォルトのインデックスはゼロから始まります。
同じ理由で、水曜日で誰かが水曜日までの日数を尋ねた場合、1ではなく0と答え、水曜日で誰かが木曜日までの日数を尋ねた場合、2ではなく1と答えます。
私がゼロベースの番号付けについて読んだ最もエレガントな説明は、値がナンバーラインのマークされた場所ではなく、それらの間のスペースに格納されているという観察です。最初のアイテムは0と1の間に保存され、次は1と2の間に保存されます。N番目のアイテムはN-1とNの間に保存されます。アイテムの範囲は、両側の数字を使用して記述できます。個々のアイテムは、慣例により、その下の番号を使用して説明されています。範囲(X、Y)が指定されている場合、以下の番号を使用して個々の番号を識別することは、算術を使用せずに最初の項目を識別できることを意味します(項目X)、Yから1を引いて最後の項目(Y -1)。上記の番号を使用してアイテムを識別すると、範囲内の最後のアイテム(アイテムY)を識別しやすくなります。
それらの上にある数に基づいてアイテムを識別することは恐ろしいことではありませんが、範囲(X、Y)の最初のアイテムをXの上にあるものとして定義すると、通常、下のアイテム(X + 1)。
1ベースのマトリックスのX、Y座標を使用してピクセルスクリーンにアクセスしてみます。式は完全に複雑です。なぜ複雑なのですか?X、Y座標を1つの数値、つまりオフセットに変換することになるからです。X、Yをオフセットに変換する必要があるのはなぜですか?それは、メモリセル(アレイ)の連続したストリームとして、メモリがコンピュータ内部でどのように編成されているかです。コンピューターはどのようにアレイセルを処理しますか?オフセットの使用(最初のセルからの変位、ゼロベースのインデックスモデル)。
したがって、コードのある時点で、1ベースの数式を0ベースの数式に変換する必要があります(またはコンパイラが必要です)。これが、コンピュータがメモリを処理する方法です。
サイズ5の配列を作成するとします
。array[5] = [2,3,5,9,8]
配列の最初の要素が位置100
を指し、インデックス付けが1ではなく、 0.
整数のサイズは4ビットな
ので
、インデックスを使用して最初の要素の場所を見つける必要があります
(最初の要素の場所は100であることを忘れないでください)。したがって、インデックス1を考えると、位置は
サイズになります。 index(1)* integer(4)のサイズ= 4
なので、実際に表示される位置は
100 + 4 = 104です
最初の場所は100であったので、真実ではない
、それは104になっていない100を指している必要があり
、これは間違っている
今、私たちは0からインデックスをとっていると仮定し
、その後
第一の要素の位置があるべき
整数のインデックス(0)のサイズ*サイズ(4)= 0
したがって、->
最初の要素の位置は100 + 0 = 100で
あり、
これが要素の実際の位置でした。これが、インデックス付けが0から始まる理由です。
それがあなたの要点を明確にすることを願っています。
まず、「配列の名前自体に配列の最初の要素のアドレスが含まれている」ため、配列は内部的にポインタと見なされることを知る必要があります。
ex. int arr[2] = {5,4};
配列がアドレス100から始まることを考慮して、要素の最初の要素がアドレス100になり、2番目が104になるようにします。配列のインデックスが1から始まる場合を考えてください。
arr[1]:-
これは、このようにポインタ式で書くことができます-
arr[1] = *(arr + 1 * (size of single element of array));
intのサイズが4バイトだとしましょう。
arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);
配列名には最初の要素のアドレスが含まれているので、arr = 100になりました。
arr[1] = *(100 + 4);
arr[1] = *(104);
それは与える
arr[1] = 4;
この式のため、公式の最初の要素であるアドレス100の要素にアクセスできません。
配列のインデックスは0から始まるので、
arr[0]:-
これは次のように解決されます
arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);
これで、配列名に最初の要素のアドレスが含まれていることがわかりました。
arr[0] = *(100);
正しい結果を与える
arr[0] = 5;
したがって、配列のインデックスは常にcの0から始まります。
参照:詳細はすべて「ブライアン・カーニングハンとデニス・リッチーによるCプログラミング言語」の本に書かれています
これは、配列内でaddress
右を指す必要があるためelement
です。以下の配列を想定しましょう:
let arr = [10, 20, 40, 60];
次に、アドレスの開始とbeの12
サイズについて考えてみましょう。element
4 bytes
address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24
それがあった場合にはない zero-based
、では技術的に私たちの最初の要素のアドレスarray
になり16
、それの場所があるように間違っています12
。
配列名は、ベースアドレスを指す定数ポインターです。arr[i]を使用すると、コンパイラーはそれを*(arr + i)として操作します。intの範囲は-128〜127であるため、コンパイラーは-128〜-1が負の数と0〜128は正の数であるため、配列のインデックスは常にゼロから始まります。
int
タイプは、少なくとも16ビットの範囲をサポートするために必要な、そしてほとんどのシステムで、これらの日は、32ビットをサポートしています。私はあなたの論理に欠陥があると思います、そしてあなたの答えは本当に他の人々によってすでに提供されている他の答えを改善しません。これを削除することをお勧めします。