電子書籍の厳選無料作品が豊富!

固定長レコードから構造体について

フラットファイルから固定長のレコードを取得して
構造体に格納する。

という内容なんですが、構造体指定バイトのデータを格納して
求めている結果が...

kozo_a:aaaaa
kozo_b:bbbbb
kozo_c:ccccc

となって欲しいのですが、
構造体の確認をしてみたところ...

list[0]:
kozo_a:aaaaabbbbbccccc
kozo_b:bbbbbccccc
kozo_c:ccccc
list[1]:
kozo_a:aaaaabbbbbccccc
kozo_b:bbbbbccccc
kozo_c:ccccc
list[2]:
kozo_a:aaaaabbbbbccccc
kozo_b:bbbbbccccc
kozo_c:ccccc
list[3]:
kozo_a:aaaaabbbbbccccc
kozo_b:bbbbbccccc
kozo_c:ccccc

のように、求めている結果と異なってしまいます。
未だ問題解決しておらず、誰かお力を貸して頂けないですか?



~input(ファイル名)~

01:aaaaabbbbbcccccdddddeeeeefffff
02:aaaaabbbbbcccccdddddeeeeefffff
03:aaaaabbbbbcccccdddddeeeeefffff


~ソース~

/*test.c*/

/********************************/
/* include */
/********************************/
#include <stdio.h>

/********************************/
/* マクロ */
/********************************/
#define FILE_NAME "input" /* 入力ファイル名 */
#define LISTMAX 5 /* レコードMAX件数 */
#define MAX_LEN 128 /* 1行の最大文字数 */

/* 入力ファイルカラム定義 */
#define colum_a 5
#define colum_b 5
#define colum_c 5
#define colum_d 5
#define colum_e 5
#define colum_f 5


/********************************/
/* 宣言 */
/********************************/
int i=0; /* カウンタ */
FILE *fp; /* FILEポインタ */
char buff[MAX_LEN];


/********************************/
/* 構造体 */
/********************************/
struct shohin
{
char kozo_a [colum_a];
char kozo_b [colum_b];
char kozo_c [colum_c];
char kozo_d [colum_d];
char kozo_e [colum_e];
char kozo_f [colum_f];
};
struct shohin list[LISTMAX];


/********************************/
/* メイン処理 */
/********************************/
int main(void)
{


/********************************/
/* ファイルオープン */
/********************************/
fp=fopen(FILE_NAME,"r");

/********************************/
/* データ入力処理 */
/********************************/
while(NULL!=(fgets(buff,MAX_LEN,fp)))
{
if(i==LISTMAX)
{
/* レコード件数がLISTMAX(5)を超えた時 */
printf("確保した以上にデータがあります\n");
break;
}

sscanf(buff,"%s %s %s", list[i].kozo_a, list[i].kozo_b, &list[i].kozo_c);
printf("list[%d]:\n\tkozo_a:%s\n\tkozo_b:%s\n\tkozo_c:%s\n",
i, list[i].kozo_a, list[i].kozo_b, list[i].kozo_c);
i++;
}
fclose(fp);
}



//▲▲▲▲▲▲▲▲▲▲▲▲▲▲
//最終的に私が求めているのは、
//あるファイルのデータから、nバイト目~nバイト目を
//構造体を用いて判定して、その部分の指定データを置換(変換)する。という課題です。

//イメージ
//変換前:aaaaaBBBBBcccccddddd
//変換後:aaaaabbbbbcccccddddd

//行き詰ってしまい先が見えません…お力を貸してください!

A 回答 (4件)

#1です。


本題とはちょっとはなれたところの疑問なんですが、
質問者さんはCOBOLの経験者だったりしませんか?
提示されているプログラムをよーく見ていると、それとなくCOBOL臭がするんですが…

Cを使うならCOBOLのことはあまり引きずらないほうが良いと思います。
    • good
    • 0

★いきなりサンプルを載せます。



●ヘッダ部
struct shohin1 {
 char kozo_a[ 5 ];
 char kozo_b[ 5 ];
 char kozo_c[ 5 ];
  :
 char kozo_f[ 5 ];
};
struct shohin2 {
 char kozo_a[ 5 + 1 ];
 char kozo_b[ 5 + 1 ];
 char kozo_c[ 5 + 1 ];
  :
 char kozo_f[ 5 + 1 ];
};

●ソース部
struct shohin1 list[ LISTMAX ];
struct shohin2 data;
int i, max;

// 読み込み部
max = fread( list, sizeof(struct shohin1), LISTMAX, fp );

