fgetsとsscanfが使いこなせません

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

fgetsとsscanfが使いこなせません

#1

投稿記事 by シノニム » 15年前

いつもお世話になりっぱなしですいませんシノニムです

現在コンソールアプリでこのようなプログラムを作ってみたんですが
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <d3d9.h>
#include <d3dx9.h>

// グローバル変数の定義
FILE *fp;                // 譜面読み込み用のファイルポインタ
int MaxCombo = -1;        // コンボ数
int LastCnt = 0;        // 最終カウント

// モード用
enum
{
    ON,
    OFF
};

// 読み込みの際の構造体
typedef struct CHECK_NOTE
{
    char text[2];
    char code[7];
    int s1;
    int s2;
    int s3;
    int s4;
    int s5;
    int s6;

    // コンストラクタ
    CHECK_NOTE(){
        strcpy(text, "NULL");
        strcpy(code, "NULL");
        s1 = OFF;
        s2 = OFF;
        s3 = OFF;
        s4 = OFF;
        s5 = OFF;
        s6 = OFF;
    }
}CHECK_NOTE;

void main(void)
{

    fp = fopen("NORMAL.txt","r");

    int m = 0;
    CHECK_NOTE Checker;
    while(MaxCombo < 0)
    {
        
        // 構造体変数郡の一部初期化
        CHECK_NOTE();

        // ファイルから1行分読み込む
        fgets(Checker.text, 30, fp);

        // 構造体の各変数に数値を出力
        sscanf(Checker.text, "%s:%d:%d,%d,%d,%d,%d", 
                                        Checker.code, 
                                        &Checker.s1, 
                                        &Checker.s2, 
                                        &Checker.s3, 
                                        &Checker.s4,
                                        &Checker.s5,
                                        &Checker.s6);


        // 終了のカウントと最大コンボ数の出力
        if( (strcmp(Checker.code, "FINISH") == 0) )            LastCnt = Checker.s1;
        else if( (strcmp(Checker.code, "COMBO" ) == 0) )    MaxCombo = Checker.s1;
        // コードがNULLなら
        else if( (strcmp(Checker.code, "NULL" ) == 0) )        ++ m;

        printf("%s\n", Checker.text);

    }
    printf("%d", m);
    fclose(fp);

};
うまく一行ずつ表示してくれません
OSはWindowsXP
言語はC++です

どなたかアドバイスお願いします

box

Re:fgetsとsscanfが使いこなせません

#2

投稿記事 by box » 15年前

>    char text[2];

題意を満たすには明らかにサイズが不足しています。
設計を見直す必要があります。

Justy

Re:fgetsとsscanfが使いこなせません

#3

投稿記事 by Justy » 15年前

 どこから突っ込めばいいのか迷うところですが、boxさんの指摘に加えて sscanfのフォーマット指定にも
問題があります。

 %sが使用されていますが、これでは ':'を越えて Checker.codeに格納しようとしますし
なにより Checker.codeで確保された文字列バッファを越えて格納してしまう危険があります。

シノニム

Re:fgetsとsscanfが使いこなせません

#4

投稿記事 by シノニム » 15年前

ご指摘ありがとうございます

>> boxさん
確かに・・・完全に見落としてました

char text[30];
char code[10];

に修正しました。ありがとうございます



>> Justyさん
Googleでググってみたところこのような使い方をしていたので、それを使わせてもらったたんですが、間違ってましたか?



上記修正したところ、COMBOの一行を読み込んでループから抜けませんでした。これから直してみようと思います

Justy

Re:fgetsとsscanfが使いこなせません

#5

投稿記事 by Justy » 15年前


> 間違ってましたか?

 間違っているかどうかは、デバッガなどで確認してみるとわかると思います。
 コードを見た限りでは今の指定ですと Checker.codeに入れられる文字数分だけ、その行が入ることになります。
 %s指定は空白類になるまでを文字列と見なして取り込むので、テキストの1行目が
[color=#d0d0ff" face="monospace]
NULL:408:0,1,1,1,1
[/color]

で、code[10]なのだとしたら 10文字分の "NULL:408:0"(終端なし)が codeに入ります。

 これは意図した通りではないですよね?


 解決方法としてはとりあえず2つほど紹介しておきます。

1 .textで受けた文字列を : で分解してから、それぞれを解析

 文字列を1文字ずつ調べて解析します。
 
 一例を挙げると、最初の : で区切り
 ・ NULL
 ・ 408:0,1,1,1,1
 の2つの文字列に分解し、前者はそのまま codeに、後者は sscanfにかけて解析する、とか。


2 フォーマット指定を "%9[^:]:%d:%d,%d,%d,%d,%d"とする。
 %[^:]で ':'が現れるまでの文字列を codeに格納します。
 また、9と長さの指定もありますので、codeには最大 9文字までが格納されます。


 どちらの方法をとるにしても、scanf/sscanfを実行した際には必ず戻り値を確認して、
全てのフォーマット指定が機能したかどうを、きちんと確認するようにしてください。

シノニム

Re:fgetsとsscanfが使いこなせません

#6

投稿記事 by シノニム » 15年前

>> Justyさん

とても親切かつ丁寧な説明ありがとうございます!

%sが空白で区切られるのは初めて知りました。またひとつ勉強になりました

2の方が簡単そうだったので2の方法を使いましたが、1の方法も時間があるときに試してみたいと思います。

無事解決しました。boxさん、Justyさん、ありがとうございました!

Justy

Re:fgetsとsscanfが使いこなせません

#7

投稿記事 by Justy » 15年前


> %sが空白で区切られるのは

 テキストファイルの方を
[color=#d0d0ff" face="monospace]
NULL:408:0,1,1,1,1
[/color]
から
[color=#d0d0ff" face="monospace]
NULL 408:0,1,1,1,1
[/color]

にできるのであれば、"%s%d:%d,%d,%d,%d,%d"というフォーマットにしても
大丈夫ですね。

閉鎖

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