🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

1368閲覧

どこが間違っているのでしょうか?またもっと美しい書き方がありますか?

pastelkona

総合スコア31

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/10/29 09:52

編集2019/10/31 01:45

##問題

問.(C++プログラミング)ファイルの内容を(リダイレクトで)読んで、各要素に1を足した値を出力するC++プログラムを作成せよ。

例)

入力 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 16 -1   
出力 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 17 -1

入力ファイルの形式

テキストファイル形式(ASCII)で記述し、要素の区切りは空白文字とする。空白文字は、C++のiostreamの標準ではスペース・改行・タブである。   
要素値は整数とする。

要素値が0または正の値である場合、通常のデータとして処理する。    
要素値が-1の場合はファイルの最後として扱い、-1を出力して、プログラムを終了する    
要素値が-1以外の負の値である場合は、エラーメッセージをcerrに出力し、プログラムを終了する。


問題をコピペするのは良くないのであれば、ここより上の部分は消します。

問題元(http://www.ced.is.utsunomiya-u.ac.jp/lecture/2014/prog/p3/kadai2/page1.php)

#include <iostream> using namespace std; int main() { int i, array[17]; cin >> array[0] >> array[1] >> array[2] >> array[3] >> array[4] >> array[5] >> array[6] >> array[7] >> array[8] >> array[9] >> array[10] >> array[11] >> array[12] >> array[13] >> array[14] >> array[15] >> array[16] >> array[17]; for (i=0; i<18; i++) { if(array[i] > 0) { array[i] = array[i] + 1; } else if(array[i] == -1) { array[i] = -1; break; } else { cerr << "Error: input is " << array[i] << endl; break; } } cout << array[0] << " " << array[1] << " " << array[2] << " " << array[3] << " " << array[4] << " " << array[5] << " " << array[6] << " " << array[7] << " " << array[8] << " " << array[9] << " " << array[10] << " " << array[11] << " " << array[12] << " " << array[13] << " " << array[14] << " " << array[15] << " " << array[16] << " " << array[17]; return 0; }

input:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 16 -1
return:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 17 17

どこが間違っているのでしょうか?またもっと美しい書き方がありますか?

--追記--

僕がわからないこと(問題としていること)は2つあります。
まずひとつ目は、
上のプログラムが、-1とreturnしなければならないところを17とreturnしたこと。
2つ目は、 cin << array[0] ...
と長くなっていたりすること。つまりきれいではないこと。1つ目の問題が解決したとして、もっときれいな書き方があるのか?という質問です。

二番目については、すでに回答をもらっており、現在、どこがどういう動きをしているのか理解(解読)しているところです。

皆さん回答していただきありがとうございます。皆さんの人生の貴重な、限りのある、お時間をもらって大変ありがたく思います。

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

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

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

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

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

cateye

2019/10/29 10:00

・配列にする必要がありますか? “0または正の値である場合”→if(array[i] > 0) この判定で良いのですか?
pastelkona

2019/10/29 10:05 編集

配列にする必要はありません。はじめに次のを書きました。(これはうまくいく) しかしなっがったるいので、短くできないか考えた結果、今回の問題に直面しました。 ``` int main() { int a, b, c, d, e, f, g, h; int i, j, k, l, m, n, o, p, q, r; cin >> a >> b >> c >> d >> e >> f >> g >> h >> i >> j >> k >> l >> m >> n >> o >> p >> q >> r; cout << a+1 << " " << b+1 << " " << c+1 << " " << d+1 << " " << e+1 << " " << f+1 << " " << g+1 << " " << h+1 << " " << i+1 << " " << j+1 << " " << k+1 << " " << l+1 << " " << m+1 << " " << n+1 << " " << o+1 << " " << p+1 << " " << q+1 << " " << -1; return 0; } ```
Y.H.

2019/10/30 02:00

「今回の問題」とは何ですか? 問題と思ってられることを具体的に質問に追記ください。
pastelkona

2019/10/30 02:22

今回の問題とは、return の最後が-1ではなく17が出力されたこと。そして、 #include <iostream> using namespace std; int main() { int i, array[17]; cin >> array[0] >> array[1] >> array[2] >> array[3] >> array[4] >> array[5] >> array[6] >> array[7] >> array[8] >> array[9] >> array[10] >> array[11] >> array[12] >> array[13] >> array[14] >> array[15] >> array[16] >> array[17]; for (i=0; i<18; i++) { if(array[i] > 0) { array[i] = array[i] + 1; } else if(array[i] == -1) { array[i] = -1; break; } else { cerr << "Error: input is " << array[i] << endl; break; } } cout << array[0] << " " << array[1] << " " << array[2] << " " << array[3] << " " << array[4] << " " << array[5] << " " << array[6] << " " << array[7] << " " << array[8] << " " << array[9] << " " << array[10] << " " << array[11] << " " << array[12] << " " << array[13] << " " << array[14] << " " << array[15] << " " << array[16] << " " << array[17]; return 0; } このプログラム(プログラムなんて言えるものではないが。)がうまく動作しない。という問題です。
kazuma-s

2019/10/30 03:43

int i, array[18]; にしていないから、何が起こっても文句は言えません。
pastelkona

2019/10/30 03:57

インデックスは、0から始まるから、1~17、0~16と思ってint array[16]にしたんですけど。僕のC++の配列についての知識なかったせいでこんな事になりました。すみません。
pastelkona

2019/10/30 04:00

int i, array[18]; にしてみたらうまく動作しました。
guest

回答5

0

ベストアンサー

とりあえず「やってはいけないこと」をやっているのを最初に指摘します。

C++

1 int i, array[17]; 2 cin >> array[0] >> /* 略 */ >> array[17];

C/C++では、配列は要素N個を確保し、0~N-1のN個の番号(添字,インデックス)でアクセスします。array[17]は18番目の要素という意味なので、確保したエリアの外。これにアクセスしてはいけません。
そういう無茶をしたので、プログラムが正常に動作しなくなったのではないかと思います。

さて。
美しさを求める前に、自分が何をしているかを知る必要はあるでしょう。
質問というか問題文かな、

要素の区切りは空白文字とする。空白文字は、C++のiostreamの標準ではスペース・改行・タブである。

と書いてあります。これは、cinによるストリーム入力において、スペースも改行も(水平)タブも、ただの区切り文字としてだけ扱われ、区別されないということです。なので、そこに「一行」という概念はありません。区切られたデータが並んでいる、それだけです。データ構造を勘違いし、「一行」に囚われて
cin >> array[0] >> array[1] >> //以下略
と並べたことが「醜さ」の始まり。
(ただし、リダイレクトではなくキーボードからの入力の場合には、OS側の都合として「改行」が言語側への入力のトリガになるという事情はあります。これは言語側の知ったことではないのですが)

cinによる入力は、入力から区切り文字までを取得して変数に格納します。(期待しない文字が来たときの話は置いといて...)
なので、例えば

C++

1int a,b,c; 2cin >> a; 3cin >> b; 4cin >> c;

に対して与えた入力が

Text

11 2 3

でも

Text

11<Tab>2<Tab>3 (Tabは水平タブ一文字)

でも、あるいは

Text

11 22 33

でも、いずれもaに1が、bに2が、cに3が入力されます。

そういうことで、今回のお題は配列を使う必要などまったくなく、一つのデータを拾ってきて、その値を調べて適宜処理してやり、終了でなければ次のデータを拾ってきて...というのを繰り返してやればいい、ということ。
それをプログラムにするなら、cateyeさんのプログラムということになるでしょう。

追記
あと、現実にはずらずら並べたプログラムを書かなきゃいけないこともあるけど、そういうときにはC/C++のソースは「フリーフォーマット」なので、見やすいように改行やら空白やらタブやら入れましょう。

C++

1 cin >> array[0] >> array[1] >> array[2] >> array[3] >> 2 array[4] >> array[5] >> array[6] >> array[7] >> 3 array[8] >> array[9] >> array[10] >> array[11] >> 4 array[12] >> array[13] >> array[14] >> array[15] >> 5 array[16] >> array[17];

とするだけでも少しマシ、と私は思います。( 切れ目の>>を行末に持ってくる派と行頭に持ってくる派が論争を始めることもありますけど...)

投稿2019/10/29 13:35

編集2019/10/29 13:49
thkana

総合スコア7703

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

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

pastelkona

2019/10/30 01:46 編集

1 2 3このように入力するためには、cin << a << b << c としなければならないと思っていました。そこが間違っていいたのですね。一行で、入力を与えているように見えて、空白を挟むごとに、「入力を取り込んで、計算して、出力する。」を繰り返しているのですね。pythonをかじった程度しか知識がないもので。 >これは、cinによるストリーム入力において、スペースも改行も(水平)タブも、ただの区切り文字としてだけ扱われ、区別されないということです。なので、そこに「一行」という概念はありません。区切られたデータが並んでいる、それだけです。 全く知りませんでした。正しくデータ構造を理解していなかった、僕のミスですね。
pastelkona

2019/10/30 03:58

C/C++では、配列は要素N個を確保し、0~N-1のN個の番号(添字,インデックス)でアクセスします。 このような基本的なことを知らなかったからうまく行かなかったのですね。すみません。
thkana

2019/10/30 03:59

1つ目の問題についても回答しています。 > そういう無茶をしたので、プログラムが正常に動作しなくなったのではないかと思います。 動作中のプログラムに対してメチャクチャなアクセスを行ったのですから、どんな異常動作が起こっても不思議ではありません。私の手元では同様の状況は再現しませんでした。OS等のシステム、コンパイラ、コンパイルオブション等全て同じ環境にすれば再現するかも知れませんが、あまり意味のあることではありません。間違ったプログラムによる異常動作ですから。
pastelkona

2019/10/30 04:51

c++ではあまりエラーが出ないんですね。 一見うまくコンパイルできるからどこがおかしいのかわかりませんでした。 スクリプト言語とは違うということを忘れてはいけませんね。
thkana

2019/10/30 12:14

コンパイルでエラーが出るのは、与えたコードが言語として成立していないということなので論外ですが、コンパイル出来ただけでは、試験で言えば解答欄を埋めただけ、と思ってください。 特に、C/C++はプログラマの邪魔をしない、という思想のもと、怪しいコードもエラーにしません。イロイロなことが起こります...
pastelkona

2019/10/31 01:17

なるほどpythonではすぐにエラーが出るので(僕のせいだが)どこがまずかったのかだいたい分かるのですが、すぐにエラーが出るのはある意味、初心者に優しい仕様なんですね。 >特に、C/C++はプログラマの邪魔をしない、という思想のもと、怪しいコードもエラーにしません。 なるほど、そういう思想がC++にはあったのですね。エラーが出れば、自分で調べられますが、エラーが出ないとなると、経験が重要ですね。 >イロイロなことが起こります... 気をつけます。
pastelkona

2019/10/31 01:29

thkanaさん 僕がろくに入門書を読まなかったせいで、初歩的なことを回答しなければならなかったことをお詫びします。 cinの一行のことは、今回の質問で一番大きな学びでした。 ストレームという概念を僕はまだ理解していないようです。 僕の知識不足に、あなたの人生の貴重な限りあるお時間を使っていただきありがとうございました。
guest

0

文字列のままでやるとすれば、

C++

1#include <iostream> 2#include <string> 3using namespace std; 4 5int main() 6{ 7 string s; 8 while (cin >> s) { 9 if (s[0] == '-') { 10 (s == "-1") ? (cout << "-1\n") : (cerr << "error\n"); 11 break; 12 } 13 bool c = true; 14 for (int i = s.size(); --i >= 0 && c; ) 15 (s[i] < '9') ? (c = false, s[i]++) : (s[i] = '0'); 16 if (c) cout << '1'; 17 cout << s << ' '; 18 } 19}

3項演算子を多用しているので低評価で構いません。

投稿2019/10/30 03:44

編集2019/10/30 04:14
kazuma-s

総合スコア8224

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

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

pastelkona

2019/10/30 04:01

ちょっと三項演算子について学んで来ます。
pastelkona

2019/10/31 01:47

回答していただきありがとうございます。 まだまだ僕には学ぶべきことがエベレスト盛りのようです。 :-) 僕の知識不足に、あなたの人生の貴重な限りあるお時間を使っていただきありがとうございました。
guest

0

問題をよく読んでください。**整数の大きさが書いていません。**つまり、18446744073709551615といったUINT64_MAXを越えてくるような場合もあり得ると言うことです。世にあるほとんどの実装ではintlong longはこのように大きな整数は扱えません。

ではどうしたら良いのかということを考えなければなりません。もしboostを使用しても良いと書いてあれば、boostの多倍長整数を使うのもありです。ですが、問題文にはboostやその他の多倍長整数ライブラリについて言及がありません。きっと使ってはいけないと考えられます。自分で多倍長整数を実装する方法もありますが、めんどくさい結構大変です。よって今回は文字列を数値にせずに、文字をそのまま処理する方法がいいと思われます。

質問のコードからは全体的に書き直す必要があるので、全部最初から書きました。整数以外が入力されたときはおかしくなりますが、来ない前提で書いています。文字列の長さは実装依存みたいですが、試した環境では18446744073709551599文字まではできるようなので、その前にメモリがつきます。

C++

1#include <iostream> 2#include <string> 3#include <algorithm> 4 5int incr() 6{ 7 std::string str; 8 std::cin >> str; 9 if (std::cin.eof() || std::cin.fail()) return 2; 10 if (str[0] == '-') { 11 if (str[1] == '1' && str.size() == 2) { 12 std::cout << "-1" << std::endl; 13 return 0; 14 } else { 15 std::cerr << u8"エラーメッセージ" << std::endl; 16 return 1; 17 } 18 } 19 bool carry_over = true; 20 std::for_each(str.rbegin(), str.rend(), [&carry_over](auto &c){ 21 if (carry_over) c++; 22 carry_over = c > '9'; 23 if (carry_over) c = '0'; 24 }); 25 if (carry_over) std::cout << '1'; 26 std::cout << str << ' '; 27 return incr(); 28} 29 30int main() 31{ 32 return incr(); 33}

