ファイルの構造について質問です

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
(≧Д≦)

ファイルの構造について質問です

#1

投稿記事 by (≧Д≦) » 10年前

c言語で数字と文字がスペースで区切られたファイルを読み込み、各行の数字と文字を行に対応する構造体に格納する、というプログラムを作りたいです
具体的には

1 hello
2 bye

というファイルを読み込むと、構造体が2つ完成し、その一つはint型の1とchar型配列のhelloを保持し、もうひとつは・・・という動作を希望しています。

とりあえず書いてみたのはいいものの、出力が妙なことになっているので、助言をください。以下にソースと出力を載せます
よろしくお願いします

コード:

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


/*構造体YJの定義*/
typedef struct yj
{
        int num;
        char word[100];
        struct yj *next;
}YJ;


/*領域確保用の関数*/
YJ *newyj()
{
        YJ *p;
        p=(YJ *)malloc(sizeof(YJ));

        if(p==NULL)
        {
                fputs("malloc failedn\n",stderr);
                exit(1);
        }
        else
        {
                return p;
        }
}


int main()
{
        FILE *fp;//ファイルポインタ
        char *fname="test.txt";//ファイル名
        char number[100],*p;//atoi変換用とポインタp
        int c,i=0,flag=0;//fgetcの返り値はint型なんだよなぁ。あとループ用のiそしてスペースで区切るためのflag
        YJ *top,*now,*new;//YJ型の先頭用と現在用と新生用 

        new=newyj();//領域確保
        now=new;//nowを先ほど確保したnewの指す領域を指させる
        top=now;//これでtopが指すのは最初の領域(書き込みではnowしか動かさない)
        p=&number[0];//pのさすアドレスをnumber[0]のアドレスに指定



        fp=fopen(fname,"r");//ファイル開く
        if(fp==NULL)//エラー処理
        {
                printf("file open failed(%s)\n",fname);
                return -1;
        }


        /*ここでメインの処理*/
        while((c=fgetc(fp))!=EOF)
        {
                /*このループで数字を抜き出す*/
                if(isdigit(c))//さらに数字の時
                {
                        *p=c;//number配列にcを入れていく
                        p++;//アドレスを容量分増やす
                }
                else if((c==' ')&&(flag==0))//
                {
                        *p='\0';//atoi変換には、配列の最後に終了記号?が必要だったはず
                        now->num=atoi(&number[0]);//nowのnumはatoiで変換された数字が入る
                        flag=1;
                }
                else if(c!='\n')//cが改行記号でない時
                {
                        now->word[i]=c;//nowの指す領域word配列に一つづつ入れていく
                        i++;//添字増やす
                }
                else if(c=='\n')
                {
                        now->word[i]='\0';//この時点で現在のnowが指している領域のnumとwordには、行に対応した数字と文字が入っている
                        new=newyj();//新しい領域確保
                        now->next=new;//これにより、現在のnowの指す領域のnextは上で確保した領域となる
                        now=new;//次のループに向け、nowを上で確保した領域に再指定

                        /*---------------ここらへんは全部ループのための再設定-------------------*/
                        p=&number[0];
                        i=0;
                        flag=0;
                }
        }

        /*ここを抜けた後は、nowの指す領域のnextはまだ確定していないため、NULLに指定する*/
        now->next=NULL;
        fclose(fp);

        /*表示させる*/
        now=top;
        while(now!=NULL)
        {
                printf("%d,%s\n",now->num,now->word);
                now=now->next;
        }


        return 0;
}

入力
-----------------------------------------------------------
810 this is the basic number of yj.
893 YAKUZA is yakuza.
19191919 this is yj's crying voice.
45454545 fapfapfapfap.
114514 very famous.
------------------------------------------------------------

出力
------------------------------------------------------------
810,this is the basic number of yj.
893,YAKUZA is yakuza.
19191919,this is yj's crying voice.
45454545,fapfapfapfap.
114514,very famous.
0,
0,
0,
------------------------------------------------------------



------------------------------------------------------------

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: ファイルの構造について質問です

#2

投稿記事 by みけCAT » 10年前

gcc 4.8.1でコンパイルして試したところ、提示されているような余計な0は出力されませんでしたが、
最後に1行ゴミが出力されました。

最後の行を読み込んだ後、次のデータを格納する領域のみを作って肝心のデータを入れてないからだと思われるので、
何らかの方法でチェックするか、データを格納する領域の作成のタイミングを変える必要があると思います。
また、mallocで確保した領域はfreeで開放することを推奨します。

コード:

YUKI.N>ls -l
合計 8
-rwxrwxrwx  1 kota 0 3067 2014-11-11 21:37 fairunokouzou.c
-rw-rw-rw-  1 kota 0  142 2014-11-11 21:38 test.txt

YUKI.N>gcc -O2 -Wall -Wextra -s -static -o fairunokouzou.exe fairunokouzou.c

YUKI.N>fairunokouzou.exe
810,this is the basic number of yj.
893,YAKUZA is yakuza.
19191919,this is yj's crying voice.
45454545,fapfapfapfap.
114514,very famous.
12141816,8 ケ

YUKI.N>
添付ファイル
fairunokouzou.zip
テスト
(10.19 KiB) ダウンロード数: 87 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

(≧Д≦)

Re: ファイルの構造について質問です

#3

投稿記事 by (≧Д≦) » 10年前

みけCATさん、アドバイスありがとうございます。

おっしゃる通り、メインのwhileループを抜けたあとに、now->next=NULLとしているために、表示の時も、ひとつ余計に構造体の中身を表示していました。
ここから、一つ前の構造体を指すポインタを定義するのもアレなので、構造体が絡んだループ処理をするときは、(now->next!=NULL)を条件文に使っていこうと思います。
また、たまに混じるゴミなのですが、どうやらflag==0の状態(数字を構造体に書き込む段階)で、改行記号が入力されると、これまた勝手に数字も文字列も格納しないにもかかわらず、nextのアドレスだけを持つ構造体が生成されてしまっていたようです。なので、以下のように

コード:

if((c=='\n')&&(flag==0))
                {
                        continue;
                }

条件文をメインの処理の最初に入れることで、行と行の間に何も入力がないただの改行でも、意図する動作が実現できるようになりました。
どうもありがとうございました。

やっぱぁ…ここのフォーラムを…最高やな!ありがとナス!

閉鎖

“C言語何でも質問掲示板” へ戻る