3

私は自分の本(およびインターネット上の多くの情報源)でこれを読みました:

配列変数は、配列の最初の要素を指します。

これが真の場合、配列変数と最初の要素が異なります。右?

これは、以下のコードによって、2 つの異なる結果が生成されることを意味します。

int main(){
    char msg[] = "stack over flow";
    printf("the store string is store at :%p\n",&msg);
    printf("First element: %p\n",&msg[0]);
}

しかし、2 つのケースで同じ結果が得られます。したがって、この例では、配列変数が最初の要素であると言うべきだと思います。(住所が同じなので)

これが正しいか間違っているかはわかりません。教えて下さい。

4

7 に答える 7

8

配列変数は、配列の最初の要素だけでなく、配列が占有するメモリ ブロック全体を意味します。Soarrayは(cf. )と同じではありません。ただし、配列の最初の要素は、配列自体と同じメモリ アドレスにあります。array[0]sizeof array / sizeof array[0]

配列が最初の要素を指していると言うことも正しくありません。ほとんどの場合、配列式は最初の要素へのポインターに崩壊しますが、それらは別のものsizeofです (例を参照)。

于 2012-08-09T13:56:23.970 に答える
5

これらは同じアドレスを指します。つまりprintf、同じ値を示しますが、タイプが異なります。

  • isの型&msgchar(*)[16]、char の配列 16 へのポインタ
  • &msg[0]isの型はchar *char へのポインタ

これをテストする簡単な方法は、ポインター演算を行うことです。印刷してみてください&msg + 1

このC FAQが役に立つかもしれません。

于 2012-08-09T13:55:44.303 に答える
5

配列変数配列全体です。配列の最初の要素へのポインターに崩壊します。

タイプを見ると:

  • msgタイプですchar [16]
  • &msgタイプですchar (*)[16]
  • &msg[0]タイプですchar *

msgしたがって、たとえば引数として渡された場合など、配列に減衰できるコンテキストでは、その値は に等しくなり&msg[0]ます。

これを描きましょう:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|s|t|a|c|k| |o|v|e|r| |f|l|o|w|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+

が配置されているこの配列の開始点を想像してください's'address 0x12345678

  • msgそれ自体は、メモリの 16 バイト全体を指します。あなたが言うときのように、4バイトのメモリint a;a指します。
  • msg[0]その 16 バイトの最初のバイトです。
  • &msg配列が始まるアドレスです。0x12345678
  • &msg[0]は配列の最初の要素のアドレスです:0x12345678

&msgこれが、との値&msg[0]が同じである理由ですが、それらの型は異なります。

問題は、msgそれ自体が一級市民ではないということです。たとえば、配列を割り当てることはできません。そのため、ほとんどの場合、配列はそのポインターに崩壊します。

関数ポインターを知っている場合、これは非常に似ています。

int array[10];
int function(int);
  • ではint *var = arrayarrayポインターに減衰します ( &array)
  • ではvoid *var = functionfunctionポインターに減衰します ( &function)

関数ポインターの場合、型を保持したいので、次のように記述します。

int (*var)(int) = function;

同様に、配列でも次のことができます。

int (*var)[10] = array;
于 2012-08-09T13:57:10.433 に答える
2
char myChar = 'A'
char msg[] = 'ABCDEFGH'

myCharと入力すると、値が得られます。しかし、msgを使用すると、最初の文字へのポインターを取得します (値には msg[x] を使用する必要があります)。

msg = &msg[0]

これで理解できると思います。

于 2012-08-09T14:01:18.007 に答える
1

配列式を使用すると、コンパイラはそれを最初の要素へのポインターに変換します。&array[0]これは、1999 C 標準の 6.3.2.1 3 で指定された明示的な変換です。最初の要素へのポインターを取得するために記述する必要がないため、便利です。

変換は、配列式が のオペランドsizeofまたは単項である場合、&または配列の初期化に使用される文字列リテラルである場合を除き、すべての式で発生します。

sizeof arrayと を出力すると、配列とその最初の要素が異なることがわかりますsizeof array[0]

于 2012-08-09T14:32:11.443 に答える
1

このように見てください:

&msg = 0x0012
&msg[0] = 0x0012
&msg[1] = 0x0013

この場合&msg[1]は を指していmsg+1ます。これがポインタの開始場所であるため、メモリの同じアドレスを参照するか&msg、参照している場合。&msg[0]char 変数のサイズは 1 バイトしかないため、配列変数をインクリメントするとポインタが +1 インクリメントされます。

たとえば整数で同じトリックを行うと、整数のサイズは 4 バイトであるため、ポインターを +4 バイトずつインクリメントします。

于 2012-08-09T14:02:13.813 に答える
1

ほとんどの場合、配列型 (「の N 要素配列」) のは、ポインター型 (「へのポインター」)Tの式に「減衰」する / 変換される / に置き換えられ、式のは次のようになります。配列の最初の要素のアドレス。 T

したがって、宣言を仮定すると

int a[10];

式の型は、a「の 10 要素配列int」、またはint [10]です。ただし、ほとんどのコンテキストでは、式の型は「へのポインタint」またはint *に変換され、式の値は と同等になり&a[0]ます。

この規則の例外は、配列式がsizeofまたは 単項演算子のオペランドである場合&、または宣言で別の配列を初期化するために使用される文字列リテラルである場合です。

したがって、上記の宣言に基づいて、次のすべてが当てはまります。

  式のタイプは値に減衰します
  ---------- ---- --------- -----
           a int [10] int * a の最初の要素のアドレス
          &a int (*)[10] n/a 配列のアドレス。
                                            最初のアドレスと同じ
                                            エレメント
       &a[0] int * n/a の最初の要素のアドレス
          *a int 該当なし a[0] の値
    sizeof a size_t n/配列内のバイト数
                                            (10 * sizeof (int))
   sizeof &a size_t 該当なし へのポインタのバイト数
                                           int の配列
   sizeof *a size_t 該当なし int のバイト数
sizeof &a[0] size_t n/int へのポインタのバイト数

a&a、および&a[0]はすべて同じ( の最初の要素のアドレス) を持ちますaが、型が異なることに注意してください。タイプは重要です。次のことを前提とします。

int a[10];
int *p = a;
int (*pa)[10] = &a;

と の両方が の最初の要素ppa指しています。aこれはアドレス にあると仮定します0x8000。行を実行した後

p++;
pa++;

ただし、p次の整数( 0x8004、4 バイトintの s と仮定) をpa指し、整数の次の 10 要素配列を指します。つまり、a( 0x8028) の最後の要素の後の最初の整数です。

于 2012-08-09T14:42:43.060 に答える