実現したいこと
C言語を使って
(1).すでにcsv形式で保存した構造体データのファイルを読み込む
(2).読み込んだデータを構造体データとして取得したメモリ領域に格納
(3).ファイルより取得した構造体データを特定のメンバをキーにしてソート
((3)はソース上にはない)
前提
macのデフォルトのgccコマンドを使ってコンパイル。コンパイルは成功
(実際のコンパイル環境は Clang)
macの環境でc言語のプログラムを書いています。
このコードの狙いとしては、先に「実現したいこと」に書いた通り、構造体のデータを一時的にcsv形式で保存し、編集する際には再度保存したcsvを読み込み、構造体として加工できるようにすることです(簡易的なデータベースを構造体を使って作成したい)。
コンパイルは成功しましたが、実行時に以下のエラーメッセージが発生しました。
発生している問題・エラーメッセージ
コンパイルは成功するが、実行の際に
zsh: segmentation fault ./fileGet_andSave
とエラーが出る
(ターミナルに表示) zsh: segmentation fault ./fileGet_andSave (lldbを実行した際のエラー表示) Process 33450 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x000000019cc67f64 libsystem_platform.dylib`_platform_strlen + 4
該当のソースコード
C
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define NUM_LETTERS 16 6#define NUM_BUFF 256 7#define ONE 1 8#define COMMA "," 9 10/* definition of struct People */ 11typedef struct{ 12 /* data */ 13 unsigned int id; 14 char first_name[NUM_LETTERS]; 15 char last_name[NUM_LETTERS]; 16 unsigned short age; 17} People; 18 19int main(){ 20 unsigned int cnt, numData; 21 FILE *fp = NULL; 22 //ファイルの文字列を一時的に格納する配列 23 char strBuff[NUM_BUFF]; 24 //構造体の配列へのポインタ 25 People *p_PeopleGet; 26 size_t sizePeople; 27 28 numData = 0; 29 //区切り文字(デリミタ)をカンマとする 30 char comma[] = COMMA; 31 //構造体 Peopleのオブジェクト1個分のサイズを求める 32 sizePeople = sizeof(People); 33 34 //すでに保存されているcsvファイルを読み込む 35 fp = fopen("People.csv", "r"); 36 37 //fopenの結果に対するエラー処理 38 if(fp == NULL){ 39 printf("failed to open file\n"); 40 exit(EXIT_FAILURE); 41 } 42 else{ 43 printf("file open succeed.\n"); 44 } 45 46 //次に fgets関数で文字列を取得できるか確認 47 if(fgets(strBuff, NUM_BUFF, fp) == NULL){ 48 printf("string in file could not be got.\n"); 49 exit(EXIT_FAILURE); 50 } 51 52 //開いたcsvファイルの行数(データ数)を求める 53 while(fgets(strBuff, NUM_BUFF, fp) != NULL){ 54 numData++; 55 } 56 57 //データ数分の構造体データを格納する領域を確保 58 p_PeopleGet = calloc(numData, sizePeople); 59 //デバッグソース(この表示が出る前に segmentation faultが出る) 60 //printf("address of p_PeopleGet: %p", p_PeopleGet); 61 62 //1行分のデータをカンマで区切り、 63 //区切ったデータを順次確保した構造体の領域に格納 64 //id, age(年齢)については文字データを数値データ(int)に変換 65 for(cnt = 0; cnt < numData; cnt++){ 66 fgets(strBuff, NUM_BUFF, fp); 67 p_PeopleGet[cnt].id = atoi(strtok(strBuff, comma)); 68 strcpy(p_PeopleGet[cnt].last_name, strtok(NULL, comma)); 69 strcpy(p_PeopleGet[cnt].first_name, strtok(NULL, comma)); 70 p_PeopleGet[cnt].age = atoi(strtok(NULL, comma)); 71 } 72 73 //取得した構造体データを出力 74 for(cnt = 0; cnt < numData; cnt++){ 75 printf("id:%3u, ", p_PeopleGet[cnt].id); 76 printf("last_name: %-16s, ",p_PeopleGet[cnt].last_name); 77 printf("first_name: %-16s, ",p_PeopleGet[cnt].first_name); 78 printf("age:%d\n", p_PeopleGet[cnt].age); 79 } 80 81 free(p_PeopleGet); 82 fclose(fp); 83 84 return 0; 85}
試したこと
デバッガ lldbを使って、segmentation fault と表示される原因を探った
callocが成功した場合には、取得した先頭のアドレスが確保されるはずなので、そのアドレスを表示させるデバッグソースを記述してテストした
補足情報(FW/ツールのバージョンなど)
(ターミナル上での出力)
$clang -v
Apple clang version 13.0.0 (clang-1300.0.29.3)
Target: arm64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$lldb -v
lldb-1300.0.32.2
Swift version 5.5-dev

回答1件
あなたの回答
tips
プレビュー