ポインタリンクについての最後の話:
ポインタの3番目の部分( "*"および "&"、ポインタのステップ長)---- 2021.1.31
ワイルドポインター
まず、以下のコードをご覧ください。このコードに構文上の問題があるかどうかを考えてください。最終的には正常に実行できますか?
int main()
{
int* p;
*p = 200;
printf("%d\n", *p);
system("pause");
return 0;
}
まず、上記のコードの簡単な分析を行います。
まず、ポインター変数pを定義し、次にポインター変数pが指すコンテンツに値200を割り当てます。最後に、pが指すメモリ空間の内容を出力します。
しかし、それを実行しようとしましたが、最終的にエラーが表示されました。どうしてこれなの?操作の結果は次のとおりです。
理由:
-
* p:ポインタ変数pが指すメモリ空間の内容を表します。ただし、下の図に示すように、プログラムは特定のメモリスペースを明確に指し示していないため、200がランダムなメモリスペースにランダムに割り当てられ、最終的にシステムがクラッシュします。
-
素人の言葉で言えば、現時点では、ポインタ変数pは狂犬に相当します。メモリ空間を噛んで見た人は誰でもそのメモリ空間を指し、そのメモリ空間に200を割り当てます。
したがって、ワイルドポインターは、初期化されていないポインターです。ポインターはランダムポインターを指し、ワイルドポインターは操作できません。
通常の操作では、変数を定義してから、変数のアドレスをポインター変数pに割り当てます。次のように。
int a = 0;
int *p;
p = &a;
*p = 200;
上記の分析を通じて、ポインタpによって保存されたアドレスを定義する必要があることも知っておく必要があります(つまり、pが指すメモリ空間がシステムに適用されている必要があります)。
ヌルポインタ
同様に、以下のコードをご覧ください。このコードに構文上の問題があるかどうかを考えてください。最終的には正常に実行できますか?
int main()
{
int a;
int* p = 0x00000000;
*p = 200;
printf("%d\n", *p);
system("pause");
return 0;
}
まず、上記のコードの簡単な分析を行います。
整数変数aとポインター変数pを定義し、今述べたワイルドポインターの問題を回避するために、0x00000000というアドレスを人為的に定義しました。次に、ポインタ変数pが指すメモリ空間の内容に200を割り当てます。最後に、そのメモリ空間の内容を* pで出力します。
しかし、それを実行しようとしましたが、最終的にエラーが表示されました。どうしてこれなの?操作の結果は次のとおりです。
理由:
- 上記のコードに示されているように、ワイルドポインターを回避するために、ポインター変数pに0x00000000を割り当てます。このとき、ポインタはnullポインタになります。実際、nullポインタを表現する別の方法は次のとおりです。
int *p = NULL;
- しかし、プログラムの実行後に問題が発生するのはなぜですか?0x0000 0000またはNULLがポインター変数pに割り当てられていることを知る必要があります。これは、ポインター変数pがこのアドレス(0x0000 0000)を指していることも意味します。具体的な回路図を下図に示します。
- 表面的には問題ないようですが、pは0x0000 0000のアドレスを保存しますが、このアドレスはシステム起動ファイルの保存に使用されることが多いため使用できません。これは違法であり、上記のようになります。書き込みアクセス許可の競合。当然、プログラムは正常に実行されません。
では、nullポインターはこの種の問題を引き起こす可能性があるため、どのアプリケーションでnullポインターが使用されているのでしょうか。
nullポインターの役割: nullポインターが使い果たされた場合、通常はポインターをNULLに割り当てます。次の使用では、ポインターがNULLかどうかを判断し、ポインターが使用されているかどうかを確認します。ポインタ値がNULLの場合、ポインタを使用してからポインタを割り当てることができることを意味します。ポインタ値がNULLでない場合は、ポインタを使用できないことを意味します。つまり、ポインタが別の場所に割り当てられていることを意味します。
ユニバーサルポインタ
私は質問を頼む;
前回の記事では述べ、次のような多くのポインタ変数のデータ型があるint*
、char*
、double*
などは、その後、ポインタ変数の型がありますすべてのタイプのデータを受け入れることができますか?
このポインタ変数をユニバーサルポインタと呼びます。
下の図のように、みんなに理解してもらうために、特別にみんなに見てもらえる絵を描きました。
上図の説明は次のとおりです。
一般的に関数を定義するとき、対応する関数インターフェイスを残すことがよくありますが、互換性を実現するために、関数に渡されるパラメーターが定義した関数インターフェイスのデータ型に準拠しているかどうかは実際にはわかりません。この問題を解決するには、ユニバーサルポインタを使用してください。
同様に、以下のコードをご覧ください。このコードに構文上の問題があるかどうかを考えてください。最終的には正常に実行できますか?
int main()
{
int a = 10;
short b = 10;
void* p = (void*)&a;
void* q = (void*)&b;
printf("%d\n", *p);
system("pause");
return 0;
}
まず、上記のコードの簡単な分析を行います。
- 一般に、ユニバーサルポインタは次のように定義します。
void *p;//万能指针
- 整数変数aを定義し、それを10に割り当てます。同様に、short型の変数bを定義します。これにも、値10が割り当てられます。
- aとbのアドレスを格納するために、2つのユニバーサルポインタpとqを定義します。しかし、前回の記事から、式の両側でデータ型を一致させる必要があることがわかりました。ここで繰り返して、みんなの印象を深めましょう。テイク
a
例を。p
式の左側のデータ型はvoid*
型ですが、a
式の右側のデータ型はint
型ですが、アドレス&
演算は前の記事の値から実行されます。現時点a
では、データ型は型になりますint*
が、データ型はまだ一致しないため、この時点で&a
データ型全体をキャストする必要があるため、式は次のようになります。void* p = (void*)&a;
- 最後に、ポインタ変数pが指すメモリ空間の内容を出力します。上記のロジックによれば、最終結果は10になります。
しかし、それを実行しようとしましたが、最終的にエラーが表示されました。どうしてこれなの?操作の結果は次のとおりです。
理由:
- 上記のように、pが指すメモリ空間の内容を最終的に取得したため、最終的なプログラムのコンパイルに失敗しましたが、以前の記事から、取得した内容は対応するデータ型のステップサイズに関連しています。データ型の幅に関連していると理解されています。
- pをユニバーサルポインタ、つまりvoid *型として定義したため、以前の記事から、pデータ型の最終ステップサイズはsizeof(void)であることがわかりますが、ご存知のとおり、voidは空を表します。これは、ポインタ変数を渡すことを意味します。pが対応するメモリ空間の内容を要求すると、システムはvoidのタイプを認識できないため、コンパイルが失敗するという現象が発生します。
- たとえば
void b;
、コンパイラは変数に割り当てられているスペースの量を認識していないため、void型の変数を定義することはできませんがvoid *
、以前の記事から、ポインタはすべて4バイトであるため、型を定義できます。
それでは、ユニバーサルポインタを使って、どうやってそのメモリ空間の内容を正常に印刷できるのか、ぜひ分析に来てください。
printf("%d\n", *p);
p
変数のデータ型はvoid*
typeです。これは*p
、対応するメモリスペースの内容が取得されることを意味しますが、結果は許可されません。次に、この時点で強制的に変換する必要があります。
それで問題は、どの部分を強制すべきかということです。
最終的な値を出力する必要が10
あり10
、データ型はint
typeです。以来p
変数はポインタ変数で、p
以前のものは“*”
、単に対応するスペースの内容を抽出することであるので、私たちの強制の一部ですp
。したがって、void*
型は型にキャストする必要がありますint*
。変更後のコードは次のとおりです。結果を確認できます。
int main()
{
int a = 10;
short b = 10;
void* p = (void*)&a;
void* q = (void*)&b;
printf("%d\n", *(int*)p);
system("pause");
return 0;
}
結びの言葉
この記事が良いと思うなら、それを気に入ってサポートすることを忘れないでください!!!