Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

C/C++のセグメンテーションフォルト(コアダンプ)とは?主な原因と具体例を解説

本記事では、C/C++プログラミングにおける「コアダンプ(セグメンテーションフォルト)」について、その発生原因と具体的なコード例を交えてわかりやすく解説します。

セグメンテーションフォルトとは

セグメンテーションフォルト(Segmentation Fault)とは、プログラムが許可されていないメモリ領域にアクセスしようとした際に、OSがプログラムを強制終了させる現象です。実行時エラーの中でも特によく発生するもので、「core dumped(コアダンプ)」というメッセージとともに表示されることから、この名前で広く知られています。

主な発生原因としては、次のようなケースが挙げられます。

  • 読み取り専用のメモリ領域に書き込もうとした場合
  • 破損した、または不正なメモリ位置にアクセスした場合

原因別の具体例

1. 文字列リテラルの書き換え

文字列リテラルは読み取り専用のメモリ領域に配置されるため、ポインタ経由で内容を変更しようとするとセグメンテーションフォルトが発生します。

int main(){
    char *str;
    str = "GfG";
    *(str+1) = 'n';  // 読み取り専用領域への書き込みで異常終了
    return 0;
}

この例では、"GfG"という文字列リテラルの2文字目を'n'に書き換えようとしていますが、リテラルは書き換え不可のためプログラムが異常終了します。文字列を変更したい場合は、char型の配列を使用しましょう。

2. 配列の範囲外アクセス

#include <iostream>
using namespace std;
int main(){
    int arr[2];
    arr[3] = 10;  // 要素数2の配列に対してインデックス3にアクセス
    return 0;
}

要素数2の配列に対してインデックス3(4番目の要素)へアクセスしており、配列の境界を超えた不正なメモリ書き込みを行っています。範囲外アクセスは必ずしも即座にクラッシュするとは限りませんが、未定義動作を引き起こす重大なバグであり、常に避けるべきです。

3. 解放済みメモリへのアクセス(Use After Free)

#include <stdio.h>
#include <stdlib.h>
int main(void){
    int* p = malloc(8);
    *p = 100;
    free(p);   // メモリを解放
    *p = 110;  // 解放後のメモリに書き込み → 異常終了
    return 0;
}

free()で解放したメモリ領域に再度アクセスすると、未定義動作となりセグメンテーションフォルトが発生する可能性があります。この種のバグは「Use After Free」と呼ばれ、セキュリティ上の脆弱性にもつながるため特に注意が必要です。

実行結果

Abnormal termination of program(プログラムの異常終了)

まとめ:セグメンテーションフォルトを防ぐために

セグメンテーションフォルトを防ぐには、以下のポイントを意識しましょう。

  • 文字列リテラルは変更せず、変更が必要な場合はchar配列を使う
  • 配列アクセス時は必ずインデックスが有効範囲内かを確認する
  • free()後のポインタにはNULLを代入し、誤って再利用しないようにする
  • ValgrindやAddressSanitizerなどのツールを活用してメモリ関連のバグを早期に検出する
  1. C/C++の三項演算子(条件演算子)の基本と使い方

    3つのオペランド(被演算子)を必要とする演算子は「三項演算子」と呼ばれます。C言語では ? : の記号で表され、「条件演算子」とも呼ばれています。三項演算子を使うと、コードの行数を削減でき、簡潔で読みやすいプログラムを書くことができます。三項演算子の構文式1 ? 式2 : 式3まず式1が評価され、その結果が真(非ゼロ)であれば式2が実行され、偽(ゼロ)であれば式3が実行されます。if-else文を1行で書けるため、簡単な条件分岐に便利です。C言語での三項演算子の例サンプルコード1#include <stdio.h> int main() { int a = -1;

  2. セグメンテーション違反はC++における未定義動作なのか?

    未定義動作(Undefined Behavior)とは、コンパイラやOSなどの実装者、そしてコンピュータ自身に対して「何をしてもよい」という自由を与える仕組みです。言い換えれば、その結果について一切考慮しなくてよい、ということを意味します。 セグメンテーション違反は必ずしも発生するとは限らない セグメンテーション違反が起こるケースは、本質的に「一時的」なものです。常にセグメンテーション違反になるとは限らず、正しく動作する(少なくとも正しく動作しているように見える)こともあります。例として、次のコードを見てみましょう。 #include <iostream> int main() {