序文:
前章からの続きですので、今日も勉強を進めていきましょう!それほどナンセンスではありません。文字配列の内容をコード化してみましょう。
char *p は文字ポインタ、* は p がポインタであることを意味し、char は p が指すオブジェクト型が char 型であることを意味します。
char*p="abcdef";
文字列 abcdef のアドレスを p に保存するとき、p は文字列全体を保存しますか、それとも a のアドレスだけを保存しますか? コードをデバッグする時間です
この時点で、 p のアドレスが文字列!の a のアドレスでもあることがわかります。学び続けましょう
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
return 0;
}
分析を開始する
printf("%d\n", sizeof(p));
p は a のアドレスを格納し、sizeof(p) はアドレスのサイズを要求します。アドレスのサイズは 4/8 バイトです
printf("%d\n", sizeof(p + 1));
p は文字列内の a のアドレスを指し、p+1 は文字列内の b のアドレスを指します。sizeof(p+1) はアドレスのサイズを見つけます。アドレスのサイズは 4/8 バイトです。
printf("%d\n", sizeof(*p));
p は文字列内の a のアドレスを指します。*p は a を指します。sizeof(*p)-->sizeof(a) なので、サイズは 1 バイトです
printf("%d\n", sizeof(p[0]));
p[0]-->*(p+0)-->*(p)、p は a のアドレスを格納するため、*p は a を指します、sizeof(p[0]) は sizeof(a) のサイズを計算します結果は1です
printf("%d\n", sizeof(&p));
文字列のアドレスは p に格納され、p の型は char* で、p 自体にもアドレスがあり、その型は char** です! したがって、sizeof(&p) はアドレスのサイズも計算し、結果は 4 になります。 /8
次に、次のコードを分析してみましょう。
printf("%d\n", sizeof(&p + 1));
&p は p のアドレスを取り出して 1 を加えます。具体的なアドレスが何であるかはわかりませんが、1 つ確かなことは、sizeof(&p+1) がアドレスのサイズを計算し、アドレスのサイズが 4/8 であるということです。バイトサイズ
printf("%d\n", sizeof(&p[0] + 1));
&(*p+0)-->p アドレス、&p[0]+1 は文字列内の b のアドレスを取得するため、このとき sizeof でアドレスのサイズが計算され、アドレスのサイズは 4/8 バイトになります。コードをデバッグすると、それが確かに b のアドレスであることがわかります。
次に strlen というコードを使用します。strlen 機能を覚えていますか? \0 に遭遇するまでの文字数を計算します。文字列は \0 を隠します。
printf("%d\n", strlen(p));
p は依然として文字列内の a のアドレスを指しており、strlen は計算中に \0 に遭遇するまで a のアドレスから始まり、この時点での計算結果は 6 バイトになります。
printf("%d\n", strlen(p + 1));
p は依然として文字列内の a のアドレスを指しているため、p+1 は文字列内の b のアドレスを指しています。このとき、strlen は b のアドレスから \0 に到達するまで計算を開始し、計算結果は 5 になります。 。
printf("%d\n", strlen(*p));
p は依然として文字列内の a のアドレスを指しています。*p が取得するのは a です。前の記事で述べたことを思い出してください。strlen に必要なパラメータは、文字 a ではなく const char* 型のアドレスです。つまり、strlen( *p ) 結果はエラーです
printf("%d\n", strlen(p[0]));
p[0]-->*(p+0)-->*p-->a、説明は上と同じで結果はエラー
printf("%d\n", strlen(&p));
strlen(&p) もアドレス計算をしますが、いつ \0 に遭遇するかわからないので、このときの結果はランダムな値になります。
printf("%d\n", strlen(&p + 1));
strlen(&p+1) 行に 1 を追加しても、いつ \0 に遭遇するかはわかりませんし、結果は依然としてランダムな値です
printf("%d\n", strlen(&p[0] +1)
&p[0]-->&*(p+0)-->p、p は a のアドレスを格納するため、&p[0]+1 はこの時点で文字列 b のアドレスを指します、strlen(&p[0 ] +1) 結果は 5 バイトになります
分析が完了したら、コードを実行して見てみましょう。もちろん、結果が間違っていれば、コードは実行されません。
以上で1次元配列の疑問の解説が終わりましたので、次は2次元配列の疑問の解説に入りますが、2次元配列の知識はまだ覚えていますか?2 次元配列の行と列は 0 から始まります。例として int a[3][4] を取り上げます。この 2 次元配列の型は int [3][4] です。2 次元配列のストレージは、メモリ内の次元配列は連続しているため、2 次元配列の行は省略できますが、列は省略できません。2 次元配列は 1 次元配列の配列として理解できます。1次元配列の書き方はint a[3]、つまり配列名+[]、2次元配列の書き方はint a[3][4]となります。を配列名とみなし、配列名 +[ ] と記述することもできます! 2 次元の各行を 1 次元の要素として扱います
次に、コードを見ていきましょう。
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[3]));
}
int a[3][4]は3行4列の2次元配列で、各要素はint型で合計12要素あります。
分析を始めましょう!コードは早い者勝ちです!
printf("%d\n", sizeof(a));
sizeof (配列名) は配列全体のサイズを計算します。要素は合計 12 個あり、各要素のサイズは 4 バイトなので、配列全体のサイズは 48 バイトです。
printf("%d\n", sizeof(a[0][0]));
a[0] は 2 次元配列の行、a[0][0] は最初の行の最初の要素、sizeof(a[0][0])-->sizeof(int)、計算結果は4です
printf("%d\n", sizeof(a[0]));
a[0] は 2 次元配列の最初の行です。sizeof(a[0]) は最初の行の配列全体のサイズを計算します。1 行には 4 つの要素があるため、最初の行全体のサイズは 16 バイトです。
printf("%d\n", sizeof(a[0] + 1));
sizeof(a[0]+1) は、sizeof 内に単独で配置されていないため、a[0] は配列の最初の要素のアドレスを表します。a[0]+1 は 2 次元配列の最初の行の 2 番目の要素のアドレスを表し、sizeof(a[0]+1) はアドレスのサイズを計算します。アドレスのサイズは 4/8 です。バイト
printf("%d\n", sizeof(*(a[0] + 1)));
上で、a[0]+1 が 2 次元配列の最初の行の 2 番目の要素のアドレスを表すことを分析しました。つまり、*(a[0]+1) は 2 次元配列の 1 行目の 2 番目の要素を表します。次元配列要素、sizeof は要素のサイズを計算し、結果は 4 バイトになります
printf("%d\n", sizeof(a + 1));
sizeof の中に配列名だけが入っているわけではないので、このとき配列名は配列の最初の要素のアドレスを表し、a+1 は配列の 2 番目の要素のアドレス、つまり 2 番目の要素のアドレスを表します。 2 次元配列の行、sizeof でアドレス サイズが計算され、結果は 4/8 になります。
printf("%d\n", sizeof(*(a + 1)));
以上より、a+1が配列の2番目の要素のアドレス、つまり2次元配列の2行目のアドレスを表すことがわかり、それを逆参照して配列全体のサイズを取得します。 2 行目、結果は 16
printf("%d\n", sizeof(&a[0] + 1));
a[0] は 2 次元配列の最初の行を示し、&a[0] は 2 次元配列の 1 行目のアドレス全体を取り出し、&a[0]+1 は 2 次元配列の 2 行目のアドレスを取得します。二次元配列。sizeof はこの時点でもアドレスのサイズを計算しており、結果は 4/8 です。
printf("%d\n", sizeof(*(&a[0] + 1)));
&a[0] は 2 次元配列の 1 行目のアドレス全体を取り出し、&a[0]+1 は 2 次元配列の 2 行目のアドレス全体を取得し、それを逆参照してサイズを計算します。 16バイトです
printf("%d\n", sizeof(*a));
a は sizeof だけの中に置かれていないため、この時点では、 a は配列の最初の要素のアドレス、つまり 2 次元配列 a[0] の最初の要素のアドレスを表し、それを逆参照して全体のサイズを取得します。配列の最初の行を取得し、 sizeof で計算すると、結果は 16 バイトになります
最後の質問
printf("%d\n", sizeof(a[3]));
ああ、a[3]? この 2 次元配列には 3 行しかありません。a[3] のサイズの計算は範囲外にアクセスされますか? いいえ、ここの円盤は安心して計算できます。一般に、コードをコンパイルして実行して実行可能ファイルを作成する必要がありますが、sizeof はコンパイル段階で結果を計算するため、範囲外アクセスが発生することはありません。sizeof(a[3]) は配列全体のサイズを計算し、結果のサイズは 16 バイトになります。
コードを実行して結果を確認します
3. ポインタ部
コード上で!
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
配列aは5つの要素を格納する1次元配列で、&aは配列全体のアドレスを取り出します このとき配列ポインタを使って受け取る必要がありますが、ここでは強制的にint*型に変換しています。
a は配列の最初の要素のアドレスを表します、a+1 は配列の 2 番目の要素のアドレスを表します、*(a+1) は配列の 2 番目の要素 2 を表します、int*ptr=(int*)( &a+1), ptr ポインティングは &a+1 のポインティングと一致しており、ptr-1 はこの時点で a[4] のアドレスをポイントしており、逆参照すると a[4]-->5 が取得されるため、答えはこの質問には 2,5 です。コードを実行して確認してください
今日の勉強はここまで、続きは明日にしましょう!