エラーメッセージの英語版:
Exception thrown at 0x7AEA4550 (vcruntime140d.dll) in HeapTest01.exe: 0xC0000005: Access violation writing location 0x00000000.
エラーメッセージの日本語版:
0x7AEA4550 (vcruntime140d.dll) で例外がスローされました (HeapTest01.exe 内): 0xC0000005: 場所 0x00000000 への書き込み中にアクセス違反が発生しました
サンプルソース
#include <stdlib.h>
#include <string.h>
int main()
{
int* p; // 対象メモリエリアへのポインター
int* tmpP; // 対象メモリエリアのアドレスカウンター
p = (int*)malloc(sizeof(int) * 16); // メモリエリア取得
tmpP = p; // 対象メモリエリアの先頭に指す
// 対象メモリエリアに任意値を入れる
for (int i = 0; i < 16; i++) {
*tmpP = 0x3412;
tmpP++;
}
// メモリ解放
free(p);
p = NULL;
// 再度書き込み(エラー発生)
memset(p, 0x00, 16);
return 0;
}
例外発生した時に止まっている画面
memset関数でエラーが発生したため、memset関数が表示されます。
(どの関数の画面が表示されるかによって、どの関数で落ちるかは分かります。)
エラー発生の原因
サンプルコードでは分かりやすいですが、原因は解放されたメモリに再度書き込みしようとしています。
メモリリークを避けるために、mallocで取得できたメモリを必ずfreeで解放する方法ですが、プログラムと処理ロジックがどんどん複雑になって、freeされていることを意識されずに再度書き込みしようとするとこのエラーが発生します。
「Access violation writing location 0x00000000」文面にあるアドレス「0x00000000」が書き込みしようとするアドレスのため、明らかにアドレスが誤って初期化されている、或いはポインターが誤ってNULL(0と同様)に設定されていると分かりますね。
デバッグ方法
注意:エラーが発生した時に、慌ててデバッグを停止・中止しないこと。メモリエラーは必ずしも毎回発生することもないので、発生した機会を大切にして冷静に分析しましょう。
①例外が発生した時にどの関数に止まっているかによって対象関数を特定
②デバッグ→ウインドウ→呼び出し履歴を開いて、どのような処理の流れで事象が発生したかを把握
(呼び出し履歴に関数名と行数があるので、対象関数が呼び出し元のファイル・関数で呼び出されることは複数箇所があっても特定しやすいですね)