0

まず、私はそれを読みました:

  • array
  • &array
  • &array[0]

「配列」が実際に配列である限り、すべて同じになります。だから私は試しました:

int main(){ 
     char ar[]={'a','b','c','\0'};
     printf("argument: &ar     %s\n",&ar);
     printf("argument: &ar[1]    %s\n",&ar[1]);
}

出力:

argument:&ar   abc  
argument:&ar[1]  bc

&ar誤解しない限り、それ自体が最初の要素へのポインタである「ar」へのポインタではなく、最初の要素へのポインタと見なされているようです。

&(charへのポインタ)がどのように扱われるべきではないので、私は試しました:

char a='s';
char *pa=&a;
printf("argument: &pa   %c\n",&pa);

の出力%cは文字でもありません。また、配列の最初の要素へのポインタがどのように扱われるべきでもありません。私は試した:

char *pa=&ar[0];
char **ppa= &pa;
printf("argument: &pa   %s\n", ppa);

の出力%sは、当然のことながら、ナンセンスです。しかし、なぜ&arナンセンスではなかったのですか?もしもポインタだったら、ポインタへのポインタはそれほど多くarないはずですか?&arppa

私の質問:

  1. 配列名の前に置くと、単に「&」は無視されますか?配列名はこれに関して単に特別なものですか?
  2. その場合、コンパイラは「&」に続く識別子が配列への参照であることをどのように確認しますか?それは実際に配列のリストでそれを検索するので、宣言されていますか?
4

3 に答える 3

2

&ar「ar」へのポインターではなく、最初の要素へのポインターと見なされているようです。それ自体は、最初の要素のポインターへのポインターです。

あなた間違っています。 &arは array へのポインターですarが、配列arはどのような種類のポインターでもありません(配列です)。したがって、&arはポインターへのポインターではありません。

配列はオブジェクトの連続したシーケンスです。 の場合はar、4 つの連続したセットですcharは、この 4 文字のセットへ&arのポインタです。これは、必然的に、そのセットの最初のポインタである と同じ場所を指していることを意味します。ただし、タイプは異なります。「4文字の配列へのポインター」を意味するtypeと、「文字へのポインター」を意味するtypeがあります。&ar[0]char&archar (*)[4]&ar[0]char *

ほとんどすべての式で、arは配列の最初の要素へのポインターに評価されるため、混乱が生じます (これに対する例外は、単項演算&子または演算子のオペランドである場合sizeofです)。ar これは、それがポインタであることを意味するわけではありません- そうではありません - ほとんどの場合、それはポインタ値に評価されます。

于 2012-07-19T02:35:11.157 に答える
1

printf形式%sは、「対応する引数はcharへのポインタです。その場所に文字列を印刷します。」また、この目的のための文字列は、ヌル文字で終わる文字のシーケンスです。

printfに渡したとき&arに、「a」のアドレスを渡しました(ただし、型は間違っています。printfはcharへのポインターを予期し、charの配列へのポインターを渡しましたが、同じです。アドレス)、およびprintfは文字列'a'、'b'、'c'、'\ 0'を見たので、"abc"を出力しました。合格した場合も同じことが起こりarます&ar[0]。それらは同じアドレスに評価されます。

printfに渡したとき&ar[1]に、「b」がある場所へのポインタを渡し、printfは文字列「b」、「c」、「\ 0」を見たので、「bc」を出力しました。

ある場所で1文字だけを渡す場合は、%c形式を使用して、(文字へのポインターの代わりに)文字を渡します。たとえば、%c形式を「a」とともに使用すると「a」が出力され、 *ar%cを*&ar[1]「b」とともに使用すると「b」が出力されます。

&arは、「ar」へのポインタではなく、最初の要素へのポインタと見なされているようです。「ar」自体は、間違いがなければ最初の要素へのポインタです。

式で使用される場合、 。arと同じように、配列の最初の要素へのポインターとして機能します&ar[0]&ararは同じアドレスです(配列の最初の文字は配列の先頭と同じアドレスにあります)が、タイプは異なります(charの配列へのポインターとcharへのポインター)。

%cの出力は文字でもありません

それは文字であり、あなたが期待していたものではなく、おそらく通常の文字や印刷可能な文字ではありません。%cには文字引数が渡されることを期待していますが、アドレス引数が渡されました。

もしそうなら、コンパイラは「&」に続く識別子が配列を参照していることをどのように確認しますか、それは宣言された配列のリストで実際にそれを検索しますか?

解析はそれよりも複雑です(基本的に、&が考慮される前に識別子が既知の配列として識別され、次に&と識別子の組み合わせ式が評価されます)。ただし、その効果は&ar、最初の要素と同じアドレスに評価されることです。

于 2012-07-19T02:38:09.813 に答える
1

コードが警告なしでコンパイルされた場合、コンパイラを十分に活用していません。お願いしていただけると助かります。警告付きでコンパイルする方法と、診断された問題を修正する方法を学びます。これらのコマンドのいずれかを使用して、以下のコードをコンパイルしました。

gcc -O3 -g -std=c99 -Wall -Wextra -m64 array-stuff.c -o array-stuff
gcc -O3 -g -std=c99 -Wall -Wextra -m32 array-stuff.c -o array-stuff

これは、GCC でクリーンなコードを作成するための良い出発点です。確かに、-Wallなく-Wextraてもかなり良いです。

