条件式のelseの書き方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
janpo
記事: 4
登録日時: 1年前

条件式のelseの書き方

#1

投稿記事 by janpo » 1年前

大学の授業の課題について質問があります。
各行に1単語が羅列している辞書ファイルをコマンドラインから読み取り、標準入力に単語を入力すると二部探索で入力した単語の行数を探し、行数を返すコードです。
標準入力が終わるまで入力と出力を繰り返し、Ctrl+Dで終了します。
質問はファイルにない単語を入力した場合、-1を返すように書かなければならないのですが、60行目あたりの条件文でelseのときに-1をzに代入したらよいと思って、以下のコードのように書きました。
しかし、ファイルにない単語を入力しても何も表示されません。ファイルにある単語を入力すると行数は表示されます。何が原因なのかご指摘いただきたいです。
また、6行目のint mojiretsu...から24行目は授業で提示されたコードなのですが、18行目からの部分は何を表しているのか教えていただきたいです。
試したこと:zの初期を-1にしておき、elseの時にzをprintするように書きましたが上手くいきませんでした。

コード:

#include <stdio.h>
#include <stdlib.h>
typedef struct {
  unsigned char s[24];
} word;                    
int mojiretsu(unsigned char *a, unsigned char *b) {
while((*x==*y)&&(*x!=0)&&(*y!=0)){
  x++;
  y++;
 }                      //10行目
  if (*x<*y){
    return -1;
  }else if(*x>*y){
    return 1;
  }else if(*x==*y){
    return 0;
  }
int r = *x - *y;
while((r == 0) && (*x != 0)) {
x++; y++;                                                           //20行目
r = *x - *y;
}
return r;
}
int main(int argc, char **argv) {
  int i,c,k;
  unsigned char t[30];
  word dict[220000];
  FILE *fp;
  if (argc < 2) {               //30行目
    fprintf(stderr,"usage: ./a.out dictFile\n"); exit(1);
  }
   if ((fp=fopen(argv[1],"r")) == NULL) {
    fprintf(stderr,"cannot open file %s\n",argv[1]); exit(1);
  }
   i=0; k=0;
  while((c=fgetc(fp)) != EOF) {
    if (c == '\n') {
      dict[i].s[k] = 0;
      i++;                  //40行目
      k=0;
    } else {
      dict[i].s[k] = c;
      k++;
    }
  }
  fclose(fp);
  int z;
  int a, b, middle;
  while(scanf("%s",t)!=EOF){         //50行目
    a=0;b=110000;
    while(a<b){
      m=(a+b)/2;
      if(moji(dict[middle].s, t)==0){
	z=middle+1;
	break;
      }else if (moji(dict[middle].s, t)>0){
	b=m;
      }else if (moji(dict[middle].s, t)<0){
	a=m;                //60行目
      }else{
	z=-1;
      }
    }
    printf("%d\n",z);
  }
  return 0;
}

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

Re: 条件式のelseの書き方

#2

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

まず、未定義の識別子mojiおよびm、および未初期化の変数middleが使われているのが致命的ですね。
このような致命的なミスがあるにもかかわらず「行数は表示されます」ということは、
このコードではなく別のコードを実行していると考えられます。
意図通りのコードを実行するよう気をつけてください。
(例えばファイル名やディレクトリの間違い、およびコンパイル忘れに注意)

その前でreturnしているので、18~21行目は実行されないダミーですね。
仮に関数mojiが副作用が無く整数を返す関数である場合、その返り値は必ず0または正または負なので、
61~62行目のelse句は実行されず、意味が無いですね。

二分探索で目標の値を探すときに範囲に中間の値をそのまま代入してしまうと、
見つからない時最後に範囲が変わらなくなって無限ループになってしまうことがあるので、
中間の値+1(目標が後ろの場合) や中間の値-1 (目標が前の場合) を代入するようにするといいでしょう。
二分探索 - Google 検索
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

box
記事: 2002
登録日時: 13年前

Re: 条件式のelseの書き方

#3

投稿記事 by box » 1年前

ぱっと見なんですけどね

コード:

int mojiretsu(unsigned char *a, unsigned char *b) {
while((*x==*y)&&(*x!=0)&&(*y!=0)){
このコード、コンパイル通ってます?
xとかyとかって、どこで定義したんですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

janpo
記事: 4
登録日時: 1年前

Re: 条件式のelseの書き方

#4

投稿記事 by janpo » 1年前

すいません。
もともとmとしており、middleの方がわかりやすいと思ったので書き換えたのですが、他所で書き換えるのを忘れていました。mojiや、a、bも同様です。
確認不足で逆に分かりにくくなってしまいました。
申し訳ありません。

box
記事: 2002
登録日時: 13年前

Re: 条件式のelseの書き方

#5

投稿記事 by box » 1年前

そしたらですね、
質問者さんのところにあるコードを
「そのままコピペして」
すべて見せていただくことは可能ですか?
そうしないと、質問者さんとここにいる人たちが
同じものを見ていることにならず、
的確な回答が来ないおそれがあるからです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

janpo
記事: 4
登録日時: 1年前

Re: 条件式のelseの書き方

#6

投稿記事 by janpo » 1年前

janpo さんが書きました:
1年前
書き直しました。
大学の授業の課題について質問があります。
各行に1単語が羅列している辞書ファイルをコマンドラインから読み取り、標準入力に単語を入力すると二部探索で入力した単語の行数を探し、行数を返すコードです。
標準入力が終わるまで入力と出力を繰り返し、Ctrl+Dで終了します。
質問はファイルにない単語を入力した場合、-1を返すように書かなければならないのですが、60行目あたりの条件文でelseのときに-1をzに代入したらよいと思って、以下のコードのように書きました。
しかし、ファイルにない単語を入力しても何も表示されません。ファイルにある単語を入力すると行数は表示されます。何が原因なのかご指摘いただきたいです。
また、6行目のint mojiretsu...から24行目は授業で提示されたコードなのですが、18行目からの部分は何を表しているのか教えていただきたいです。
試したこと:zの初期を-1にしておき、elseの時にzをprintするように書きましたが上手くいきませんでした。

コード:

#include <stdio.h>
#include <stdlib.h>
typedef struct {
  unsigned char s[24];
} word;
int moji(unsigned char *a, unsigned char *b) {
while((*a==*b)&&(*a!=0)&&(*b!=0)){
  a++;
  b++;
 }
  if (*a<*b){
    return -1;
  }else if(*a>*b){
    return 1;
  }else if(*a==*b){
    return 0;
  }
int r = *a - *b;
while((r == 0) && (*a != 0)) {
a++; b++;
r = *a - *b;
}
return r;
}
int main(int argc, char **argv) {
  int i,c,k;
  unsigned char t[24];
  word dict[110000];
  FILE *fp;
  
  if (argc < 2) {
    fprintf(stderr,"usage: ./a.out dictFile\n"); exit(1);
  }
   if ((fp=fopen(argv[1],"r")) == NULL) {
    fprintf(stderr,"cannot open file %s\n",argv[1]); exit(1);
  }
   i=0; k=0;
  while((c=fgetc(fp)) != EOF) {
    if (c == '\n') {
      dict[i].s[k] = 0;
      i++;
      k=0;
    } else {
      dict[i].s[k] = c;
      k++;
    }
  }
  fclose(fp);
  int z;
  int a, b, middle;
  while(scanf("%s",t)!=EOF){
    a=0;b=110000;
    while(a<b){
      middle=(a+b)/2;
      if(moji(dict[middle].s, t)==0){
	z=middle+1;
	break;
      }else if (moji(dict[middle].s, t)>0){
	b=middle;
      }else if (moji(dict[middle].s, t)<0){
	a=middle;
      }else{
	z=-1;
      }
    }
    printf("%d\n",z);
  }
  return 0;
}


box
記事: 2002
登録日時: 13年前

Re: 条件式のelseの書き方

#7

投稿記事 by box » 1年前

またもやぱっと見ですけどね
main()が長すぎると思います。プログラム全体をいくつかに機能に適切に分割し、
それらを実行する関数群を構成し、mainはそれらを呼ぶだけで全体の司令塔に徹する、
という設計がいいのかな~と個人的には思います。他の人がどう思うかは知らんけど。

あと、mojiっていう関数の動作を「日本語で」説明できますか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 13年前

Re: 条件式のelseの書き方

#8

投稿記事 by box » 1年前

mojiっていう関数の動作を「日本語で」説明できますか?
なんでこんなこと聞いてるかっていうとですね、今のmoji()には、
別の回答にもあるとおり、
「絶対に通らない部分」があるからなんですよ。
それは

コード:

    int r = ~
以下の部分。
絶対に通らない部分なんていらないですよね?
いらんのだったら消せばいいし、いるんだったら
通るようにロジックを見直す必要があるんとちゃう?ってことです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

janpo
記事: 4
登録日時: 1年前

Re: 条件式のelseの書き方

#9

投稿記事 by janpo » 1年前

int r〜以下の部分は配布された資料に書かれていたコードであり、理解できていません。ミケCAT様からの回答に18〜21行目はダミーと書かれていたので、その部分はあってもなくても変わらないものだと解釈しました。

box
記事: 2002
登録日時: 13年前

Re: 条件式のelseの書き方

#10

投稿記事 by box » 1年前

int r〜以下の部分は配布された資料に書かれていたコードであり、理解できていません。
ということはその部分を理解できずにmoji()の上の方を書いたってことですね。
そういうことでしたら、このトピックに関する当方からの回答は差し控えることにします。
わからずに書いているコードに論評する資格は当方にはありませんので。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 条件式のelseの書き方

#11

投稿記事 by usao » 1年前

関数を提示するならするで
「この関数というのは何をするもので,引数はこういうもので,戻り値はこうなる」っていうような説明をまともにすればいいのに.
そういった正しい動作に関する説明が関数 moji() に対して存在していたら,こんな無意味に話がこじれたりしないよね,きっと.

(まぁ,それが把握できているならこんな関数名を付けてはいないであろう,とも思えるが)

返信

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