記事内にはプロモーションが含まれています

【C言語】CSVファイルの読み込み方法を徹底解説(配列や構造体への格納など)

【C言語】CSVファイルの読み込み方法を徹底解説(配列や構造体への格納など) C言語

C言語でデータ処理を行う際、Excelやデータベースから出力されたCSVファイル(カンマ区切りファイル)を読み込みたいという場面は頻繁に訪れます。

しかし、Pythonなどのスクリプト言語とは異なり、C言語には「CSVを読み込むための標準関数」が用意されていません。

そのため、「ファイルを1行ずつ読み込む」「カンマで区切る」「数値に変換する」といった処理をすべて自分で実装する必要があります。

ここでつまずく初心者の方は非常に多いですが、一度パターンを覚えてしまえば、どのような形式のCSVでも自由自在に扱えるようになります。

この記事では、C言語でCSVファイルを読み込むための基本的な手順から、2次元配列や構造体への格納方法、さらに特定列の抽出テクニックまで、現在の開発環境でも通用する実装方法をサンプルコード付きで徹底解説します。

【本記事の信頼性】
プロフィール
執筆者:マヒロ
  • 執筆者は元エンジニア
  • SES⇒大手の社内SE⇒独立
  • 現在はこじんまりとしたプログラミングスクールを運営
  • モットーは「利他の精神」

CSV読み込みの基本手順と必要な関数

C言語でCSVを読み込む処理は、大きく分けて以下の3ステップで構成されます。

  1. fopen でファイルを開く。
  2. fgets でファイルを「1行ずつ」読み込む。
  3. strtok または sscanf で、読み込んだ行を「カンマ」で分割する。

まずは、最も基本となる「文字列として読み込んで画面に表示する」プログラムを見てみましょう。

カンマ区切りで文字列を表示する基本コード

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LINE_LENGTH 1024

int main(void) {
    FILE *fp;
    char line[MAX_LINE_LENGTH];
    char *token;

    // 読み込むCSVファイルを開く
    fp = fopen("data.csv", "r");
    if (fp == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }

    // 1行ずつ読み込む
    while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
        // 改行文字を削除(任意)
        line[strcspn(line, "\n")] = 0;

        // カンマを区切り文字として最初のトークンを取得
        token = strtok(line, ",");

        // 行末までトークンを取得し続ける
        while (token != NULL) {
            printf("[%s] ", token);
            token = strtok(NULL, ","); // 次のトークンへ
        }
        printf("\n"); // 1行読み終わったら改行
    }

    fclose(fp);
    return 0;
}

実行結果(data.csvが “ID,Name,Score” の場合)

[ID] [Name] [Score] 
[1] [Tanaka] [80] 
[2] [Suzuki] [90] 

fgets 関数は、ファイルから改行コードまで(または最大文字数まで)を1行として読み込み、バッファ(line 配列)に格納します。

その後、strtok 関数を使って、読み込んだ1行の文字列をカンマ , で分割(トークン化)しています。

strtok は少し特殊な関数で、2回目以降の呼び出しには NULL を指定することで、「さっきの続き」から分割を行ってくれます。

読み込んだデータを「配列」や「構造体」に格納する

単に表示するだけでなく、読み込んだデータをプログラム内で計算や並べ替えに使いたい場合は、変数に格納する必要があります。

ここでは、実務でよく使われる「構造体」への格納方法を紹介します。

構造体を使ってCSVデータを管理する

例えば、「ID(整数)」、「名前(文字列)」、「得点(実数)」というデータを持つCSVを読み込む場合を考えます。

セキュリティ上のリスク(バッファオーバーフロー)を避けるため、文字数制限付きで読み込むのが鉄則です。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE 1024
#define MAX_RECORDS 100

// データを格納する構造体
typedef struct {
    int id;
    char name[50];
    double score;
} Student;

int main(void) {
    FILE *fp;
    char line[MAX_LINE];
    Student students[MAX_RECORDS]; // 構造体の配列
    int count = 0; // 読み込んだレコード数

    fp = fopen("students.csv", "r");
    if (fp == NULL) return 1;

    // ヘッダー行(1行目)を読み飛ばす場合
    // fgets(line, MAX_LINE, fp);

    while (fgets(line, MAX_LINE, fp) != NULL) {
        if (count >= MAX_RECORDS) break; // 配列の上限チェック

        // sscanfを使ってカンマ区切りで型変換しながら読み込む
        // %49[^,] は「カンマ以外の文字を最大49文字まで読み込む」という意味(ヌル文字分を考慮してサイズ-1)
        sscanf(line, "%d,%49[^,],%lf", &students[count].id, students[count].name, &students[count].score);

        count++;
    }

    fclose(fp);

    // 格納結果の確認
    for (int i = 0; i < count; i++) {
        printf("ID:%d 名前:%s 得点:%.1f\n", students[i].id, students[i].name, students[i].score);
    }

    return 0;
}

