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

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

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

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

Q&A

解決済

4回答

1139閲覧

5回、自然数を入力し、その中で最小値と最大値を除いた合計値を出力するプログラム

Shomo_

総合スコア16

C

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

0グッド

0クリップ

投稿2023/01/30 03:35

編集2023/01/30 10:20

C言語で「5回、自然数を入力し、その中で最小値と最大値を除いた合計値を出力するプログラム」を作成しています。

その際、

最小値かつ最大値に再度遭遇した場合は、再度遭遇した値の分は加算したい

と考えています。(当部分は投稿後に加筆しています)

下記に、現在のコードの出力結果と完成イメージを記します。

cmd

1【現在】 2str[0] = 1 3str[1] = 1 4str[2] = 3 5str[3] = 5 6str[4] = 5 715 8 9【完成イメージ】 10str[0] = 1 11str[1] = 1 12str[2] = 3 13str[3] = 5 14str[4] = 5 159

【現在】の結果は、下記【ソースコード】の実行結果です。
なのでエラーメッセージは出ていないです。

C

1【ソースコード】 2#include <stdio.h> 3#define YOUSO 5 4int main(void) 5{ 6 int str[YOUSO],min,max; 7 int total = 0; 8 int minFlag = 0; 9 int maxFlag = 0; 10 11 for(int i=0; i<YOUSO; i++) 12 { 13 printf("str[%d] = ",i); 14 scanf("%d",&str[i]); 15 //ずっと「scanf("%d",str);」だと思ってた。確かにscanfはアドレスを欲しがっているのだが、これだとstrの先頭だけ値を入力していることになる。 16 //なので0番目を抜いた1,2,3,4番目にゴミが入る。 17 } 18 19 min = str[0]; 20 max = str[0]; 21 22 for(int i=1; i<YOUSO; i++) 23 { 24 if(str[i] < min) 25 { 26 min = str[i]; 27 } 28 else if(str[i] > max) 29 { 30 max = str[i]; 31 } 32 } 33 34//1,1,3,5,5 35//min 1 max 5 36 for(int i=0; i<YOUSO; i++) 37 { 38 if(str[i] == min && minFlag == 0) //最小の値と初めて遭遇したら 39 { 40 minFlag = 1; 41 } 42 else if(str[i] == max && maxFlag == 0) //最大の値と初めて遭遇したら 43 { 44 maxFlag = 1; 45 } 46 47 48 if(str[i] == min && minFlag == 1) //最小の値と再度遭遇したら 49 { 50 total += str[i]; //足し込む 51 } 52 else if(str[i] == max && maxFlag == 1) //最大の値と再度遭遇したら 53 { 54 total += str[i]; //足し込む 55 } 56 57 58 if(str[i] != min && str[i] != max) //最小、かつ、最大の値と遭遇しなかったら 59 { 60 total += str[i]; //足し込む 61 } 62 } 63 printf("%d",total); 64}

【補足情報】
なし

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

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

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

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

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

fana

2023/01/30 03:52

後半の実装部分でフラグがどうのとかごちゃごちゃやってるけど, 単純に全部足したものからminとmaxを引けば良いという話ではないのでしょうか?
ardin

2023/01/30 03:56 編集

まず、問題文をそのまま解釈するとして、イメージに意見するのもなんだけれども、完成イメージの答えが違いませんか? 答えは3ではないですか?
Shomo_

2023/01/30 04:05

fana様 !!確かに。その方法で解決しますね。。
Shomo_

2023/01/30 04:10 編集

ardin様 すみません。私の説明が不足しておりました。 目的は「最小値と最大値を除く合計値の出力」ですが、 「最小値かつ最大値に再度遭遇した場合は、再度遭遇した値の分は加算したい」 という説明が抜けておりました。誤解を招きすみません。
guest

回答4

0

異なる結果が出てしまっています

という話に関しての応答とはなりませんが,
「物事をシンプルにすればそれだけミスも起きにくい」のではないか? という気がします.

(配列要素に対する scanf についての混乱があったような話が質問文内に見受けられますが)本件に配列は不要でしょうし,
結果の計算方法も既に述べられているように「全部足したものから最小と最大を引く」で良いでしょう.

C

1//入力作業関数.入力された値を返す 2int Input( int DispIndex ) //引数はprintfでの表示に使うだけ 3{ 4 int v; 5 printf( "str[%d] = ", DispIndex ); 6 scanf( "%d", &v ); 7 return v; 8} 9 10int main( void ) 11{ 12 int Sum,Min,Max; 13 Sum = Min = Max = Input( 0 ); 14 for( int i=1; i<5; ++i ) 15 { 16 int v = Input( i ); 17 Sum += v; //とにかく総和を取る 18 if( v < Min ){ Min = v; } 19 if( v > Max ){ Max = v; } 20 } 21 printf( "%d\n", Sum-Min-Max ); //最後にこの値を表示すれば良い 22 return 0; 23}