// フィールド分割処理
for ( i = 0 ; i < max ; i++ ){
 struct shohin *p = &list[i];
 
 sprintf( data.kozo_a, "%.*s", sizeof(p->kozo_a), p->kozo_a );
 sprintf( data.kozo_b, "%.*s", sizeof(p->kozo_b), p->kozo_b );
 sprintf( data.kozo_c, "%.*s", sizeof(p->kozo_c), p->kozo_c );
  :
 sprintf( data.kozo_f, "%.*s", sizeof(p->kozo_f), p->kozo_f );
 
 // 置換前の表示部
 printf( "置換前:%.*s\n", sizeof(struct shohin1), p->kozo_a );
 
 // 置換(変換)部
 if ( !strcmp(data.kozo_b,"BBBBB") ){
  memcpy( p->kozo_b, "bbbbb", sizeof(p->kozo_b) );
 }
 // 置換後の表示部
 printf( "置換後:%.*s\n\n", sizeof(struct shohin1), p->kozo_a );
}

解説:
・固定長レコードの構造体へのセットは『fread』関数で簡単に行えます。
 問題は『kozo_a』メンバの次に『kozo_b』メンバの文字列が NULL 文字で区切らずに
 連続している事です。そこで、for 文で文字列の分割用の構造体(struct shohin2)に
 コピーしています。この分割用の構造体を利用して置換(変換)を行って下さい。
・あと fopen、fclose の部分は省略しました。
・以上。おわり。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/fread.html,ht …
    • good
    • 0

> sscanf(buff,"%s %s %s", list[i].kozo_a, list[i].kozo_b, &list[i].kozo_c);


ANo.1でも言われていますが、
ここは質問者さんの意図通りに動作していないと思います。
最初の%sでbufの内容がほぼ全部読み込まれてlist[i].kozo_aに格納され、
残りの%sでの読み取りは失敗してます。
結果的に、sscanf(buff,"%s", list[i].kozo_a); としたのと同じことになってます。

list[i].kozo_aはsizeof(char)*5の領域しか確保されてないので、
list[i].kozo_aに格納しようとした内容は
kozo_b以降のメンバや、次のshohin構造体にあふれてしまいます。
そのため、struct shohinの定義でメンバの順番を入れ替えたり、
間に別のメンバを入れたりすると挙動が変わると思います。
(正しく作っているなら、メンバ順を入れ替えても動作は同じはずです。)

なお、scanfの%sでも読み取り文字数は
> sscanf(buff,"%5s%5s%5s", list[i].kozo_a, list[i].kozo_b, &list[i].kozo_c);
とすれば制限できますが、
'\0'の分の領域が足りていないのであふれることに変わりはありません。
'\0'終端の文字列として格納する気がないなら、そもそも%sで取得するべきではないですね。
(もっとも、'\0'終端文字列として扱いたいのか、
単なるバイト列として扱いたいのか質問者さんの文章からはよく分かりませんでしたが。)


> //あるファイルのデータから、nバイト目~nバイト目を
> //構造体を用いて判定して、その部分の指定データを置換(変換)する。
やりたいのが本当にこれだけなら、そもそも構造体使う必要性が低い気がします。


それと気になったのですが、なぜ変数をmain関数内で宣言していないのでしょうか
グローバル変数にする必要性はなさそうなのですが?
あと、main関数の最後のreturnを忘れてますよ。
    • good
    • 0

sscanf(buff,"%s %s %s", list[i].kozo_a, list[i].kozo_b, &list[i].kozo_c);



ここで sscanf の戻り値を確認してみてください。
多分質問者さんの期待するのとは違う値になっているはずです。

で構造体が

struct shohin
{
char kozo_a [colum_a];
char kozo_b [colum_b];
char kozo_c [colum_c];
char kozo_d [colum_d];
char kozo_e [colum_e];
char kozo_f [colum_f];
};

この定義だと kozo_a と kozo_b (後に続くものも同様)は
連続していますよね。そこにきて各配列メンバーの末尾に
ナルバイトが入っていないので

list[0]:
kozo_a:aaaaabbbbbccccc
kozo_b:bbbbbccccc
kozo_c:ccccc

こうなると。

レコードもフィールドも固定長なら、sscanfなんて持ち出さないで
直接格納してしまえばいいのでは? 各メンバーの終端をどう処理するか
を考える必要はありますが。
そもそもこのレコードをフィールドに分割する必要があるんでしょうか?

ほかにもいろいろ指摘したいところはありますがこのくらいにしておきます。
    • good
    • 0

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