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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

4674閲覧

関数の戻り値が正しく代入されない

cherry_0515

総合スコア13

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/04/24 15:28

編集2019/04/24 16:02

###前提・実現したいこと

複数の単語を与えてその中で辞書順で一番若い単語を出力するプログラムを作っています。言語はC言語です。単語は一度に与えられて、単語と単語の間は空白か改行で区切られています。
単語の最初の文字の位置を探して大文字を小文字に変えることはできたのですが、単語を最も若い単語と比較する関数がうまく機能しません。
関数の戻り値は比較対象の二つの単語のうち、辞書順で前に来るものの位置文字目が格納されている配列の番号を返すように作りました。しかし、その値をminに代入するといつもminが一単語目の一文字目のASCⅡコードの値になってしまいます。この戻り値を正常に代入できればプログラムは完成です。どこが問題なのか見つけられましたら、教えていただきたいです。

ちなみに、minにはint型で定義した時に0を代入しています。ここに書いたプログラムの前のmain関数内には、
・getchar関数で一文字ずつC-dが打たれるまで文字を格納
・単語数を数えながら、単語の先頭の文字がいる配列の番号をx[i]に格納
・大文字なら小文字に
というプログラムを書きました。
strcmp関数を用いる方法をあとになって知りましたが、ここまで作ったのでこのまま完成させたいです。よろしくお願いいたします。

###発生している問題・エラーメッセージ
このように入力すると、このように出力されます。

cherry tmm C 1回目 youngに入れる前 min=0 return min-k(0) 1回目 youngに入れた後 min=99 2回目 youngに入れる前 min=99 return min-k(99) 2回目 youngに入れた後 min=99 3回目 youngに入れる前 min=99 return min-k(99) 3回目 youngに入れた後 min=99 ------------------------------ Alkkf ke kdjf ksl 1回目 youngに入れる前 min=0 return min-k(0) 1回目 youngに入れた後 min=97 2回目 youngに入れる前 min=97 return min-k(97) 2回目 youngに入れた後 min=97 3回目 youngに入れる前 min=97 return min-k(97) 3回目 youngに入れた後 min=97 4回目 youngに入れる前 min=97 return min-k(97) 4回目 youngに入れた後 min=97

###該当のソースコード

C

1#include<stdio.h> 2#include<string.h> 3 4int young(char *str,int x,int min,int k){ 5 /*x+1番目の文字とmin+1番目の文字を比較 若い方の位置を返す kは最初の文字からどれだけ離れたかの記憶*/ 6 if(str[x]>str[min]){ /*minの方が若い*/ 7 printf("return min-k(%d)\n",min-k); 8 return min-k; /*離れた分戻すためにkを引く*/ 9 } 10 if(str[x]==str[min]){ 11 if(str[min+1]<'A' || (str[min+1]>'Z' && str[min+1]<'a') || str[min+1]>'z'){ 12 /*minの方が単語が短いからreturn min-k*/ 13 printf("return min-k(%d)\n",min-k); 14 return min-k; 15 } 16 else if(str[x+1]<'A' || (str[x+1]>'Z' && str[x+1]<'a') || str[x+1]>'z'){ 17 /*xの方が単語が短いからreturn x-k*/ 18 printf("return x-k(%d)\n",x-k); 19 return x-k; 20 } 21 k++; /*次の文字へ行くから離れた分記憶*/ 22 young(str,x+1,min+1,k); /*次の文字を比較*/ 23 } 24 if(str[x]<str[min]){ /*xの方が若い*/ 25 printf("return x-k(%d)\n",x-k); 26 return x-k; 27 } 28} 29 30/*以上がyoung関数の中身です。*/ 31 32/*以下にyoung関数を用いる前後のプログラムを記します。 33その他の部分に問題がないことは確認済みです。*/ 34 35 for(i=0;i<count;i++){ 36 if(str[x[i]]<'A' || (str[x[i]]>'Z' && str[x[i]]<'a') || str[x[i]]>'z') continue; 37 printf("%d回目 youngに入れる前 min=%d\n",i+1,min); 38 min=young(str,x[i],min,0); /*x[i]+1文字目からの単語とそれまでで一番若い単語の比較*/ 39 printf("%d回目 youngに入れた後 min=%d\n\n",i+1,min); 40 } 41 42

試したこと

