16

私はプログラミング入門コースのティーチングアシスタントですが、一部の学生はこの種の誤りを犯しました。

char name[20];
scanf("%s",&name);

彼らが学んでいるので、これは驚くべきことではありません...驚くべきことは、gcc警告に加えて、コードが機能することです(少なくともこの部分)。私は理解しようとしていて、次のコードを書きました。

void foo(int *v1, int *v2) {
  if (v1 == v2)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

int main() {
  int test[50];
  foo(&test, test);
  if (&test == test)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

コンパイルと実行:

$ gcc test.c -g
test.c: In function ‘main’:
test.c:12: warning: passing argument 1 of ‘foo’ from incompatible pointer type
test.c:13: warning: comparison of distinct pointer types lacks a cast
$ ./a.out 
Both pointers are the same
Both pointers are the same

なぜ彼らが変わらないのか誰かが説明できますか?

配列のアドレスを取得できないためだと思いますが(取得できないため& &x)、この場合、コードはコンパイルされません。

編集:配列自体が最初の要素のアドレスと同じであることは知っていますが、これはこの問題とは関係がないと思います。例えば:

int main() {
  int a[50];
  int * p = a;
  printf("%d %d %d\n", p == a, p == &a[0], &p[0] == a);
  printf("%d %d %d\n", p == &a, &p == a, &p == &a);
}

プリント:

$ ./a.out 
1 1 1
1 0 0

2行目が。で始まる理由がわかりません1

4

5 に答える 5

26

あなたの例では、配列testは50のブロックですints。したがって、次のようになります。

| int | int | ... | int |

単項演算子を配列に適用すると、配列&のアドレスを取得します。あなたがそれを他のものに適用するときと同じように、本当に。50のそのブロックを指すポインタもそうです:&testints

(&test) -----------> | int | int | ... | int |

50 intの配列を指すポインタには、タイプがあります。int (*)[50]これは、のタイプです&test

名前が単項演算子または単項演算子testのいずれのオペランドでもない場所で名前を使用すると、最初の要素へのポインターに評価されます。したがって、渡すに渡すものは、要素へのポインタに評価されます。sizeof&testfoo()test[0]

(test) -----------------\
                        v
(&test) -----------> | int | int | ... | int |

これらは両方とも同じアドレスを指していることがわかります-&test配列全体を指しているにもかかわらずtest、配列の最初の要素を指している(これらの値が持つさまざまなタイプでのみ表示されます)。

于 2010-05-24T00:11:10.113 に答える
10

実際、それらは異なり、少なくとも同じタイプではありません。

しかし、Cでは、配列のアドレスは配列の最初の要素のアドレスと同じであるため、「それらは異ならない」ので、基本的に同じものを指します。

于 2010-05-23T23:25:10.700 に答える
6

次のような配列を定義する場合

char name[20];

name暗黙的にに変換可能ですchar*&name、タイプchar (*)[20](20文字の配列へのポインター)です。アドレスは同じです。

のアドレスを確認してください(&name + 1)&nameによって形が 異なりsizeof(char [20])ます。

于 2010-05-24T00:00:45.973 に答える
2

配列の名前は、ほとんどの場合、その最初の要素のアドレスに評価されます。2つの例外は、それがのオペランドsizeofまたは単項である場合&です。

単項演算&は、その引数のアドレスを示します。配列のアドレスはその最初の要素のアドレスと同じであるため、(void*)&array == (void*)array常に真になります。

array、最初の要素へのポインタに変換されると、タイプはT *。のタイプ&arrayT (*)[n]、です。ここnで、は配列内の要素の数です。したがって、

int* p = array;        // Works; p is a pointer to array[0]
int* q = &array;       // Doesn't work; &array has type int (*)[10]
int (*r)[10] = &array; // Works; r is a pointer to array
于 2010-05-24T00:07:12.203 に答える
-3

これはgccの最適化だと思います。考えてみてください。

  • &testのアドレスを指すtest
  • testtestまたはの最初の要素を指す&test[0]
  • [0](ほとんどの場合)と同じです*

したがって、これによると、これとは異なる&test 可能性testがありますが、その時点で余分なレベルの間接参照を持つ目的がないため、gccはこれを最適化します。

于 2010-05-23T23:58:14.237 に答える