掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.24909

過去形の出力
投稿者---esp(2005/12/22 17:38:41)


入力した動詞の現在形を辞書を利用して過去形にして出力し、辞書に該当する単語がなければ「辞書にありません」と回答するようにするプログラム(ループして何度も処理できるようにする)なのですが、実行時eatとate
の次の行から「辞書にありません」が9つ出てしまいます。解決方法を教えてほしいです。
また、標準入力から現在形の英文を読み込み、規則動詞を見つけ出し、過去形に変えて出力するプログラムもfgetsを使うのだと思うのですがお教えいただきたいです。


#include <stdio.h>
#include <string.h>

main()
{
int i, j, st;
char v[100];
static char *dic[10][2] = {              /*辞書*/
{"eat","ate"},{"walk","walked"},{"like","liked"},
{"die","dyed"},{"look","looked"},{"take","took"},
{"hit","hit"},{"swim","swam"},{"run","ran"},{"play","played"}};

while(scanf("%s",v) != EOF){
for(i=0; i<10; i++){
if(strcmp(v,dic[i][0]) == 0){
printf("%s\n", dic[i][1]);
}
}
for(i=0; i<10; i++){
if(strcmp(v,dic[i][0]) != 0){
printf("辞書にありません\n");
}
}
}
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:過去形の出力 24912 esp 2005/12/22 17:48:29
<子記事> Re:過去形の出力 24938 まきじ 2005/12/23 18:48:50


No.24912

Re:過去形の出力
投稿者---esp(2005/12/22 17:48:29)


インデックス揃ってないです。見にくくてすいません。



この投稿にコメントする

削除パスワード

No.24916

Re:過去形の出力
投稿者---RAPT(2005/12/22 18:44:00)


> インデックス揃ってないです。見にくくてすいません。
インデントね。

インデントを入れて、HTML変換ツールを使って、環境を明示してください。

# 謝っておいて、なぜ修正(or再投稿)しないかなー??



この投稿にコメントする

削除パスワード

No.24917

Re:過去形の出力
投稿者---esp(2005/12/22 18:59:20)


すいません。初カキコでよくわからなかったんです。少し調べればできたのに・・・
環境はWindowsXPでコンパイラはBorland C++ Compiler 5.5です。
よろしくお願いします。

#include <stdio.h>
#include <string.h>

main()
{
  int i, j, st;
  char v[100];
  static char *dic[10][2] = {
    {"eat","ate"},{"move","moved"},{"copy","copied"},
    {"die","dyed"},{"talk","talked"},{"take","took"},
    {"hit","hit"},{"swim","swam"},{"run","ran"},{"play","played"}};

      while(scanf("%s",v) != EOF){
        for(i=0; i<10; i++){
          if(strcmp(v,dic[i][0]) == 0){
             printf("%s\n", dic[i][1]);
          }
        }
        for(i=0; i<10; i++){
          if(strcmp(v,dic[i][0]) != 0){
             printf("辞書にありません\n");
          }
        }
     }
}
 



この投稿にコメントする

削除パスワード

No.24921

Re:過去形の出力
投稿者---shu(2005/12/22 20:25:19)


こんな感じ。

    while (fgets( buf, sizeof(buf), stdin ))
    {
        //
        if (/* 文字列が辞書に無かったら */)
        {
            puts( "辞書にありません" );
            continue;
        }

        //
        puts( dic[i][1] );
    }



この投稿にコメントする

削除パスワード

No.24927

Re:過去形の出力
投稿者---esp(2005/12/23 00:10:38)


shuさん返信ありがとうございます。
ifの中にstrcmp(buf,dic[i][0]) != 0)と書いて実行してみても、
うまくいきませんでした。条件文が間違っていたでしょうか。




この投稿にコメントする

削除パスワード

No.24928

Re:過去形の出力
投稿者---まきじ(2005/12/23 00:46:28)


>ifの中にstrcmp(buf,dic[i][0]) != 0)

これだと dic[i] と違うたびに if 文の中が実行されます。
dic[0] から dic[9] に無ければ if 文の中を実行するのですよ。


この投稿にコメントする

削除パスワード

No.24929

Re:過去形の出力
投稿者---esp(2005/12/23 02:45:58)


>dic[0] から dic[9] に無ければ if 文の中を実行する
strcmpは使わなさそうなのでそれ抜きで考えており、i<10と書いたら「辞書にはありません」がi>10と書けば辞書の過去形が全部表示されるなど、自分の望む結果とは程遠いものしか出てきません。


この投稿にコメントする

削除パスワード

No.24930

Re:過去形の出力
投稿者---ゾン兵衛(2005/12/23 06:59:35)


>自分の望む結果とは程遠いものしか出てきません。

 どのようにソースを変更したら、コンパイルや、実行時に
どんな結果が出たのか具体的に書いたほうがいいです。


 提示されたソースでは、最初の"for"文と2番目の"for"文が独立して回っているので、
"eat"と入力した場合、