これはコードの適応です (ファイル内array-stuff.c) — ほとんどは異なりますが:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{ 
    // DC4M = Doesn't compile for me, because I compile with stringent warnings
    char ar[16] = { 'a', 'b', 'c', '\0' };  // Note explicit size
    printf("%-18s  %s\n", "Code:", "char ar[16] = { 'a', 'b', 'c', '\0' };");
    //printf("argument: &ar     %s\n", &ar);    // DC4M
    printf("argument: &ar[1]  %s\n", &ar[1]);

    printf("%-18s  0x%" PRIXPTR "\n", "ar:",       (uintptr_t)ar);
    printf("%-18s  0x%" PRIXPTR "\n", "&ar:",      (uintptr_t)&ar);
    printf("%-18s  0x%" PRIXPTR "\n", "(ar+1):",   (uintptr_t)(ar+1));
    printf("%-18s  0x%" PRIXPTR "\n", "(&ar+1):",  (uintptr_t)(&ar+1));
    printf("%-18s  0x%" PRIXPTR "\n", "&ar[1]:",   (uintptr_t)(&ar[1]));
    printf("%-18s  0x%" PRIXPTR "\n", "&(ar[1]):", (uintptr_t)(&(ar[1])));
    printf("%-18s  0x%" PRIXPTR "\n", "(&ar)[1]:", (uintptr_t)((&ar)[1]));

    printf("%-18s  %zu\n", "sizeof(ar):",       sizeof(ar));
    printf("%-18s  %zu\n", "sizeof(&ar):",      sizeof(&ar));
    printf("%-18s  %zu\n", "sizeof(void*):",    sizeof(void*));
    printf("%-18s  %zu\n", "sizeof(ar[1]):",    sizeof(ar[1]));
    printf("%-18s  %zu\n", "sizeof(&ar[1]):",   sizeof(&ar[1]));
    printf("%-18s  %zu\n", "sizeof(&(ar[1])):", sizeof(&(ar[1])));
    printf("%-18s  %zu\n", "sizeof((&ar)[1]):", sizeof((&ar)[1]));

    {
    char  a = 's';
    char *pa = &a;
    printf("%-18s  %s\n", "Code:", "char  a = 's';");
    printf("%-18s  %s\n", "Code:", "char *pa = &a;");
    //printf("argument: &pa   %c\n", &pa);    // DC4M
    printf("%-18s  0x%" PRIXPTR "\n", "&pa:",  (uintptr_t)&pa);
    printf("%-18s  0x%" PRIXPTR "\n", "&a:",   (uintptr_t)&a);
    printf("%-18s  0x%" PRIXPTR "\n", "pa:",   (uintptr_t)pa);
    }

    {
    char  *pa = &ar[0];
    char **ppa = &pa;
    //printf("argument: &pa   %s\n", ppa);  // DC4M
    printf("%-18s  %s\n", "Code:", "char  *pa = &ar[0];");
    printf("%-18s  %s\n", "Code:", "char **ppa = &pa;");

    printf("%-18s  0x%" PRIXPTR "\n", "&pa:",  (uintptr_t)&pa);
    printf("%-18s  0x%" PRIXPTR "\n", "ppa:",  (uintptr_t)ppa);
    printf("%-18s  0x%" PRIXPTR "\n", "*ppa:", (uintptr_t)*ppa);
    printf("%-18s  0x%" PRIXPTR "\n", "&ppa:", (uintptr_t)&ppa);
    }

}

これは、64 ビット コンパイルを使用した Mac OS X 10.7.4 マシンからの出力です。

Code:               char ar[16] = { 'a', 'b', 'c', '
argument: &ar[1]  bc
ar:                 0x7FFF6C9DE570
&ar:                0x7FFF6C9DE570
(ar+1):             0x7FFF6C9DE571
(&ar+1):            0x7FFF6C9DE580
&ar[1]:             0x7FFF6C9DE571
&(ar[1]):           0x7FFF6C9DE571
(&ar)[1]:           0x7FFF6C9DE580
sizeof(ar):         16
sizeof(&ar):        8
sizeof(void*):      8
sizeof(ar[1]):      1
sizeof(&ar[1]):     8
sizeof(&(ar[1])):   8
sizeof((&ar)[1]):   16
Code:               char  a = 's';
Code:               char *pa = &a;
&pa:                0x7FFF6C9DE560
&a:                 0x7FFF6C9DE56F
pa:                 0x7FFF6C9DE56F
Code:               char  *pa = &ar[0];
Code:               char **ppa = &pa;
&pa:                0x7FFF6C9DE558
ppa:                0x7FFF6C9DE558
*ppa:               0x7FFF6C9DE570
&ppa:               0x7FFF6C9DE550

そして、これは 32 ビット コンパイルからの出力です。

Code:               char ar[16] = { 'a', 'b', 'c', '
argument: &ar[1]  bc
ar:                 0xC008A670
&ar:                0xC008A670
(ar+1):             0xC008A671
(&ar+1):            0xC008A680
&ar[1]:             0xC008A671
&(ar[1]):           0xC008A671
(&ar)[1]:           0xC008A680
sizeof(ar):         16
sizeof(&ar):        4
sizeof(void*):      4
sizeof(ar[1]):      1
sizeof(&ar[1]):     4
sizeof(&(ar[1])):   4
sizeof((&ar)[1]):   16
Code:               char  a = 's';
Code:               char *pa = &a;
&pa:                0xC008A668
&a:                 0xC008A66F
pa:                 0xC008A66F
Code:               char  *pa = &ar[0];
Code:               char **ppa = &pa;
&pa:                0xC008A664
ppa:                0xC008A664
*ppa:               0xC008A670
&ppa:               0xC008A660

さまざまな数字がどのように得られたのかを理解すると、物事を理解するための順調な道を歩むことになります。

&array[1]として解釈されることに注意してください&(array[1])(&array)[1]種類とサイズが異なります。&配列添字などの後置演算子は、アドレス ( ) や間接 ( )演算子などの単項演算子よりも厳密に結合します*

于 2012-07-19T03:38:15.080 に答える