文字の読み込みや単語数を数える仕組みに問題がないか、printfを入れて確認しましたが、問題はありませんでした。また、関数の戻り値はおかしくないかを確認するために、return文の前にprintfを書いて正しい値が確認しました。その値は正しいものでした。
また、関数に入れる前からminがおかしくなっていないかprintfで確認しましたが、きちんと初期値の0でした。しかし、関数から代入した後のminには違う値が入ってしまいます。関数の戻り値の型もきちんとint型になっている事も確認しました。
いろいろな単語を入力してみて、minが一単語目の一文字目を小文字にした際のASCⅡコードの値になっていることには気づけました。

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2019/04/24 15:40

なぜ単語を抽出して昇順にソートして先頭を取り出さないのでしょう? 処理としてはそのほうが楽だと思いますが?
pepperleaf

2019/04/24 15:47

提示のコードの printf()と出力結果が一致しないように見えますが、、。
cherry_0515

2019/04/24 15:58

cateyeさん 勉強不足でソートするというアイデアが思いつきませんでした。そちらも考えてみます。 pepperleafさん 間違ったものをコピペしていました。直しました。ご指摘ありがとうございます。
guest

回答2

0

ベストアンサー

ロジックは追っていませんが、一か所非常に怪しい箇所があります。

C

int young(char *str,int x,int min,int k){
...
if(str[x]==str[min]){
...
young(str,x+1,min+1,k); /次の文字を比較/
}
...
}

内部で呼び出したyoung関数の返り値がその場で捨てられてしまっています。
返り値を呼び出し元に伝播させるために、returnしてやって下さい。

C

1 ... 2 return young(str,x+1,min+1,k); /*次の文字を比較*/ 3 } 4 ...

再帰を利用する上ではよくあるミスです。何か警告が出ているのでは無いでしょうか。


あと、細かいようですが、誰も指摘していないので。

  • : ASCⅡコード
  • : ASCIIコード (Wikipedia)

参考

階乗の計算を題材に実験してみます。

######期待通りに動いている例

C

1#include <stdio.h> 2 3int fractional(int n) { 4 if(n == 0) { 5 return 1; 6 } 7 8 return n * fractional(n-1); 9} 10 11int main(void) { 12 int num = 10; 13 printf("%d! = %d\n", num, fractional(num)); 14 15 return 0; 16}

標準出力 Wandbox

10! = 3628800

######期待通りに動かない例

C

1#include <stdio.h> 2 3int fractional(int n) { 4 if(n == 0) { 5 return 1; 6 } 7 8 //return n * fractional(n-1); 9 n * fractional(n-1); 10} 11 12int main(void) { 13 int num = 10; 14 printf("%d! = %d\n", num, fractional(num)); 15 16 return 0; 17}

標準出力/標準エラー出力 Wandbox

prog.c: In function 'fractional': prog.c:9:7: warning: value computed is not used [-Wunused-value] n * fractional(n-1); ~~^~~~~~~~~~~~~~~~~ prog.c:10:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ 10! = 1
  • -Wunused-value

値が使われていないけど、良いの?という警告です。

  • -Wreturn-type

返り値が無いけど、良いの?という警告です。

本当は返されていない返り値を無理矢理使っていることになり、未定義の動作を踏んでいます。

投稿2019/04/24 16:26

編集2019/04/25 04:07
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cherry_0515

2019/04/24 16:42

ありがとうございます‼エラーは何も出なかったので気づきませんでした…。 returnしないと計算結果を捨てていることになるとは全く気付かなかったです。今度から気を付けます。参考までありがとうございました。
jimbe

2019/04/25 01:34 編集

蛇足ながら >young(str,x+1,min+1,k); は young(str+1, x, min); と, str ポインタのほうを加算することで, x や min を加算する必要が無くなり, x や min が変化しなくなるので k を削除することが出来ます.
LouiS0616

2019/04/25 04:01

@cherry_0515 さん どのようなコンパイラをご利用でしょうか? @jimbe さん 有益なコメントありがとうございます。
guest

0

printf("min=%d\n",i,min);

上記のコード、あってますか?

投稿2019/04/24 15:49

sin_250

総合スコア112

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cherry_0515

2019/04/24 16:07

修正途中の間違ったプログラムを添付してしまいました。iが余分ですよね。ご指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問