4

Cで次のコードを書きました:

#include<stdio.h>

int  main()
{
  int a[10][10]={1};
  //------------------------
  printf("%d\n",&a);
  printf("%d\n",a);
  printf("%d\n",*a);
  //-------------------------
  printf("%d",**a);

  return 0;
}

上記の 3 つの printf ステートメントで、同じ値が得られました。私のマシンでは2686384です。しかし、最後のステートメントでは1になりました。

何かおかしいのではないですか?これらのステートメントは、次のことを意味します。

  1. のアドレスaは 2686384 です
  2. に格納されている値aは 2686384 です
  3. が指す変数のアドレスa(つまり 2686384) に格納される値は 2686384 です。

これはa、自分自身を指す変数のようなものでなければならないことを意味します...

では、なぜ出力が*(*a)1 になるのでしょうか。と評価されないのはなぜ*(*a)=*(2686384)=2686384ですか?

4

7 に答える 7

2
#include<stdio.h>

int  main()
{
  // a[row][col]
  int a[2][2]={ {9, 2}, {3, 4} };
  // in C, multidimensional arrays are really one dimensional, but
  // syntax alows us to access it as a two dimensional (like here).

  //------------------------
  printf("&a            = %d\n",&a);
  printf("a             = %d\n",a);
  printf("*a            = %d\n",*a);
  //-------------------------

  // Thing to have in mind here, that may be confusing is:
  // since we can access array values through 2 dimensions,
  // we need 2 stars(asterisk), right? Right.

  // So as a consistency in this aproach,
  // even if we are asking for first value,
  // we have to use 2 dimensional (we have a 2D array)
  // access syntax - 2 stars.

  printf("**a           = %d\n", **a );         // this says a[0][0] or *(*(a+0)+0)
  printf("**(a+1)       = %d\n", **(a+1) );     // a[1][0] or *(*(a+1)+0)
  printf("*(*(a+1)+1)   = %d\n", *(*(a+1)+1) ); // a[1][1] or *(*(a+1)+1)
  // a[1] gives us the value on that position,
  // since that value is pointer, &a[i] returns a pointer value
  printf("&a[1]         = %d\n", &a[1]);
  // When we add int to a pointer (eg. a+1),
  // really we are adding the lenth of a type
  // to which pointer is directing - here we go to the next element in an array.

  // In C, you can manipulate array variables practically like pointers.
  // Example: littleFunction(int [] arr) accepts pointers to int, and it works vice versa,
  //          littleFunction(int* arr) accepts array of int.

  int b = 8;
  printf("b             = %d\n", *&b);

  return 0;

}
于 2014-02-01T02:53:48.850 に答える
1

配列の名前で構成される式は、配列の最初の要素へのポインターに減衰する可能性があります。したがって、aタイプはですがint[10][10]、に減衰する可能性がありint(*)[10]ます。

さて、この崩壊は式で起こります*a。したがって、式のタイプはint[10]です。同じロジックを繰り返すと、これは再びに減衰しint*、さらに、配列の最初の要素の最初の要素、つまり、に減衰します。**ainta1

他の3つのprintステートメントは、それぞれ、配列のアドレス、配列の最初の要素、および配列の最初の要素の最初の要素を出力します(もちろん、これらはすべて同じアドレスであり、タイプが異なります)。

于 2012-09-21T11:30:49.343 に答える
1

まず、配列について一言...

、、、または単項演算子のoperand0であるsizeof場合、または宣言内の別の配列を初期化するために使用される文字列リテラルである場合を除き、 「N要素配列」型のは変換(「減衰」)されます。タイプ「ポインタ」の式。式の値は、配列の最初の要素のアドレスになります。 _Alignof&TT

式の&a型は「10要素配列の10要素配列へのポインタint」またはint (*)[10][10]。式のaタイプは「10要素配列の10要素配列int」であり、上記の規則により、「ポインタから10要素配列のint」またはに減衰しますint (*)[10]。そして最後に、式*a(と同等a[0])のタイプは「10要素の配列int」であり、これも上記の規則により「ポインタ」に減衰しますint

配列のアドレスとその最初の要素のアドレスが同じであるため、3つの式はすべて同じ値になります: &a[0][0]== a[0]====== 。ただし、式のタイプは異なります。これは、ポインター演算を行うときに重要です。たとえば、次の宣言がある場合:*aa&a

int (*ap0)[10][10] = &a;
int (*ap1)[10]     =  a;
int *ip            = *a;

