プロが教えるわが家の防犯対策術!

C言語において、以下の条件で、ファイルに保存されているテキストデータを構造体に格納する方法を教えて下さい。


例題として、テキストファイルに保存されている社員データを構造体に格納するものとします。
初心者なので、記述内容が充分か分かりませんが、宜しくお願いします。


---以下条件---

・入力ファイルはテキスト形式(.txt)とし、ファイル名は「memberlist」とします。
・ファイル(memberlist)には、社員1人につき、社員番号、名前、名前(ヨミガナ)が、「,」で区切られて存在するものとします。
また、、テキストファイルには一行につき社員1人のデータが存在するものとし、複数の社員データが同一行に存在することはありません。

テキストファイルの例).

10001,山田太郎,ヤマダタロウ,
10002,佐藤一郎,サトウイチロウ,
30010,池田悟,イケダサトル,
………………
………………(続く)


・構造体は以下のように定義されているものとします。
なお、テキストファイルに何件の社員データがあるかは定義しませんが、
構造体の数は充分に確保されているものとします。

struct Person {
int num;      /*社員番号*/
char name[10]; /*名前*/
char kana[20];  /*名前(ヨミガナ)*/
};
struct Person List[100];

上記の条件のもとでテキストファイルの内容を構造体に格納したいのです。
そこで以下のようなプログラムを作ってみましたが、エラーが発生してしまいます(後述)。

#include<stdio.h>
/***構造体定義***/
struct Person {
int num;      /*社員番号*/
char name[10]; /*名前*/
char kana[20];  /*名前(ヨミガナ)*/
};
struct Person List[100];

main()
/***変数の定義***/
FILE *rfp
char rbuf[256];
char *tp;
int i,size;

/***ファイルオープン***/
rfp = fopen("memberlist.txt","r");
  /*エラー処理省略(ファイルオープンは正常に終了したものとします)*/

/***構造体への格納処理***/
while(1){
size = fgets(rbuf,256,rfp);    /*テキストデータを一行取得*/
  tp = strtok(rbuf,",");       /*テキストデータをカンマで区切る*/
  sprintf(List[i].num,"%05d",tp); /*文字列を数値に変換し、社員番号を構造体へ*/
  tp = strtok(NULL,",");      /*テキストデータをカンマで区切る*/
  strcpy(List[i].name,tp);     /*名前を構造体へ*/
  tp = strtok(NULL,",");      /*テキストデータをカンマで区切る*/
  strcpy(List[i].kana,tp);      /*ヨミガナを構造体へ*/
 if(size == NULL){
  break;                 /*データを読み終えたら、ループを離脱*/
 }
}

上記のプログラムのエラー内容ですが、
まず、社員番号を文字列変換し格納するsprintf文で、
「パラメータ '__buffer' は signed char * 型として定義されているので int は渡せない(関数 main )」
というコンパイルエラーが発生します。

また、実行すると、Windowsからのエラー、「問題が発生したため、”プログラム名”を終了します。~~~」というプログラムが強制終了される時に出現するエラーが発生します。

可能性としてどのような問題が考えられますか?よろしくお願いします。

A 回答 (4件)

 gccでは、エラーが連発して、実行させる以前の問題でした。


 ファイルは行末の「 , 」を省いて csv ファイル風に処理してあります。


/* Gcc on Mac OSX */
#include <stdio.h>
#include <string.h>/* strtok() */
#include <stdlib.h>/* atoi() */

#define SIZE256

/***構造体定義***/
struct Person {
int num;/*社員番号*/
char name[10];/*名前*/
char kana[20];/*名前(ヨミガナ)*/
};

int main(void) {
/***変数の定義***/
struct Person List[100];
FILE *rfp;
char rbuf[SIZE];
int i = 0;

/***ファイルオープン***/
rfp = fopen("memberlist.txt","r");
/*エラー処理省略(ファイルオープンは正常に終了したものとします)*/

/***構造体への格納処理***/
while(fgets(rbuf,SIZE,rfp) != NULL) {/*テキストデータを一行取得*/
List[i].num = atoi(strtok(rbuf,","));/*文字列を数値に変換し、社員番号を構造体へ*/
strcpy(List[i].name,strtok(NULL,","));/*名前を構造体へ*/
strcpy(List[i++].kana,strtok(NULL,"?n"));/*ヨミガナを構造体へ、i++を追加*/
}

return 0;
}
    • good
    • 0

>>「パラメータ '__buffer' は signed char * 型として定義されているので int は渡せない(関数 main )」


これについては他の方が指摘している通り atoi() を使うことで間違いないのですが、
>>「問題が発生したため、”プログラム名”を終了します。~~~」
これについてはまだ誰も指摘していないのでそれについて解答させていただきます

このエラーが発生する箇所はおそらく
>>tp = strtok(NULL,",");
という部分です。

なぜこのようなエラーが発生するかというと
>>char *tp;
とポインタだけ宣言しといてアドレスを代入していないため、出たら目なシステムなどが使っている大事なところに代入され Windows OS がその本来のデータを守るためです。

もしポインタを使うのであれば
tp = (char*)calloc(256, sizeof(char));
という風にする必要があります。 (これを変数の動的確保といいます)calloc() は第二引数のサイズを第一引数の個数だけ確保したメモリのアドレスを戻り値として返します。
又は、
>>char rbuf[256];
といった具合に配列で宣言するついでに tp も同様に宣言すればよいのではないでしょうか?(こちらを変数の静的確保といいます)

このミスはポインタを理解し切れていない人だと良くやらかすものです(私も良くやらかしました)。ポインタという概念はC言語では非常に重要な概念ですのでまだ理解し切れていないのであれば嫌にならない程度に勉強してください。

参考URL:http://homepage2.nifty.com/c_lang/index_c.html
    • good
    • 0

>sprintf(List[i].num,"%05d",tp); /*文字列を数値に変換し、社員番号を構造体へ*/


これはsprintfの使い方が間違っている。
sprintf()はあくまでも文字列に成形する関数です。
List[i].num=strtol(tp,NULL,10);
とかにするとよいかも。

あとは、構造体のメンバーが固定長になっているので、バッファーオバーフローのチェックをしないと長い名前の人がいたらプログラムがクラッシュします。
    • good
    • 0

sprintfの使い方いろいろおかしいような:


・第1引数にint型変数の値を渡している。
・tpは文字列へのポインタなのに、それを%d(数値用書式文字列)で整形しようとしている。

sprintfのマニュアルを読んでみては。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!