実行結果

ID:1 名前:Tanaka 得点:80.5
ID:2 名前:Suzuki 得点:90.0
ID:3 名前:Sato 得点:75.2

ここでは strtok の代わりに sscanf 関数を使用しています。

sscanf は「文字列からフォーマットに従って値を読み取る」関数です。

重要なポイントは、文字列を読み込む際に %[^,] ではなく %49[^,] のように最大文字数を指定している点です。

配列サイズを超えて書き込まれるのを防ぐために、必ずバッファサイズより1小さい値を指定しましょう。

特定の列だけを読み込む・抽出する方法

巨大なCSVファイルから、「3列目のデータだけ欲しい」という場合もあります。
その場合は、strtok でトークンを数えながら読み進める方法が有効です。

指定した列(カラム)の値を取得する関数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LINE 1024

// 指定した列番号(0始まり)の文字列を取得する
void get_column(char *line, int col_index, char *result) {
    char *token;
    int current_col = 0;

    // 行をコピーして破壊されないようにする(strtok用)
    char temp_line[MAX_LINE];
    strcpy(temp_line, line);

    token = strtok(temp_line, ",");
    while (token != NULL) {
        if (current_col == col_index) {
            strcpy(result, token); // 見つかったら結果にコピー
            return;
        }
        token = strtok(NULL, ",");
        current_col++;
    }
    strcpy(result, ""); // 見つからなかったら空文字
}

int main(void) {
    char line[] = "101,Apple,150,Red"; // テスト用のCSV行
    char value[100];

    // 2列目(価格:150)を取得
    get_column(line, 2, value);
    
    printf("抽出した値: %s\n", value);

    return 0;
}

実行結果

抽出した値: 150

get_column 関数を作成し、行データと欲しい列番号を渡すことで、その列の文字列だけを抽出できるようにしました。

strtok は元の文字列を書き換えてしまう(区切り文字をヌル文字にする)ため、strcpy で一時的なバッファにコピーしてから処理を行っている点がポイントです。

CSV読み込み時の注意点とトラブルシューティング

CSV読み込みはシンプルに見えますが、実務では「ダブルクォーテーションで囲まれたデータ」や「空のデータ」などでハマることがあります。

空フィールド(,,)の扱いに注意

strtok 関数は、連続する区切り文字を1つとみなす仕様があります。

そのため、1,,80 のようにデータが空(欠損)の場合、strtok は空欄をスキップしてしまい、データが左にずれるという問題が発生します。

空データが含まれる可能性があるCSVを扱う場合は、strtok を使わずに strchr などを使って自力でカンマを探すループ処理を書くか、strsep(非標準)の使用を検討してください。

ダブルクォーテーション " の扱い

Excelなどで出力したCSVは、データの中にカンマが含まれる場合、"Tanaka, Taro", 20 のようにダブルクォーテーションで囲まれます。

標準の strtok やシンプルな sscanf では、このダブルクォーテーション内のカンマも区切り文字として認識してしまい、正しく読み込めません。

これに対応するには、1文字ずつ解析して「引用符の中かどうか」を判定する自作のパーサー(解析ロジック)を組む必要があります。

改行コードの違い

Windowsで作成されたCSVは改行コードが \r\n ですが、Linuxなどでは \n です。

fgets は改行コードも含めて読み込むため、行末のデータ(最後の列)に \r が付着してしまい、数値変換や文字列比較がおかしくなることがあります。

読み込み直後に strcspn などで改行コードを除去する処理を入れるのが鉄則です。

C言語のスキルを活かして年収を上げる方法

以上、C言語でCSVファイルを読み込む方法について解説してきました。

なお、C言語のスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。

C言語を扱えるエンジニアは比較的希少価値が高く、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。

なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。

今すぐ転職する気がなくとも、とりあえず転職エージェントに無料登録しておくだけで、スカウトが届いたり、思わぬ好待遇の求人情報が送られてきたりするというメリットがあります。

併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなC言語の案件を探しやすくなります。

転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。