• ベストアンサー

空白を含む文をファイルに書き込んで10文字ずつ読み出す

空白を含む文を10文字ずつ読み出そうとしています。でも 文1:I am a poor programmer. 文2:2nd Sentence 結果:2nd Sentenr programmer. となります。"I am a poo"が欲しいのですが。 800文字以内にするためにmainだけにしました。後で補足できます。 int main() { sentence sntc; fstream file; file.open("SENTENCE.TXT", ios::app | ios::out | ios::in | ios::binary ); sntc.getData(); file.write( reinterpret_cast<char*>(&sntc), sizeof(sntc) ); file.seekg(0, ios::end); int endposition = file.tellg(); int n = endposition / sizeof(sentence); cout << "\nThere are " << n << " sentences in file"; cout << "\nEnter sentence number: "; cin >> n; int position = (n-1) * sizeof(sentence); file.seekg(position); file.read( reinterpret_cast<char*>(&sntc), sizeof(sntc) ); sntc.showData(); cout << endl; file.seekg(position, ios::cur); file.read( reinterpret_cast<char*>(&sntc), 10); sntc.showData(); cout << endl; return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.3

ひさしぶりにストラウストラップ本を見返してみました。 やはり、readでは\0が付加されないようです。 (『プログラミング言語C++第3版』§21.3.4) seekgの前でちゃんと表示されたのは、ファイルからではなく、 getData()によって入力されたからでしょう。 この場合、自動的にヌルが付加されます。 ファイル読み込みに、read()ではなく、 getline()を使うと良いと思います。 ただ、やっぱりこのキャストはおかしい。 こうやって入力すると、たまたまsentence内のstrに データが入るかもしれませんが、 オブジェクトの使い方としてはいただけません。 代案として、 (1)strをpublicにして、 file.getline(sntc.str, 11); のようにする。 (2)バッファを使い、sentenceにsetStr, getStrメソッドを付加して、 char buf[80]; file.getline(buf, 11); sntc.setStr(buf); のようにする。 これ以上はわからないので、 C++に詳しい人の登場を待ちます。

ginkgo
質問者

お礼

解決しました! 一つ目の問題は私の「テストで表示」がいけなかったみたいです。 あの行のお陰で「本番の表示」のときには既に駒が一つ進んでました。 二つ目の問題はどうも // file.seekg(position, ios::cur); の行が邪魔をしていたようです。 下の通りに修正しました。 int main() { sentence sntc; fstream file; file.open("SENTENCE.TXT", ios::app | ios::out | ios::in | ios::binary ); sntc.getData(); file.write( reinterpret_cast<char*>(&sntc), sizeof(sntc) ); file.seekg(0, ios::end); int endposition = file.tellg(); int n = endposition / sizeof(sentence); cout << "\nThere are " << n << " sentences in file"; cout << "\nEnter sentence number: "; cin >> n; int position = (n-1) * sizeof(sentence); file.seekg(position); for(int i=0; i<5; i++) { position = file.tellg(); cout << position; // file.seekg(position, ios::cur); file.read( reinterpret_cast<char*>(&sntc), 10); sntc.showData(); cout << endl; } return 0; } オリジナルの文は "I am on my way to becoming a great C++ programmer."で 結果はこんな風です。 0 Sentence: I am on myB 10 Sentence: way to beB 20 Sentence: coming a gB 30 Sentence: reat C++ pB 40 Sentence: rogrammer.B Press any key to continue (Bがついていますが…気にしないでください(~o~)) 結局、readとreinterpret_cast<char*>はそのままなのですが getlineの発想から何がおかしいか発見できました。 liar_adanさんの回答がなかったらここまで辿り着けなかったと思います。 なるべく自分で解くように努力しますが、躓くだろうことは必至ですから これからもどうかよろしくお願いします。m(__)m ありがとうございました。

その他の回答 (2)

  • mk1234
  • ベストアンサー率30% (20/65)
回答No.2

う~~ なんてこったい。 せっかく朝、新規の質問2つに解答を書いて、その後を楽しみにして覗いてみたら、2つとも消えてるではないですか。(これは質問者に言っているのではないですよ。 あくまでも管理人さんのほうです) C++については良く分かりませんが、 1.コード1行づつに何をやってるのか書いてもらえればどこがおかしいか分かると思いますよ。 2.>結果:2nd Sentenr programmer.   >となります   推測ですが、1回目の読み込みのデータが残っているわけだから、それがあなたの期待に反するC++の仕様なら、自分で1回目のデータを消してから、2回目のデータを読み込めば良いのではないでしょうか?

ginkgo
質問者

お礼

答えてくださってたんですね。 どうやら、私の目に留まる前に消えたみたいですね。(>_<) 1. もともとのプログラムには一行一行丁寧に説明がありましたが、800字以内に収めないとここに載せられないので割愛しました(これが#1で述べている連続した質問をした理由です)。 2. それは確かに気付きませんでした。それで早速やろうと思ったのですが…クリアする方法が分かりませんでした。もうこの教科書、駄目です。5cmくらいの厚さがあるんですが、例題も目録も使えません。それ以前に私が駄目駄目ちゃんなんですが(爆) ありがとうございました。

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.1

新しい質問が削除されてしまったようですね。 最近、規則が厳しくなって、 連続している質問は禁止されたんですよ。 で、私はCはちょっと自信がありますが、 C++はよく知りません。 見当で書きますが的はずれだったらごめんなさい。 問題は、file.read()で、10文字読み込んだところで ヌル文字が書き込まれないことではないでしょうか。 char *による文字列は終端に\0が付かないとそのまま続いてしまいます。 10文字読み込んだ後に、11文字目に'\0'を書き込む作業が必要になります。 ところで、sentenceというのはどうもクラスのようですが、 これにreinterpret_castを使って文字列を書き込むのは、 どう考えてもおかしいような気がします。 クラスのメンバとしてchar txt[100];のようにして、 file.read(sentence.txt, 100); とか file.read(sentence.txt, 10); とかする方が普通ではないでしょうか。 もう一度言いますが、私はC++は詳しくないので、 間違ったことを言ってるかもしれません。 お許しください。

ginkgo
質問者

お礼

はい、連続している質問は禁止されたのは知っていましたが、そうでもしないとC++のプログラムなんかは全部載らないんですよね。かといって削ると「質問が分からない」と過去に何度かケチつけられましたし…。それならば800文字の制限をなんとかしてもらいたいですよね、OKWebさん...。 でもliar_adanさんが回答下さったお陰でmain以外のパートもやっと公開できます。感謝します! #include <fstream> #include <iostream> using namespace std; class sentence { protected: char str[80]; public: void getData() { cout << "\n Enter a sentence: "; cin.get(str, 80, '\n'); } void showData() { cout << "\n Sentence: " << str; } }; 問題は大きく分けて二つです。 ・一つ目は"2nd Senten"ではなくて"I am a poo"の10文字を表示させたいこと。 positionの設定がおかしいと思うのですが(n-1)にした時点で0になってるはずですよね…。 なぜ最初からにならないのでしょうか? ・二つ目は10文字で終わらずに表示されてしまうこと。 そうですね、ヌルがいるかもしれませんね。 ただ、seekgの前のラインでテストのために文1を表示しているのですが、 ここではヌルがなくてもちゃんと文の終わりで終わってるんですよね…。 どうしても駄目なら自分でヌルを入れることにします。 実はこのプログラムは教科書に載っている例題をいろんなところから切り貼りして名前を変えて作りました。reinterpret_castは一度変えたらエラー(char *に変換できません、とかいう)を食らったので変えるのをやめました。本当に必要であれば変えてみます。 ありがとうございました。 …引き続き、回答をお待ちしております。