[追記]
上記と異なる方針:

  • 入力値を一旦配列に全部格納してから処理する
  • 「足すべきものだけを足す」という方向で集計処理を行う

という場合,
最小値/最大値 そのものではなくて「配列の何番目の要素が 最小/最大 なのか」という情報を扱うようにすると,最後の集計処理の話が簡単になるかもしれません.

C

1int main( void ) 2{ 3 //※str[]への入力部分は本質でないので省略 4 int str[5] = { 1,1,3,5,5 }; 5 6 //iMin, iMax は 最小/最大 な要素のindex. 7 //すなわち,最小値は str[iMin], 最大値は str[iMax] 8 int iMin=0, iMax=0; 9 for( int i=1; i<5; ++i ) 10 { 11 if( str[i] < str[iMin] ){ iMin = i; } 12 if( str[i] > str[iMax] ){ iMax = i; } 13 } 14 15 //集計:ここがこんな感じで楽になる 16 int Sum = 0; 17 for( int i=0; i<5; ++i ) 18 {//最小でも最大でもない要素の値だけを足していく 19 if( i!=iMin && i!=iMax ){ Sum += str[i]; } 20 } 21 printf( "%d\n", Sum ); 22 return 0; 23}

投稿2023/01/30 04:23

編集2023/01/30 06:09
fana

総合スコア11658

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

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

fana

2023/01/30 04:30

入力のための処理がmain内にごちゃごちゃ入ると処理フローが見難いと思うので,関数にしています. イレギュラーな入力(scanfの戻り値が変だとか,入力が「自然数」じゃない場合とか)への対処とかが必要ならば,さらにごちゃごちゃするでしょうし.
Shomo_

2023/01/30 04:52 編集

fana様 仰る通り、入力や加算処理がごちゃごちゃしていました。 個人でやっていたので実行して期待する結果になれば。と考えていましたが、その前にここは公共の場であり、私の回答者の方への配慮がなかったなと感じました。第一、コードを振り返った時など自分のためにもならないですね。 <<イレギュラーな入力 コードを拡張するとなると必要ですね。そのためにも関数等で分ける必要性を理解しました。 コメント、コード例含めありがとうございます。
fana

2023/01/30 04:59

もちろん他者への配慮も必要でしょうが,今回の場合は「他者が見難い」というよりは「自分のため」の側かな,と. 「こういう入力値が与えられた場合にどういう処理をすればよいか…」っていうのを試行錯誤なりする際には,入力処理の具体的な実装というのはどうでもよい事柄なわけなので,そういうのは試行錯誤対処の外側に追い出しておくと,自身のコードを読むにも書き換えるにもちょっとは楽なんじゃないかな的な.
Shomo_

2023/01/30 05:25

fana様 「配列と条件分岐、どちらも使い慣れていないのにどちらも使おうとして余計に悩んでいる」 という感じはあります。 分からなくなったときのために、理解するための工夫を心掛けようと思いました。 そうすれば、fana様が仰っていた「全部足してから引けばいい」という、単純明快なアプローチに気づくことも比較的しやすくなるのかなと思いました。いろいろありがとうございました。
fana

2023/01/30 06:14

元々のアプローチ(配列使用 + 足すべき値だけを足していく)に即した話も一応追記.
Shomo_

2023/01/30 07:37

fana様 追記のプログラムを拝見し終えました。 驚きの連続です。 配列例として{1,1,3,5,5}として集計作業をする際、 現在見ている要素の値が「最小値なのか、最大値なのか」という基準だけで見てしまうと 最小値、最大値それぞれと同じ値と遭遇した場合の加算処理がやっかいになりますが、 最小値、最大値それぞれの添え字を持っておくことで その添え字に遭遇しないように加算処理できるんですね。。 本当に参考にさせていただいています。ありがとうございます。
guest

0

ベストアンサー

最小値最大値が2回ずつ含まれている場合、最後のループ内で minFlag maxFlag0 から 1に変更した際に続けて minFlag == 1 maxFlag == 1 の条件にひっかかってしまいます。ループ中の3個目の ifelse if にするとうまくいきそうです。
こういう問題はデバッガでステップ実行すればすぐに気付くので、デバッガの使い方を覚えましょう。

しかし、このアプローチだと全項目が同じ値だと間違った結果になりますね。

無条件にすべて足して後から最小値と最大値を引くと、よりシンプルなコードになるでしょう。

投稿2023/01/30 03:51

編集2023/01/30 04:01
int32_t

総合スコア20880

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

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

Shomo_

2023/01/30 04:00

回答の他、考え方まで教えていただきありがとうございました。 最初のifを除くifをelse ifに変更したら期待する結果が出ました。 まだ考え方に理解が及んでいないので、ご指摘いただきましたデバッグで変数の状態を追ってみます。。
Shomo_

2023/02/11 17:16

今更ですが、投稿したコードでデバッグした際の挙動を把握しました。 エラーで動かないならまだしも、動くのならデバッグしないのはもったいないと感じました。
guest

0

配列を使わなければならない、という条件が無いのであれば、私なら次のように実装します。 ご参考までに。

C

1#include <stdio.h> 2 3#define YOUSO 5 4 5int main( void ) { 6 int total = 0; 7 int min, max; 8 int i; 9 int n; 10 11 for ( i = 0; i < YOUSO; i += 1 ) { 12 printf( "enter number %d = ", i ); 13 scanf( "%d", &n ); 14 if ( i == 0 ) { 15 min = n; 16 max = n; 17 } 18 else { 19 if ( min > n ) min = n; 20 if ( max < n ) max = n; 21 } 22 total += n; 23 } 24 total = total - min - max; 25 printf("%d",total); 26 27 return 0; 28} 29

投稿2023/02/07 07:46

kurai

総合スコア85

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

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

kurai

2023/02/07 07:47

と思ったら、すでに BA の int32_t さんがそう仰っていました(汗)。 蛇足でした……。
Shomo_

2023/02/08 05:36

kurai様 ありがとうございます。合計から最小最大を引く件かと存じますが蛇足なんてとんでもないです。 kurai様のコード、そして皆様のコードもそうですが、とてもコンパクトにまとまっているなと感じました。 例えばforの個数であったり、配列を使うなら並び替えによる最小値、最大値の位置に配慮せずに済んだりなどです。実は今、皆様からいただきましたアドバイスをもとに「5個の自然数を入力し、その中の最小値と最大値を出力する」というのを関数とポインタを使って作成している途中でして、アドバイスをもとに作成しているので当たり前ですがすごく助かっています。
kurai

2023/02/08 14:30

そう言っていただけると救われます、ありがとうございます。 関数とポインターは C の要諦とも言えるところです。 図を描くのは私もオススメします!
guest

0

並び替えるのが真っ当かもしれません。

c

1#include <stdio.h> 2#include <stdlib.h> 3#define N 5 4int icmp(int *a, int *b) { return *a - *b; } 5int main(void) { 6 int v[N]; 7 for(int i=0; i<N; i++) { 8 printf("str[%d] = ", i); 9 scanf("%d", &v[i]); 10 } 11 qsort(v, N, sizeof(v[0]), icmp); 12 int total = 0; 13 for(int i=1; i<N-1; i++) { 14 total += v[i]; 15 } 16 printf("%d\n", total); 17}

投稿2023/01/30 18:48

編集2023/01/30 18:48
jimbe

総合スコア12646

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

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

Shomo_

2023/01/31 03:48 編集

jimbe様 qsortもすごい機能ですが、私は2個目のforの使い方もすごいなと思いました。 <肝?> ①配列内要素を昇順にする ②forで最初と最後の要素にアクセスさせずに加算する 下記を参考にしつつ、ご提示いただきましたソースを編集・実行すると 【完成イメージ】と同じ結果が出ました。 https://monozukuri-c.com/langc-funclist-qsort/ 質問一つからここまで学びの機会が生まれると、正直思っていませんでした。 ありがとうございます。とても励みになります。
jimbe

2023/01/31 14:48 編集

for は 0~n ループに使われるのが大抵ですが、 その本質は for(①;②;③) ④; の時、 ①→②→④→③→②→④→③→… と②が偽になるまで処理を続けることであり、どう使うかはプログラマ次第です。 バブルソートの二重ループ等も面白く感じるかもしれませんね。 Javaでバブルソートのプログラムを作成する方法【初心者向け】 https://magazine.techacademy.jp/magazine/19444
Shomo_

2023/02/03 03:49 編集

jimbe様 webでバブルソートのソースを見て「なんでforが2つ必要なんだろう」と思い、 1時間ほどステップ実行やタッチパネルで変数の動きを逐一描いたりしてました。 それで気付いたのですが、プログラミングってコーディングに取り掛かる前に 図などを書いて整理すると何が必要か把握しやすくなるんですね。 人それぞれかもですが「とりあえずコード書きつつ~」の方針でやっていた自分からすると イメージできてから挑むのが楽で時短になるなと思いました。
jimbe

2023/02/02 16:53 編集

>図などを書いて整理 以前も同様に仰る方が居られました。 今は紙に書いていても慣れてくれば頭の中で書けるようになります。 様々なプログラムをコードと共にイメージとして経験していけばそれだけ引き出しが多くなりますので、是非続ける事をお勧めします。
Shomo_

2023/02/03 03:51 編集

jimbe様 アドバイスいただきありがとうございます。 最近、本当に少しずつですが考えるより先に無意識にコード化している時があります。(特にfor、if等の条件式) 今回、それも大きく見れば引き出しが作れているのかもと感じました。 これからもっとひたむきに向き合おうと思います。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問