ネタだとわかる人だけ低評価をお願いします。解説が欲しい場合は「解説希望」とコメントに書いてください。気が向いたら書きます。

投稿2019/10/29 12:49

編集2019/10/29 12:53
raccy

総合スコア21737

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

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

fana

2019/10/30 02:17

標準入力から1文字ずつ取得してテンポラリファイルに出力しておき,後からそれを逆順に読込む形で処理すれば長さの限界を突破できますか?
pastelkona

2019/10/30 06:59 編集

変数「c」が何を表しているのかよくわからないのですが、教えてもらえませんか?
raccy

2019/10/30 09:20

> fanaさん その方法ならメモリの限界は突破できますね。ただ、ファイルシステムにもファイルサイズの制限があるので、現実世界では無限にはできないです。ですが、インプットファイルもファイルシステムに存在する以上、テンポラリファイル分は別のファイルシステムになっているとか出ない限り、大丈夫でしょう。あとは容量に空きがあるか確認することぐらいですね。 >pastelkonaさん cはstrの要素への左辺値参照(char型)です。
pastelkona

2019/10/31 01:36

bool carry_over = true; から return incr(); までが何をしているのか、なんとかわかったときは、驚きました、carry_overを関数の外で宣言して、参照することによって、加算することができたらfalseで終わるようにして、はじめのif (carry_over) c++を実行させないようにしているということに気がついたときは、本当に凄いなと思いました。 最後に、僕の知識不足に、あなたの人生の貴重な限りあるお時間を使っていただきありがとうございました。
guest