ate ・・・・・・・・・・・・ (最初の"for"文の結果)
(表示なし) ・・・・・ (2番目の"for"文の i == 0 のとき)
辞書にありません (2番目の"for"文の i == 1 のとき)
〜〜〜〜〜〜〜
辞書にありません (2番目の"for"文の i == 9 のとき)

となります。

この場合、最初の"for"文で辞書の検索はすんでいるので、
その結果を利用すれば、一回のLoopですみます。

例えば、
 入力した文字列が,辞書にあれば"break"でLoopを抜ける。
 この場合,Loop回数(i)は、"0"〜"9" になる。
 もし,文字列が辞書になければ、Loopは最後まで回りLoop回数(i)は"10"になるので、
 Loop回数(i)が"10"なら、"辞書にありません"と表示する。

または、
 フラグを設定して、"0"で初期化する。
 文字列が辞書にあればフラグを"1"にする。
 フラグが"0"なら、"辞書にありません"と表示する。



この投稿にコメントする

削除パスワード

No.24931

Re:過去形の出力
投稿者---esp(2005/12/23 15:11:37)


下のプログラムを実行させ単語を入力したところ過去形は表示されずに、「slシZタYタ」なる意味不明なものが出てくるだけでした。 また、fgesの所をscanfにしてputsの所をprintfにした所、過去形は表示されたのですが、辞書に対応してないとき、「辞書にありません」ではなく、また「slシZタYタ」がでてきました。ならばと思い、dic[10][1]='\0'と加えてみたら、「辞書にありません」と出るべき場所に(null)が出るようになりました。
もう一息という所まで来ていると思うのでよろしくお願いします。



#include <stdio.h>
#include <string.h>

int main(void)
{
        int i;
    char buf[100];
        static char *dic[10][2] = {
          {"eat","ate"},{"move","moved"},{"copy","copied"},
          {"die","dyed"},{"walk","walked"},{"take","took"},
          {"hit","hit"},{"swim","swam"},{"run","ran"},{"play","played"}};
    
    while (fgets(buf,100,stdin ) != NULL){
        for(i=0; i<10; i++){
           if(strcmp(buf,dic[i][0]) == 0) break;
           else if(i==10){
              puts("辞書にありません\n");
           }
        }
        puts(dic[i][1]);
    }
}



この投稿にコメントする

削除パスワード

No.24935

Re:過去形の出力
投稿者---あかま(2005/12/23 17:35:59)


>fgetsの所をscanfにして
fgetsだと'\n'が付加されているので除去してやる必要があります。

>if(i==10)
はwhile内にありますので実行されることがありません。
そして見つからないままwhileを抜けると
>puts(dic[i][1]);
で
puts(dic[10][1]);
が出力されるのでおかしな文字が出力されます(dic[9]までしか参照してはダメ)

入力はscanfにして
if(i==10)の位置をwhileの外に変えればいいでしょう。



この投稿にコメントする

削除パスワード

No.24936

Re:過去形の出力
投稿者---iijima(2005/12/23 17:41:07)


> 下のプログラムを実行させ単語を入力したところ過去形は表示されずに、
> 「slシZタYタ」なる意味不明なものが出てくるだけでした。

fgetsはリターンキーを押したときの改行文字'\n'を末尾につけた文字列を
バッファに読み込みます。
辞書の単語には改行文字がついていませんから、辞書にある単語を入力した
つもりでも、一致する単語がないという結果になります。
# そのときに意味不明の文字列が表示される理由は後述。

fgetsを使うなら、バッファ内に取り込まれた文字列から改行文字を取り除
く処理を加えるか、あるいは、辞書の単語の文字数分だけを比較する必要が
あります。

> 辞書に対応してないとき、「辞書にありません」ではなく、また「slシZタYタ」
> がでてきました。

>        for(i=0; i<10; i++){ <--------------------※1
>           if(strcmp(buf,dic[i][0]) == 0) break;
>           else if(i==10){   <--------------------※2
>              puts("辞書にありません\n");
>           }
>        }
>        puts(dic[i][1]);     <--------------------※3

※1でiが10に等しくなったときにこのforループは終了します。
したがって、※2のところでiが10になることはなく、

    puts("辞書にありません\n");

は決して実行されません。

一方、※3はforループが終われば常に実行されます。
つまり、10回繰り返しても一致する単語が辞書になかったときfor文は終了
し、そのときのiは10ですから、※3のところではdic[10][1]を出力しよう
とします。

しかし、dic[10][1]は、配列として確保したメモリ領域の範囲外への不正
なアクセスということになります。
そして、たまたまそこに記憶されていたデータが意味不明の文字列として
出力されたということです。



この投稿にコメントする

削除パスワード

No.24937

Re:過去形の出力
投稿者---iijima(2005/12/23 18:26:35)


補足:

> fgetsを使うなら、バッファ内に取り込まれた文字列から改行文字を取り除
> く処理を加えるか、あるいは、辞書の単語の文字数分だけを比較する必要が
> あります。

