2
#include <stdio.h>

int multi[2][3] = {{17, 23, 19}, {72, 34, 44}};

int main()
{
    printf("%p\n", multi);    //line 1
    printf("%p\n", *multi);   //line 2

    if(*multi == multi)
        puts("They are equal!");

    return 0;
}

1行目と2行目はどう違うの?

私は出力を得ています:

They are equal

また、誰かがポインターと多次元配列での使用に関する優れたチュートリアルを参照できますか..

4

4 に答える 4

2

値は同じですが、型が異なります。

multiint [2][3]であり、評価時に型に変換されますint (*)[3]

*multiは typeint [3]であり、評価されると typeint *です。

実際:

*multi == multi

はコンパイラによって受け入れられますが、==演算子の 2 つのオペランドの型が異なるため、式は C では有効ではありません。比較を実行するには、2 つのオペランドのいずれかをキャストする必要があります。

于 2012-08-04T13:35:51.560 に答える
2

あなたへの質問は、コードをコンパイルするときに gcc によって与えられます。

ml.c:10: warning: comparison of distinct pointer types lacks a cast

multiint二次元配列の一種です。あれはint[][]

*multiは 1 次元配列の型ですint。あれはint[]

そのため、それらは同じオブジェクトではありません。比較の対象となるには、キャストする必要があります。この間違ったコードが内部でどのように機能するかを見てみましょう。

なんとcmpインストラクションも一切なし!(コンパイル済み-g -O0)。実際にはここは必要ありませんcmpmultiへのポインターに減衰するためです&multi[0][0]。に*multi減衰し&multi[0]ます。したがって、メモリの観点からは、それらは同じであり、c コンパイラは喜んでそれらを最適化します ( -O0:) を使用しても)。

(gdb) disassemble 
Dump of assembler code for function main:
   0x0000000000400504 <+0>: push   rbp
   0x0000000000400505 <+1>: mov    rbp,rsp
=> 0x0000000000400508 <+4>: mov    eax,0x400648
   0x000000000040050d <+9>: mov    esi,0x600900
   0x0000000000400512 <+14>:    mov    rdi,rax
   0x0000000000400515 <+17>:    mov    eax,0x0
   0x000000000040051a <+22>:    call   0x4003f0 <printf@plt>
   0x000000000040051f <+27>:    mov    edx,0x600900
   0x0000000000400524 <+32>:    mov    eax,0x400648
   0x0000000000400529 <+37>:    mov    rsi,rdx
   0x000000000040052c <+40>:    mov    rdi,rax
   0x000000000040052f <+43>:    mov    eax,0x0
   0x0000000000400534 <+48>:    call   0x4003f0 <printf@plt>
   0x0000000000400539 <+53>:    mov    edi,0x40064c
   0x000000000040053e <+58>:    call   0x400400 <puts@plt>
   0x0000000000400543 <+63>:    mov    eax,0x0
   0x0000000000400548 <+68>:    leave  
   0x0000000000400549 <+69>:    ret

呼び出す前に行うことputs()は、出力する必要がある文字列のアドレスを引数レジスタに移動することだけです。

gdb) x/10cb 0x40064c
0x40064c <__dso_handle+12>: 84 'T'  104 'h' 101 'e' 121 'y' 32 ' '  97 'a'  114 'r' 101 'e'
0x400654 <__dso_handle+20>: 32 ' '  101 'e'

ほら、あなたはコンパイラを十分に混乱させています:)最適化で5月cmpを取り除いたのです。always true:)

エキスパート C プログラミングには (驚き! 驚き!) という名前の章があります。

Chapter 4. ショッキングな真実: C 配列とポインタは同じではない!

強くお勧めします。

于 2012-08-04T14:12:51.350 に答える
0

簡単に言えば、C では、行列は行列の行である一連の連続した配列として格納されます。

m は 3 つの int の配列へのポインタ型を持ち、行列の最初の配列/行のアドレスです

m* は int へのポインタ型を持ち、最初の行の最初の要素のアドレスです

2 番目の配列のアドレスである m+1 と、2 番目の配列/行の最初の要素のアドレスである *( m + 1 ) にも同じことが適用されます。

お役に立てれば。

于 2012-08-04T19:26:08.167 に答える
0

-Wall を指定してコンパイルすると、コンパイラは次の行について警告します (cause: comparison of distinct pointer types):

if(*マルチ == マルチ)

multiは配列であり、C では、彼のアドレスは彼の最初の要素 aka のアドレスですmulti[0]*multimulti[0] とも呼ばれる配列の最初の要素へのポインタです。

同じデータ ( {17, 23, 19}) を含む 2 つのアドレスを比較しているため、この出力が得られる理由が説明されています。

この助けを願っています。

よろしく。

于 2012-08-04T14:05:05.023 に答える