0

text

1usr ~/Project/test % ./a.out 21 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 16 -1 32 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 17 4usr ~/Project/test % ./a.out 51 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -16 -1 62 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 7Error: input is -16 8usr ~/Project/test % ./a.out 90 1 2 3 -1 101 2 3 4

cpp

1#include <iostream> 2 3using namespace std; 4 5int main() 6{ 7 int num = 0; 8 while(num != -1) { 9 cin >> num; 10 if (0 <= num) { 11 cout << num + 1 << ' '; 12 } else if (num != -1) { 13 cerr << endl << "Error: input is " << num; 14 break; 15 } 16 } 17 cout << endl; 18 // 19 return 0; 20}

投稿2019/10/29 10:31

編集2019/10/29 11:08
cateye

総合スコア6851

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

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

cateye

2019/10/29 10:43 編集

通常のwhile文でも可能 ちょこっと手直しd^^
pastelkona

2019/10/29 10:45

わかった! while (i < x)でxを変数にして、python3のlen()関数みたいなのを使うのですね!
pastelkona

2019/10/29 10:47

ちょっと試してみます。
cateye

2019/10/29 10:49

いや、int num = 0;としているので、"do{"の代わりに"while (num != -1){"でも良いということです。
pastelkona

2019/10/29 10:53

しかし、while文は、条件式がtrueである限り、ループし続きるものですよね?、でも「-1」が来たら、breakされるようにしたつもりなのですが、うまくいってないのでしょうか?
pastelkona

2019/10/29 10:57

doというものは知りませんでした。ごめんなさい。 なるほどwhile(num != -1)とするのですね!
cateye

2019/10/29 11:03

ソースを差し替えました
cateye

2019/10/29 12:08

もっとうまい書き方がありそうですが・・・、現状ですv^^;
pastelkona

2019/10/29 12:09

これは、例えば、「1 2 3 4」と与えた場合、四回whileが回っているということですか? 空白を挟むごとに、whileが回っている? 一行そのまま取り込んで一行そのまま、出力しているわけではないということですか?
cateye

2019/10/29 13:55

〉四回whileが回っているということですか?・・・そうです
fana

2019/10/30 02:08

(-1を出力する部分が抜けている)
cateye

2019/10/31 01:37

^^;
pastelkona

2019/10/31 01:42

do whileというのは最後に、条件式を確認するものなんですね。 一番初めに回答してくれて、whileを空白ごとに、回していけばよいということを教えてくれてありががとうございます。空白、改行、タブが…と問題に書いてあったことはこういうことだったのですね。 空白のことを僕はうまくわかっていなかったんですね。 僕の知識不足に、あなたの人生の貴重な限りあるお時間を使っていただきありがとうございました。
guest

0

問題をみた限り、どこにも要素数が17とは書いてありません。

コードはどうやら変数は17で固定となっているようですので、要素数を可変としないとクリアできないと思いますがどうでしょうか?


やり方がわからない、的を得ていない回答だった場合、お手数ですがコメント頂ければ対応致します。

投稿2019/10/29 10:14

KanazawaKureha

総合スコア368

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

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

pastelkona

2019/10/29 10:19

僕には今の所、アイディアが思いつかないのですが、あなたはなにかアイディアをお持ちですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問