次に、の次の10x10配列を指すように進みap0++、(または)の次の10要素配列を指すように進み、次の()を指すように進みます。 ap0intap1++ap1inta[1]ip++ipint&a[0][1]

**aと同等です。*a[0]と同等a[0][0]です。これはの最初の要素のaであり、タイプintと値があります(に初期化されるだけで、残りのすべての要素はに初期化されることに1注意してください)。 a[0][0]10

%pポインタ値を出力するために使用する必要があることに注意してください。

printf("&a = %p\n", &a);
printf(" a = %p\n",  a);
printf("*a = %p\n", *a);
于 2012-09-21T11:55:46.963 に答える
0

C99規格から

宣言によって定義された配列オブジェクトを検討してください

int x[3][5];

ここで、x は int の 3 × 5 配列です。より正確には、x は 3 つの要素オブジェクトの配列であり、それぞれが 5 つの int の配列です。(*((x)+(i))) と同等の式 x[i] では、x は最初に 5 つの int の初期配列へのポインターに変換されます。次に、i は x の型に応じて調整されます。これは、概念的には、i にポインターが指すオブジェクトのサイズ、つまり 5 つの int オブジェクトの配列を掛けることを伴います。結果が加算され、間接参照が適用されて 5 つの int の配列が生成されます。式 x[i][j] で使用すると、その配列は最初の int へのポインターに変換されるため、x[i][j] は int を生成します。

それで、

初期配列は x[0][0] のみです。

すべての x、&x、および *x は x[0][0] を指します。

于 2012-09-21T11:49:21.517 に答える
0

いいえ、コードに問題はありません。考えれば考えるほど、これを説明するのが難しいことに気付くので、これに入る前に、次の点を念頭に置いてください。

  1. 配列はポインターではありません。そのように考えないでください。それらは異なる型です。
  2. [] は演算子です。これはシフトとディファレンスの演算子なので、書くprintf("%d",array[3]);ときはシフトとディファレンシングをしています

したがって、配列 (最初に 1 次元について考えてみましょう) はメモリ内のどこかにあります。

int arr[10] = {1};
//Some where in memory---> 0x80001f23
                            [1][1][1][1][1][1][1][1][1][1]

だから私が言うなら:

*arr; //this gives the value 1

なんで?arr[0]配列の先頭であるアドレスの値を与えるのと同じだからです。これは、次のことを意味します。

arr; // this is the address of the start of the array

それで、これは私たちに何を与えますか?

&arr; //this will give us the address of the array. 
      //which IS the address of the start of the array
      //this is where arrays and pointers really show some difference

だからarr == &arr;。配列の「仕事」はデータを保持することです。配列は独自のデータを保持しているため、他のものを「指す」ことはありません。限目。一方、ポインターには、何か他のものを指す仕事があります。

int *z;     //the pointer holds the address of someone else's values
z = arr;    //the pointer holds the address of the array
z != &z;    //the pointer's address is a unique value telling us where the pointer resides
            //the pointer's value is the address of the array

編集: これについて考えるもう1つの方法:

int b;   //this is integer type
&b;      //this is the address of the int b, right?

int c[]; //this is the array of ints
&c;      //this would be the address of the array, right?

したがって、これについてはかなり理解できます。

*c;   //that's the first element in the array

そのコード行は何を教えてくれますか? deferencecの場合、int を取得します。つまり、プレーンcはアドレスです。これは配列の先頭であるため、配列のアドレスです。したがって、次のようになります。

c == &c;
于 2012-09-21T11:53:31.113 に答える
0

まず、ポインター値を出力したい場合は、%p- を使用します - 64 ビット マシンを使用している場合、 int はほぼ確実にポインターよりも小さくなります。

**aは実質的に a であるものを二重逆参照しているint**ため、最初のサブ配列の最初の要素は次のようになります。

于 2012-09-21T11:29:12.783 に答える
0

aとして定義する場合T a[10](where Tis some typedef)、単純な unadornedは、 と同じように、配列の開始アドレスをa意味します。どちらも typeです。&a[0]T*

&aも配列の開始アドレスですが、タイプはT**です。

多次元配列が存在すると、事態はより複雑になります。何が起こっているのかを確認するには、typedef を使用して物事を小さなチャンクに分割する方が簡単です。だから、あなたは効果的に書いた

typedef int array10[10];
array10 a[10];

[読者への演習: の型はa何ですか? (そうではありません int**)】

**aint配列の最初の値に正しく評価されaます。

于 2012-09-21T11:37:18.873 に答える