重複の可能性:
配列名はCのポインターですか?
私が定義した場合:
int tab[4];
tabを表示すると、次のようになります。
printf("%d", tab);
上記のコードは、メモリ内の最初の要素へのアドレスを表示します。
そのため、次のような配列を定義しないのはなぜだろうと思っていました。
int *tab[4];
タブはポインタです。
助けてくれてありがとう!
重複の可能性:
配列名はCのポインターですか?
私が定義した場合:
int tab[4];
tabを表示すると、次のようになります。
printf("%d", tab);
上記のコードは、メモリ内の最初の要素へのアドレスを表示します。
そのため、次のような配列を定義しないのはなぜだろうと思っていました。
int *tab[4];
タブはポインタです。
助けてくれてありがとう!
タブはポインタです
いいえ、tab
配列です。具体int[4]
的に。ただし、関数の引数として(および他の多くのコンテキストで)渡すと、配列は最初の要素へのポインターに変換されます。配列とポインタの違いを確認できます。たとえば、呼び出したときと、配列にsizeof array
割り当てよsizeof pointer
うとしたとき(コンパイルされないとき)などです。
int *tab[4];
への4つのポインタの配列を宣言しint
ます。それが配列とポインタの間の混乱にどのように関係しているかわかりません。
tab
はポインターではなく、関数に渡されると 4 つの整数の配列であり、最初の要素へのポインターに崩壊します。
int tab[4];
これは別の配列ですが、4 つの整数ポインターを保持しています。
int *tab[4];
最後に、完全を期すために、これは 4 つの整数の配列へのポインターです。これを逆参照すると、4 つの整数の配列が得られます。
int (*tab)[4];
あなたは完全に間違っているわけではありません。つまり、あなたの発言は間違っていますが、真実からそれほど離れていないということです。
C における配列とポインターは同じ算術演算を共有しますが、主な違いは、配列はコンテナーであり、ポインターは他のアトミック変数と同様であり、それらの目的はメモリ アドレスを格納し、ポイントされた値の型に関する情報を提供することです。
について何かを読むことをお勧めしますpointer arithmetic
Steve Jessopのコメントを考慮して、ポインター演算のシンプルで効果的な世界を紹介できるスニペットを追加したいと思います。
#include <stdio.h>
int main()
{
int arr[10] = {10,11,12,13,14,15,16,17,18,19};
int pos = 3;
printf("Arithmetic part 1 %d\n",arr[pos]);
printf("Arithmetic part 2 %d\n",pos[arr]);
return(0);
}
配列はポインターのように振る舞うことができ、あなたのケースではポインターのように見えても、ポインターではないことでまったく同じ種類の算術演算を適用できます。
int *tab[4];
この定義は、tab
配列に含まれるものと含まれpointers of int
ないものを意味しますint
C規格から
コーディングガイドライン
配列オブジェクトを最初の要素へのポインターに暗黙的に変換することは、Cで配列のより強力な型チェックを作成しようとする際に非常に不便です。経験の浅い、C言語では、開発者は配列とポインターをこれで許可されているよりもはるかに厳密に同一視することがあります。要件(宣言ではなく、式での使用に適用されます)。たとえば、次のようになります。
file_1.c
extern int *a;
file_2.c
extern int a[10];
aの2つの宣言は、開発者によって互換性があると誤って想定されることがあります。どのガイドラインの推奨事項が誤った開発者の仮定(または不十分なトレーニング)を克服するかを確認することは困難です。単一の宣言ポイントを指定するガイドラインの推奨事項に従っている場合、この問題は1つのファイルで宣言された419.1識別子では発生しません。関数指定子の使用法とは異なり、開発者は、配列関数指定子がtypetypeに変換されたオブジェクトが、最初の要素へのポインターに暗黙的に変換されるという事実に精通しています。単項&演算子を配列型のオペランドに適用すると、読者に役立つ視覚的な手がかりが得られるのか、作成者の意図(「そこで冗長な演算子は何をしているのか」)について疑問に思うようになるのかは不明です。
例
static double a[5];
void f(double b[5])
{
double (*p)[5] = &a;
double **q = &b; /* This looks suspicious, */
p = &b; /* and so does this. */
q = &a;
}
配列オブジェクトにレジスタストレージクラスがある場合、動作は定義されていません
ほとんどの場合、配列型の式はポインター型の式に変換 (「減衰」) され、式の値は配列の最初の要素のアドレスになります。この規則の例外は、配列式がsizeof
、_Alignof
、または単項演算子のオペランドである場合、または&
宣言で別の配列を初期化するために使用される文字列リテラルである場合です。
int tab[4];
tab
の場合、4 要素配列として定義されint
ます。声明では
printf("%d", tab); // which *should* be printf("%p", (void*) tab);
式 は、tab
「の 4 要素配列」型から「へのint
ポインタ」型に変換されますint
。