辞書の単語の文字数分だけの比較だと、入力文字列が辞書の単語以上の長さ
の場合で、その先頭部が辞書の単語と一致するとヒットしてしまいます。
例えば、入力が"diet"のとき"die"でヒットします。

これを防ぐには文字数の比較もしなくてはならなくなって面倒なので、バッ
ファ文字列から改行文字を取り除く方がよさそうです。

バッファ文字列の中から改行文字'\n'を探し、それを終端文字'\0'に置き
換えれば取り除いたことになります。



この投稿にコメントする

削除パスワード

No.24939

Re:過去形の出力
投稿者---esp(2005/12/23 19:18:20)


scanfからの入力を使うとちゃんと作動しました。ありがとうございました。ここでもしfgetsから入力するならどんなプログラムになるんでしょうか?下のプログラムのscanf("%s",buf) != EOFをfgets(buf,sizeof(buf),stdin) != NULLに変えてみて実行したらうまくいきませんでした。

#include <stdio.h>
#include <string.h>

main()
{
        int i;
        char buf[100];
        static char *dic[10][2] = {
          {"eat","ate"},{"move","moved"},{"copy","copied"},
          {"die","dyed"},{"walk","walked"},{"take","took"},
          {"hit","hit"},{"swim","swam"},{"run","ran"},{"play","played"}};
    
    while (scanf("%s",buf) != EOF){
        for(i=0; i<10; i++){
           if(strcmp(buf,dic[i][0]) == 0) break;
        }
        puts(dic[i][1]);
        dic[10][1] = '\0';
        if(i==10)
        puts("辞書にありません");
    }
}



この投稿にコメントする

削除パスワード

No.24940

Re:過去形の出力
投稿者---あかま(2005/12/23 19:27:34)


マッチしない入力で試しましたか?

//dic[10][1] = '\0';
//dic[10]にアクセスしてはダメです。

if(i==10)puts("辞書にありません");
else puts(dic[i][1]);





この投稿にコメントする

削除パスワード

No.24944

Re:過去形の出力
投稿者---esp(2005/12/23 21:37:19)


こういう感じに書いたら、実行時何を打っても「辞書にありません」と出てきます。

while (fgets(buf,sizeof(buf),stdin) != NULL){
    for(i=0; i<10; i++){
       if(strcmp(buf,dic[i][0]) == 0) break;
    }
    dic[10][1] = '\0';
    if(i==10) puts("辞書にありません");
    else puts(dic[i][1]);
}





この投稿にコメントする

削除パスワード

No.24950

Re:過去形の出力
投稿者---あかま(2005/12/23 22:59:23)


>dic[10][1] = '\0';
いや、だからdic[10]にアクセスしちゃだめだってば。
なんの意味があるのです?

while (scanf("%s",buf) == 1){
    for(i=0; i<10; i++){
        if(strcmp(buf,dic[i][0]) == 0) break;
    }
    if(i==10) puts("辞書にありません");
    else puts(dic[i][1]);
}

どーしてもfgetsでやりたいときは'\n'を消すために
buf[strlen(buf)-1] = '\0';
を入れないとダメです。



この投稿にコメントする

削除パスワード

No.24938

Re:過去形の出力
投稿者---まきじ(2005/12/23 18:48:50)


/*
compiler : gcc 3.4.2 (mingw-special)
option : -std=iso9899:1999 -pedantic -O2 -Wall
*/

#include <stdio.h>
#include <string.h>

enum {N = 10, W = 256};

int main(void){
    static char *dic[N][2]={{"eat","ate"},{"move","moved"},{"copy","copied"},
                             {"die","dyed"},{"talk","talked"},{"take","took"},
                             {"hit","hit"},{"swim","swam"},{"run","ran"},
                             {"play","played"}
                            };
                            
    char word[W];
    
    printf("word:");
    fgets(word,sizeof word,stdin);
    
    char *p = strchr(word,'\n');
    if(*p) *p = '\0';
    
    int i;
    for(i = 0; i < N; i++){
        if(!strcmp(word,dic[i][0])){
            puts("HIT");
            break;
        }
    }
    
    if(i == N) puts("NO");
}



この投稿にコメントする

削除パスワード

No.24945

Re:過去形の出力
投稿者---esp(2005/12/23 21:45:28)


18行と21行に「ここでは宣言できない」というコンパイルエラーが出てしまいます。2つを上のほうに持っていって実行してもできませんでした。文字列を先頭から検索するstrchrというのは初めて見ました。勉強になります。


この投稿にコメントする

削除パスワード

No.24946

Re:過去形の出力
投稿者---まきじ(2005/12/23 21:57:24)


>18行と21行に「ここでは宣言できない」というコンパイルエラーが出てしまいます。

適切な位置で宣言してください。
ソースの上部に明記してあります開発環境で動作は確認済みです。


この投稿にコメントする

削除パスワード

No.24951

Re:過去形の出力
投稿者---esp(2005/12/23 23:10:12)


適当な場所に宣言した後、実行したらできました。
ありがとうございました。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