質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • C++

    3594questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • for

    245questions

    for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

  • ループ

    53questions

    ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

C++でforループがうまくいきません

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 885

yasunori_bam

score 1

前提・実現したいこと

C++で簡単なタイピングゲームを作っています。
ファイルからランダムな行を読み込んで、","で分割して分割した2番目の単語を入力させるものです。

発生している問題・エラーメッセージ

ループ中、時々p_word_afterの指す値がNULLになります。この時、p_word_beforeの指す文字列は一つ前のループのときと同じになっています。
ちなみに、rand()%55の値が同じである場合はp_word_afterに値が入っているので、これは原因ではないと思います。これはどういった現象なんでしょうか。

該当のソースコード

int key=0,count,score=0,mistake=0,ran=0,line,add,word_num;
int level=0;
char *advise;
unsigned i;
char line_text[256];
char word_before[50][128];
char word_after[50][128];
char *p_word_before;
char *p_word_after;
FILE *fp;
fp=fopen(<<filename>>,"r");
for(count=50;count>0;count--){
    rewind(fp);
    p_word_before=word_before[count];
    p_word_after=word_after[count];
    int len;
    srand((unsigned)time(NULL));
    line=0;
    for(line=rand()%55;line>0;line--){
        fgets(line_text,256,fp);
    }
    p_word_before=strtok(line_text,",");
    p_word_after=strtok(NULL,",");
    system("cls");
    add=0;
    while(*(p_word_after+add)!='\n'){
        add++;
    }
    *(p_word_after+add)='\0';
    printf("%s (%s) 残り%d単語\n",p_word_before,p_word_after,count);
    i=0;
    len=strlen(p_word_after);
    while(i<len){
        if(_kbhit()){
            key=_getch();
            if(key==0||key==224)key=_getch();
            if(key==p_word_after[i]){
                printf("checked %c\n",key);
                i++;
                score++;
            }else{
                mistake++;
            }
            fflush(stdin);
        }
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

IDE : VisualStudio2012 for Desktop

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • HogeAnimalLover

    2016/05/08 21:38

    それはどこの行です発生していますか?strtokで発生しているならばこの仕様を調べれば良いと思います。(検索対象が見つからない場合にNULLが返る)

    キャンセル

回答 2

checkベストアンサー

0

こんにちは。

ざっと見る限り、yasunori_bamさんが記載されている現象が起こるソースのようには見えません。

rand()%55が0の時はfgets(line_text,256,fp);が実行されませんので、p_word_beforeに「前回」のfor(count)ループ時の値が入ることはありえますが、その時、p_word_afterにも前回と同じ値が入る筈なのでNULLにはならない筈です。

また、rand()%55が例えば5の時、p_word_afterに値が入ったり、NULLが入ったりするのですね?
それもちょっと考えにくいです。・・・①

ただ、もし、サブ・スレッドを使っていてサブ・スレッドでもstrtok()を使っていたら、何が起こるか分かりませんので、ご説明されたような事象が起きる可能性はあります。strtok()はスレッド安全ではありませんので。
しかし、ご提示された内容からサブ・スレッドを使っているとは思えません。

試しに、下記の直後で、line_text、p_word_before、p_word_afterを表示してみては如何でしょうか?
何か掴めそうな気がします。

p_word_before=strtok(line_text,",");
p_word_after=strtok(NULL,",");

ところで、①の現象はどのようにして確認されましたか? どうもその確認にミスがありそうな予感がします。
また、ファイルは55行以上存在し、その全ての行にはp_word_afterがNULLになることはない文字列が入っていることは確認できていますか? 例えば、p_word_afterがNULLにならない行を55行コピペしておけば簡単に条件を作れると思います。


因みに下記はミスですね?(特に影響はないと思いますが。)

p_word_before=word_before[count];
p_word_after=word_after[count];

countは50から始まりますが、 word_before[50][128],  word_after[50][128]ですので、word_before[49][], word_after[49][]までしかありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/08 23:34

    > その時、p_word_afterにも前回と同じ値が入る筈なのでNULLにはならない筈です。

    strtok関数は渡された文字列バッファに書き込みを行います(区切り文字のところにnull終端を書き込む)。ですので、ファイルから読まなかった場合、バッファの内容は前回とは違うものになります。

    キャンセル

  • 2016/05/08 23:40

    あああ、そういえばそうでした。フォローありがとうございます。
    ということは、rand()%55が0の時に限って発生しそうですね。

    しかし、この質問を開いた時はまだcatsforepawさんの書き込みなかったのに...
    書き込む前にチェックするようにしているのですが、時々忘れちゃいます。orz

    キャンセル

  • 2016/05/08 23:45

    回答有り難うございます。①の現象はVisualStudioのデバッグモードで変数の値を確認しながら実行して結果を得ました。
    ご提案いただいた通り、p_word_before,p_word_after,line_textを表示してみたところ、rand()%55のときline_textに前のループ(for(count+1))のときの分割後のline_textが入っていました。ほんとにありがとうごうざいました!

    キャンセル

  • 2016/05/08 23:49

    Chironian さん

    > 書き込む前にチェックするようにしているのですが、時々忘れちゃいます。

    私もです……。

    キャンセル

0

ぱっと見て気になったことが一点。

for(count=50;count>0;count--){

この記述だと、ループの中ではcountが50から始まって最後に1になります。

p_word_before=word_before[count];
p_word_after=word_after[count];

それぞれの配列は[50]で確保されているため、添え字に指定可能な範囲は0~49です。ループ初回でcountに50が入っているので、配列の範囲を超えています。


しっかり見て気になった点を。

for(line=rand()%55;line>0;line--){
   fgets(line_text,256,fp);
}

rand()%55は0になる可能性があります。その場合、条件判定でいきなりループ終了になるため、ループ内のfgetsが実行されません。
そうなると、line_textに正しい文字列が入らず、strtok関数が正しい結果を返さないのだと思います。

line=rand()%55 + 1とすれば良いと思います。


補足
strtok関数は、返すべき文字列がないとNULLを返します。前述のループでfgetsを実行しないまま抜けると、前回のバッファの内容が残っているわけですが、区切り文字が消されてしまっているので最初のstrtokで文字列全体を返してしまい、次のstrtokでは返すべき文字列がないという状況になったのだと思われます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

  • 解決済

    python リスト型 remove文

    data = [1,1,2,1,3,4] for num in data: if data.count(num) < 2: data.remove(num) return d

  • 解決済

    タイピングゲームの作成、乱数について

    前提・実現したいこと Cでタイピングゲームのような物を作っているのですが、今のコードのままだとランダムに表示させた問題を正解したときに再度同じ問題が出てしまいます 既に使用した

  • 解決済

    c言語 リスト構造の検索

    アドレス帳の検索機能だけのプログラムを作っています。 作りたいプログラムは、  1,検索したい人の名前を入力する  2,事前に登録された情報の中から部分一致検索する 

  • 解決済

    c言語学習中の学生です。

    前提・実現したいこと c言語を学んでいる学生です。 非常に低レベルな質問ですがお願いします。 Windows10でmingwを使っています。 発生している問題・エラーメッセージ

  • 解決済

    char型の配列変数にchar型の変数を代入したい

    使用言語 C 環境 Visual Studio 2017 初めての質問です。 独学でプログラミングを始めたのですがわからないところがあり困っています。 char型の配列変数の使い方

  • 受付中

    プログラムを見やすく改良したい

    正常に動くプルグラムを見やすく改良したい。 具体的に教えていただければありがたいです。セグメンテーションフォルトでベスト7まで表示して停止します。173行あたりだと思うのですが、よ

  • 解決済

    電話帳で修正関数を作っています。修正箇所が浮かんでこないので助言をおねがいします。

    電話帳で修正関数を作っています。 //氏名を修正する。 //電話番号を修正する。 のところで修正箇所のコードの書き方が浮かんでこないのでの助言、ヒント をお願いできればありがたいで

  • 解決済

    存在する組み合わせを数えたい

    例えば下のような文字列がある場合 あいう あうえ い うい この4つの文字列のうち同じ文字の組み合わせをもつ文字列を数えたいです。 上の場合、たとえば「あ」と「う」があるのは「あい

同じタグがついた質問を見る

  • C++

    3594questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • for

    245questions

    for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

  • ループ

    53questions

    ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します