文字列判定プログラム(再帰的)の課題です
文字列判定プログラム(再帰的)の課題です
文字列の判定プログラムを作っています。
{rat,cat,dog,elephant,horse,bat,hamster}
動物名を英語で与えて、上記の要素であるかどうかを判定するmemberという関数を再帰的プログラムとして作成せよ。
という内容の課題です。
条件として
条件(1)
struct cell{
char animal[20];
struct cell *next;
}
↑を用いたリスト構造として記述すること
条件(2)
memberのプロトタイプ宣言は
int member(char *,struct cell *);
第1引数:文字列
第2引数:リストへのポインタ
返り値:第1引数の文字列が第2引数のリストの要素ならば1を、そうでなければ0を返す。
条件(3)
00と入力するとプログラムを終了する。
という3つの条件があります。
自分でも組みましたが、
http://ideone.com/B7YLR
↑
どうしてもなかなかうまくいきません。
どの箇所を直したらうまく走るようになりますか?
是非教えてください。
{rat,cat,dog,elephant,horse,bat,hamster}
動物名を英語で与えて、上記の要素であるかどうかを判定するmemberという関数を再帰的プログラムとして作成せよ。
という内容の課題です。
条件として
条件(1)
struct cell{
char animal[20];
struct cell *next;
}
↑を用いたリスト構造として記述すること
条件(2)
memberのプロトタイプ宣言は
int member(char *,struct cell *);
第1引数:文字列
第2引数:リストへのポインタ
返り値:第1引数の文字列が第2引数のリストの要素ならば1を、そうでなければ0を返す。
条件(3)
00と入力するとプログラムを終了する。
という3つの条件があります。
自分でも組みましたが、
http://ideone.com/B7YLR
↑
どうしてもなかなかうまくいきません。
どの箇所を直したらうまく走るようになりますか?
是非教えてください。
Re: 文字列判定プログラム(再帰的)の課題です
ideoneに貼り付けてあるソースコードのインデントがめちゃくちゃですので、それを綺麗にするところから始めましょう。
インデントについては投稿前チェックリストのチェック2と3を御覧ください。
さて、まず構造体のポインタで詰まっているようですね。基本を書きますので参考にしてください。 という構造体があったとしましょう。
基本的な使い方は下記のようになります。
インデントについては投稿前チェックリストのチェック2と3を御覧ください。
さて、まず構造体のポインタで詰まっているようですね。基本を書きますので参考にしてください。 という構造体があったとしましょう。
基本的な使い方は下記のようになります。
struct Foo foo; /* struct Foo型の変数を生成 */
struct Foo *ptr = &foo; /* struct Foo*型のポインタ変数を生成(初期値はfooを指すようにする) */
foo.bar = 0; /* OK (なぜならば変数fooは実体だから) */
ptr.bar = 0; /* ERROR (なぜなら変数ptrはポインタだから。特にドット'.'でアクセスしているのがマズイ) */
ptr->bar = 0; /* OK (ポインタの場合はアロー演算子を使う) */
(*ptr).bar = 0; /* OK (アロー演算子は、実はこの書き方と同じ意味) */
Re: 文字列判定プログラム(再帰的)の課題です
リスト構造の話をするより前に、配列や文字列(char *)の取扱いに関する
復習が必要であるような気がします。
復習が必要であるような気がします。
例えばこの行、どういう意図で書かれているのでしょうか。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 文字列判定プログラム(再帰的)の課題です
To:beatleさん
*next->animal[20]を挿入してもうまくいきません・・
To:boxさん
リスト構造の1つのセルの中の動物名ratとして書いています。
listhead→rat|*next→cat|*next・・・といった感じをイメージしています。
例えばratと次のセルへのアドレス(&cell2)の2つをcell1と言った感じです。
*next->animal[20]を挿入してもうまくいきません・・
To:boxさん
リスト構造の1つのセルの中の動物名ratとして書いています。
listhead→rat|*next→cat|*next・・・といった感じをイメージしています。
例えばratと次のセルへのアドレス(&cell2)の2つをcell1と言った感じです。
Re: 文字列判定プログラム(再帰的)の課題です
指摘1
mainの最初にlisthead = NULL;をしているので、
そのあとのlisthead.next = &ani1;で落ちることでしょう。
その前にコンパイルできないですけどね。
listhead = NULL;でなくlisthead = &ani1;ですな。
指摘2 C言語ではこんな代入の仕方はしません というようにしないとだめです。
指摘3 charだけだと文字一つしか入力できません。
00で終了と、'00'ならば文字2つだよね?
2文字以上取得するならばその分配列をつくるべきです。
てゆーか、いらなくない??
すでにmainの最初でchar animal[20]が宣言されているんだから。
指摘4
再帰的プログラムとは、関数内で自分の関数を呼ぶことです。
また文字列の比較はstrcmpなどの関数を呼ぶしかないです。
間違っても、以下のような式にはなりません。 突っ込みどころが多すぎですね。。
精進してください。
mainの最初にlisthead = NULL;をしているので、
そのあとのlisthead.next = &ani1;で落ちることでしょう。
その前にコンパイルできないですけどね。
listhead = NULL;でなくlisthead = &ani1;ですな。
指摘2 C言語ではこんな代入の仕方はしません というようにしないとだめです。
指摘3 charだけだと文字一つしか入力できません。
00で終了と、'00'ならば文字2つだよね?
2文字以上取得するならばその分配列をつくるべきです。
てゆーか、いらなくない??
すでにmainの最初でchar animal[20]が宣言されているんだから。
while(strcmp(animal, "00") != 0) {
printf("動物名を英語で入力してください(00で終了)-->");
scanf("%s", animal);
//省略
再帰的プログラムとは、関数内で自分の関数を呼ぶことです。
また文字列の比較はstrcmpなどの関数を呼ぶしかないです。
間違っても、以下のような式にはなりません。 突っ込みどころが多すぎですね。。
精進してください。
Re: 文字列判定プログラム(再帰的)の課題です
とりあえず一度基礎から復習しなおす必要があると思います
if文の使い方
関数について(特にスコープというところ)
48行目から56行目までは滅茶苦茶です。
あとエラーの意味もわかるようになりましょう
例えばprog.cpp:48: error: ‘next’ was not declared in this scopeの意味はわかりますか?
if文の使い方
関数について(特にスコープというところ)
48行目から56行目までは滅茶苦茶です。
あとエラーの意味もわかるようになりましょう
例えばprog.cpp:48: error: ‘next’ was not declared in this scopeの意味はわかりますか?
Re: 文字列判定プログラム(再帰的)の課題です
私はこれで動くよとは一言も言ってません。you3749 さんが書きました:To:へにっくすさん
ご指摘ありがとうございます。
http://ideone.com/WQwGQ
ご指摘された箇所を直しましたが、まだ上手く動きません。
前とは違うエラーも発生しています・・・
さて指摘続きです。
指摘1: の後に と続いてますが、member関数の引数の型はchar*と、struct cell *ですよね?
*animal と書くと、char型を渡すことになってしまいます。*はいりません。
また上記の*nextはどっからきたの?
適当に書いたって、コンパイルするときに宣言してない変数を使うんじゃねーよ、と怒られるだけですよ。
nextを宣言してある変数に置き換えてください。(新しく宣言してはだめですよ)
指摘2:
if文の中の条件文に = (イコール一文字) はあり得ません。
等しい条件を表すにはどう書くんだっけ?
指摘3:
なんですかこれ。strcmp関数の意味分かってますか?
一致判定しているのは最初だけですね。
ちゃんとかっこの対応もとってください。
int member(char *animal,struct cell *next){
if(strcmp(ani1.animal,"rat") == 0){
return 1;
}else if(strcmp(ani2.animal,"cat"){
return 1;
}else if(strcmp(ani3.animal,"elephant"){
return 1;
}else if(strcmp(ani4.animal,"horse"){
return 1;
}else if(strcmp(ani5.animal,"bat"){
return 1;
}else if(strcmp(ani6.animal,"hamster"){
return 1;
}else{
return 0;
}
}
まずはコンパイルエラーをなくすことを目指しましょう。。
コンパイルエラーがなくなったら再掲示してください。
Re: 文字列判定プログラム(再帰的)の課題です
To:へにっくすさん
2度もご指摘ありがとうございます。書き直しました。
http://ideone.com/2hyI4
なんとかコンパイラは通すことが出来ましたが、要素以外のものも"~は存在します。"と表示されてしまいます。
例えば、birdと入力した時に「birdは存在しません」と表示されるようにしたいのですが、何が原因でこうなるのでしょうか?
もしよろしければ、もう1度指摘をお願いします。
2度もご指摘ありがとうございます。書き直しました。
http://ideone.com/2hyI4
なんとかコンパイラは通すことが出来ましたが、要素以外のものも"~は存在します。"と表示されてしまいます。
例えば、birdと入力した時に「birdは存在しません」と表示されるようにしたいのですが、何が原因でこうなるのでしょうか?
もしよろしければ、もう1度指摘をお願いします。
Re: 文字列判定プログラム(再帰的)の課題です
65行目から72行目にかけて
struct cell ani1;
のように7つの変数を生成していますが、これらの変数は初期化されていません。
つまり、
ani1.animal
ani2.animal
などにはゴミデータが入っていますので、そのゴミデータと"rat"や"cat"のようなデータとを比較しても無意味ですし、そもそも未初期化のゴミデータを参照するのは正しいCプログラムではありません。
member関数は何をやりたい関数なのでしょうか?渡されたリスト(struct cell *next)に、渡された文字列(char *animal)が含まれるかをチェックしたいのですよね?
だとしたら渡されたnext変数を使うようにしなければいけないでしょうね。
struct cell ani1;
のように7つの変数を生成していますが、これらの変数は初期化されていません。
つまり、
ani1.animal
ani2.animal
などにはゴミデータが入っていますので、そのゴミデータと"rat"や"cat"のようなデータとを比較しても無意味ですし、そもそも未初期化のゴミデータを参照するのは正しいCプログラムではありません。
member関数は何をやりたい関数なのでしょうか?渡されたリスト(struct cell *next)に、渡された文字列(char *animal)が含まれるかをチェックしたいのですよね?
だとしたら渡されたnext変数を使うようにしなければいけないでしょうね。
Re: 文字列判定プログラム(再帰的)の課題です
そして48行目から52行目までがおかしいですね。以下、その部分の抜粋です。
you3749さんは最初の投稿で
member関数の中身も、間違ってはいるものの、「第1引数の文字列が第2引数のリストの要素ならば1を」返そうという意図はしっかり伝わってきます。
しかし、先ほど抜粋したif文ではそれが真逆になっています。
すなわち、memberの戻り値が0ならば「存在します。」と表示し、1ならば「存在しません。」と表示しています。
if(member(animal,listhead)==0){
printf("%sは存在します。\n",animal);
}else if(member(animal,listhead)==1){
printf("%sは存在しません。\n",animal);
}
と書いてます。member関数は、「第1引数の文字列が第2引数のリストの要素ならば1を」返すと、ご自分で書いておりますし、you3749 さんが書きました: 条件(2)
memberのプロトタイプ宣言は
int member(char *,struct cell *);
第1引数:文字列
第2引数:リストへのポインタ
返り値:第1引数の文字列が第2引数のリストの要素ならば1を、そうでなければ0を返す。
member関数の中身も、間違ってはいるものの、「第1引数の文字列が第2引数のリストの要素ならば1を」返そうという意図はしっかり伝わってきます。
しかし、先ほど抜粋したif文ではそれが真逆になっています。
すなわち、memberの戻り値が0ならば「存在します。」と表示し、1ならば「存在しません。」と表示しています。
Re: 文字列判定プログラム(再帰的)の課題です
本題ではありませんが念のため少し補足を。
必要であればif文の中の条件文で代入演算子を使うことに問題はありません。
等しいかどうかを判定するために代入演算子を使うのが間違っているだけで、へにっくす さんが書きました: 指摘2:
if文の中の条件文に = (イコール一文字) はあり得ません。
等しい条件を表すにはどう書くんだっけ?
必要であればif文の中の条件文で代入演算子を使うことに問題はありません。
Re: 文字列判定プログラム(再帰的)の課題です
>int member(char *animal,struct cell *next)
関数の引数の名前と、構造体のメンバーの名前を同じにすると、頭がごちゃごちゃになってきっと間違えます。
再帰のプログラムになるのはまだ先でしょうね。
関数の引数の名前と、構造体のメンバーの名前を同じにすると、頭がごちゃごちゃになってきっと間違えます。
再帰のプログラムになるのはまだ先でしょうね。
non
Re: 文字列判定プログラム(再帰的)の課題です
beatle さんがレスしている通りです。you3749 さんが書きました:To:へにっくすさん
2度もご指摘ありがとうございます。書き直しました。
http://ideone.com/2hyI4
なんとかコンパイラは通すことが出来ましたが、要素以外のものも"~は存在します。"と表示されてしまいます。
例えば、birdと入力した時に「birdは存在しません」と表示されるようにしたいのですが、何が原因でこうなるのでしょうか?
もしよろしければ、もう1度指摘をお願いします。
listheadをせっかく渡してるのに、memberの中で渡されたnextを使っていないんだから当たり前。
member関数の中で宣言している変数は消して、引数であるnextに置き換えてみてください。
またmemberの返す値の意味が逆なのも beatle さんが指摘している通りですので、その修正もしてくださいね。
確かに問題ないんだけど、私は嫌いです。だってぱっと見、紛らわしいし。h2so5 さんが書きました:等しいかどうかを判定するために代入演算子を使うのが間違っているだけで、
必要であればif文の中の条件文で代入演算子を使うことに問題はありません。
私だったら代入文と条件文を一緒にしたりしません。
まあ好みの問題だな。
Re: 文字列判定プログラム(再帰的)の課題です
返信もせずにすいません。
beatleさん、h2so5さん、nonさん、アドバイスして下さりありがとうございました。
なんとか動かせるようになりました。
http://ideone.com/4gfXT
memberの比較対象と返す真偽が逆になっていたようです。
今まで長く付き合って下さり、ありがとうございました。
勝手ながら、これにて解決とさせて頂きます。
アドバイスして下さった皆様に感謝します。
beatleさん、h2so5さん、nonさん、アドバイスして下さりありがとうございました。
なんとか動かせるようになりました。
http://ideone.com/4gfXT
memberの比較対象と返す真偽が逆になっていたようです。
今まで長く付き合って下さり、ありがとうございました。
勝手ながら、これにて解決とさせて頂きます。
アドバイスして下さった皆様に感謝します。
Re: 文字列判定プログラム(再帰的)の課題です
まったく再帰関数にはなっていませんが、解決でよろしいのでしょうか。
Re: 文字列判定プログラム(再帰的)の課題です
私、最初の指摘4で、
まあエラーを取り除くのに腐心して、肝心の課題であることを忘れるのは初心者にありがちですが、これが仕事ならお叱りを食いますよ。
一応参考になるページを挙げときます
再帰関数
と言ってるのに、何も考慮していないですねえ。指摘4
再帰的プログラムとは、関数内で自分の関数を呼ぶことです。
まあエラーを取り除くのに腐心して、肝心の課題であることを忘れるのは初心者にありがちですが、これが仕事ならお叱りを食いますよ。
一応参考になるページを挙げときます
再帰関数