2

私はmsdnとcplusplus.comでmemsetの使用法を読みました、私はそれを知っています(私が間違っているなら私を訂正してください):

int p =3;
// p = object value
// &p = memory address where p is stored

違いは何ですか:

char szMain[512];
memset( szMain, 0x61, sizeof( szMain ) );
cout << szMain[4];

と:

char szMain[512];
memset( &szMain, 0x61, sizeof( szMain ) );
cout << szMain[4];

(0x61 = a、ASCIIテーブルの16進数)

なぜ両方が同じ振る舞いをするのですか?これが建設的な質問でない場合は、ご容赦ください。私はC++の初心者で、理解できないようです。

4

3 に答える 3

4

何が起こっているかは、標準では配列からポインタへの変換として説明されています。

4.2配列からポインタへの変換[conv.array]

タイプ「NTの配列」または「Tの未知の境界の配列」の左辺値または右辺値は、タイプ「ポインターからT」の右辺値に変換できます。結果は、配列の最初の要素へのポインターです。


上記は、への最初の呼び出しで、配列の最初の要素のアドレスを格納するmemset szMainポインター(より具体的にはへのポインター)に変換されることを示しています。char

2番目の呼び出しで、&szMainはタイプのポインタを生成しますchar (*)[512]。と同じ型の配列へのポインタszMainで、配列自体のアドレスを格納します。

szMainの開始はその最初の要素()と同じアドレスにあるため、これらの式は両方とも同じ正確な値を生成しますszMain[0]が、同じタイプではないことに注意してください。


memset最初の引数としてaを受け入れるvoid*ため、任意のポインター型を暗黙的に使用して関数を呼び出すことができます。

于 2012-06-25T23:30:47.420 に答える
3

szMain配列の識別子です。ほとんどの場合、配列識別子は減衰して、配列の最初の要素へのポインタになります。つまり、&szMain[0]

memsetしたがって、最初の例では、配列の最初の要素のアドレスを渡しています。2番目の例では、配列自体のアドレスを渡します。ただし、これらはまったく同じアドレスです。

于 2012-06-25T23:25:35.220 に答える
2

はい、この場合、2つの動作は同じですが、必ずしもそうとは限りません。

配列名のほとんどの使用法は、配列の最初の要素のアドレスを示します。Tの配列の場合、ポインタのタイプはになりますT *

代わりに配列のアドレスを明示的に取得すると、同じアドレスが取得されますが、タイプが異なります( "Pointer toT"ではなく"TypeTのN個のオブジェクトの配列へのポインター")。

この場合、渡したアドレスはに変換されるvoid *ため、タイプの違いはすぐに破棄されますが、タイプの違いをすぐに破棄しない別のコンテキストで使用した場合、必ずしも同じ効果が得られるとは限りません。 。たとえば、配列の最初の要素を初期化せずに残したい場合は、次のようにします。

memset(szMain+1, 'a', sizeof(szMain));

そこにあるタイプ(この場合)は「charへのポインター」であるため、必要に応じて、配列の2番目のcharから開始します。ただし、次の場合:

memset(&szMain+1, 'a', sizeof(szMain));

1を追加する代わりに、1つの配列のサイズを追加するため、2番目の要素のアドレスではなく、配列の最後の直後にアドレスを渡します。

余談ですが、「a」が必要な場合は、質問で行ったように値を16進数でエンコードするのではなく、上記のように直接使用することをお勧めします。少なくとも、はるかに読みやすくなっています。理論的には移植性も高くなりますが、16進値が正しく機能しないマシン(主にIBMメインフレーム)を本当に気にする人はほとんどいません。

于 2012-06-25T23:37:35.190 に答える