先頭へ戻る

ファイルとエラー 解答ページ | Programming Place Plus 新C++編

Programming Place Plus トップページ新C++編ファイルとエラー

先頭へ戻る

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (確認★)

次のプログラムを実行すると、どういう出力になりますか?

#include <iostream>

int main()
{
    std::cout << "a";
    std::cerr << "b";
    std::cout << "c" << std::flush;
    return 0;
    std::cout << "d";
    std::cerr << "e";
}


途中で return 0; としているところがあります。main関数の中に書いた return文が実行されると、その時点でプログラムが終了します(本編解説)。したがって、return 0; よりも下に書かれている2つの出力は行われません。

実行されるのは先頭の3つの出力だけということになります。

std::cout による出力はバッファリングされ、std::cerr による出力はバッファリングされませんが、main関数が終了するときに強制的にフラッシュされますから、先頭の3つの出力 (abc) はきちんと出力されます(本編解説)。

よって実行結果はこうなります。

abc

問題2 (応用★★)

標準入力から名前と年齢、血液型を入力させ、その情報をファイルへ書き出すプログラムを作成してください。ファイル処理に関するエラーチェックも実装してください。


たとえば次のようになります。

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>

int main()
{
    std::cout << "Please enter the your name.\n";
    std::string name {};
    std::getline(std::cin, name);

    std::cout << "Please enter the your age.\n";
    std::string age {};
    std::getline(std::cin, age);

    std::cout << "Please enter the your bloodtype.\n";
    std::string blood_type {};
    std::getline(std::cin, blood_type);

    constexpr auto path = "data.txt";
    std::ofstream ofs(path);
    if (ofs.fail()) {
        // ファイルオープンに失敗
        std::cerr << "File open error: " << path << "\n";
        return EXIT_FAILURE;
    }

    ofs << name << "\n";
    ofs << age << "\n";
    ofs << blood_type << "\n";

    ofs.close();
    if (ofs.fail()) {
        // ファイルクローズに失敗
        std::cerr << "File close error: " << path << "\n";
        return EXIT_FAILURE;
    }

    std::cout << "Save to " << path << "\n";
}

実行結果(標準出力):

Please enter the your name.
Ken Tanaka  <-- 入力した内容
Please enter the your age.
31  <-- 入力した内容
Please enter the your bloodtype.
AB  <-- 入力した内容
Save to data.txt

実行結果(data.txt):

Ken Tanaka
31
AB

最初に標準入力から情報を受け取ったあと、std::ofstream によって data.txt を書き込み用にオープンしています。ここでオープンに失敗する可能性を考えて、エラーチェックをしています。エラーチェックは fail関数(あるいは、オープンに関しては is_open関数)を使って行えます(本編解説)。

エラーが起きていたら、std::cerr で標準エラーにエラーメッセージを出力してから、return文を使ってプログラムを終了させます。return EXIT_FAILURE; のようにして、失敗したことを明確にします(本編解説)。

ofs への書き込みのところではエラーチェックをしていません。しても構いませんが、書き込むデータをバッファに蓄えているだけなら、ここでエラーチェックしてもまず無意味です(本編解説)。今回は、クローズ時にエラーチェックするようにしました。これは、クローズ時にフラッシュされる保証があるからです。

クローズ時にエラーチェックするためには、自動的なクローズに任せず、ofs.close(); のようにしてクローズする必要があります(本編解説)。


なお、ここでは省きましたが、入力された内容が不適切かどうかのチェックを行うことも考えられます。名前が未入力であったり、年齢がマイナスあるいは整数でなかったり、血液型も A、B、AB、O 以外の入力を認めたくない場合もあるかもしれません。今回のプログラムであれば、標準入力からの入力を受け取ったあとで、こういったチェックを行い、問題があれば、data.txt に書き出さないようにするのがいいでしょう。

現時点までの解説内容では、血液型のチェックを書くのが難しいという問題はあります(「複数のパターンのどれにも該当しないとき」という条件式が書けない)。

問題3 (応用★★)

問題2で作られたファイルを読み込んで、名前と年齢、血液型を標準出力へ出力するプログラムを作成してください。ファイル処理に関するエラーチェックも実装してください。


たとえば次のようになります。

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>

int main()
{
    constexpr auto path = "data.txt";
    std::ifstream ifs(path);
    if (ifs.fail()) {
        // ファイルオープンに失敗
        std::cerr << "File open error: " << path << "\n";
        return EXIT_FAILURE;
    }

    std::string name {};
    std::getline(ifs, name);
    std::string age {};
    std::getline(ifs, age);
    std::string blood_type {};
    std::getline(ifs, blood_type);
    if (ifs.fail()) {
        // ファイルからの読み込みに失敗
        std::cerr << "File read error: " << path << "\n";
        return EXIT_FAILURE;
    }

    std::cout << name << "\n";
    std::cout << age << "\n";
    std::cout << blood_type << "\n";    

    ifs.close();
    if (ifs.fail()) {
        // ファイルクローズに失敗
        std::cerr << "File close error: " << path << "\n";
        return EXIT_FAILURE;
    }
}

data.txt の内容:

Ken Tanaka
31
AB

実行結果:

Ken Tanaka
31
AB

今度は読み込みなので std::ifstream に変わりましたが、ファイルオープンのエラーチェックの方法は問題②と同じです。

ファイルからの読み込みの際のエラーチェックは、3つのデータをすべて読み取るコードを通してから1回だけ行うようにしています。1回1回チェックしてもいいですが、どこかで失敗すれば、それ以降も失敗するので、これでも構いません。

ここでは省きましたが、読み込んだデータが想定外のものである可能性もあります。そのようなチェックをするなら、読み込みのエラーチェックの直後で行います(本編解説)。

問題4 (調査★★)

標準出力と標準エラーへ出力しているプログラムを作成し、リダイレクトによって出力先を別々のところに変更することを試してみてください。


コマンドプロンプトなどがもつリダイレクトという機能を使うと、標準出力や標準エラーおよび標準入力の入出力先を変更できます。コマンドプロンプトでの方法については、Windows編>コマンドプロンプト>リダイレクトのページで説明しています。

実験用に次のようなプログラムを作成します。

#include <iostream>

int main()
{
    std::cout << "Hello standard output.\n";
    std::cerr << "Hello standard error.\n";
}

このプログラムをビルドして実行ファイルを作成したら、コマンドプロンプトから実行します。普通に実行する場合、次のように書きます(実行ファイルの名前は hello.exe だとする)。

hello.exe

標準出力の出力先を stdout.txt に変更するには、次のように実行します。

hello.exe >stdout.txt

標準エラーの出力先を stderr.txt に変更するには、次のように実行します。

hello.exe 2>stderr.txt

2つを同時に行うには、次のように実行します。

hello.exe >stdout.txt 2>stderr.txt

この場合の実行結果は次のようになります。

実行結果(画面):

実行結果(stdout.txt):

Hello standard output.

実行結果(stderr.txt):

Hello standard error.


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
Twitter でツイート Twitter をフォロー LINE で送る
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー