新規記事の投稿を行うことで、非表示にすることが可能です。
2017年09月20日
《その37》 関数宣言(p.207演習6-4),値渡し(p.209演習6-5),Void関数(p.211演習6-6 )
新版明解C++入門編 p.207 演習6-4
半径 r の円の面積を求めて返却する関数 circ_area を作成せよ。円周率は3.14とする。
double circ_area(double r);※これ以降の問題文では、作成する関数の関数宣言を示します。
// p207_演習6-4
#include <iostream>
using namespace std;
double circ_area(double);
int main()
{
double r;
cout << "半径 : "; cin >> r;
cout << "円の面積 … " << circ_area(r) << '\n';
}
double circ_area(double r)
{
const double PI = 3.14;
return r * r * PI;
}

新版明解C++入門編 p.209 演習6-5
1からnまでの全整数の和を求めて返却する関数を作成せよ。
int sumup(int n);
// p209_演習6-5
#include <iostream>
using namespace std;
int sumup(int n)
{
int tmp = 0;
while (n > 0)
tmp += n--;
return tmp;
}
int main()
{
int n;
do {
cout << "正の整数を入力 : "; cin >> n;
} while (n < 1);
cout << "1から" << n << "までの全整数の和 … " << sumup(n) << '\n';
}

新版明解C++入門編 p.211 演習6-6
『こんにちは。』 と表示する関数 hello を作成せよ。
void hello();
// p211_演習6-6
#include <iostream>
using namespace std;
void hello()
{
cout << "こんにちは。\n";
}
int main()
{
hello();
}

--
《その36》 関数(p.205演習6-1,演習6-2,演習6-3 )
新版明解C++入門編 p.205 演習6-1
受け取ったint型引数の値nが負であれば-1を返却し、0であれば0を返却し、正であれば1を返却する関数 sign_ofを作成せよ。
以下の /* ・・・ */ の部分を作成すること。※作成するのは、関数本体の部分です。
int sign_of(int n) { /* ・・・ */ }
ただし、関数だけを作っても、正しく動作するかどうかの検証ができません。
そのため、関数をテストするmain関数なども作る必要があります。
これ以降の演習問題も同様です。
// p205_演習6-1
#include <iostream>
using namespace std;
int sign_of(int n)
{
if (n < 0)
n = -1;
if (n > 0)
n = 1;
return n;
}
int main()
{
int n;
do {
cout << "整数入力(999で終了) : "; cin >> n;
cout << "判定 … " << sign_of(n) << '\n';
} while (n != 999);
}

新版明解C++入門編 p.205 演習6-2
三つのint型引数 a, b, c の最小値を求める関数 min を作成せよ。
int min(int a, int b, int c) { /* ・・・ */ }
// p205_演習6-2
#include <iostream>
using namespace std;
int min(int a, int b, int c)
{
int min = a;
if (min > b)
min = b;
if (min > c)
min = c;
return min;
}
int main()
{
int a, b, c;
cout << "3整数入力 : "; cin >> a >> b >> c;
cout << "最小値 … " << min(a, b, c) << '\n';
}

新版明解C++入門編 p.205 演習6-3
三つのint型引数 a, b, c の中央値を求める関数 med を作成せよ。
int med(int a, int b, int c) { /* ・・・ */ }※中央値の例を、以下に示す。
変数 a, b, c が 1 , 3, 2 であれば中央値は 2で、1, 2, 1 であれば 1で、
1, 1, 1 であれば 1。
// p205_演習6-3
#include <iostream>
using namespace std;
int med(int a, int b, int c)
{
int med = a;
if ((a - b) * (b - c) >= 0) med = b;
if ((b - c) * (c - a) >= 0) med = c;
return med;
}
int main()
{
int a, b, c;
do {
cout << "3整数入力(0 0 0 の入力で終了) : "; cin >> a >> b >> c;
cout << "中央値 … " << med(a, b, c) << '\n';
} while (a != 0 || b != 0 || c != 0);
}

--
《その35》 多次元配列の要素数(p.189演習5-12),初期化子(p.191演習5-13)
新版明解C++入門編 p.189 演習5-12
3次元配列の要素数を求める式を示せ。プログラムを作成して確認を行うこと。
3次元配列aの要素数は
式 sizeof(a) / sizeof(a[0][0][0])
で求めることができる。
// p189_演習5-12
#include <iostream>
using namespace std;
int main()
{
cout << "3次元配列 a[5][6][7] の場合\n\n";
int a[5][6][7];
cout << "sizeof(a) / sizeof(a[0]) … "
<< sizeof(a) / sizeof(a[0]) << '\n';
cout << "sizeof(a[0]) / sizeof(a[0][0]) … "
<< sizeof(a[0]) / sizeof(a[0][0]) << '\n';
cout << "sizeof(a[0][0]) / sizeof(a[0][0][0]) … "
<< sizeof(a[0][0]) / sizeof(a[0][0][0]) << '\n';
cout << "\n要素数は\n";
cout << "sizeof(a) / sizeof(a[0][0][0]) … "
<< sizeof(a) / sizeof(a[0][0][0]) << '\n';
}

新版明解C++入門編 p.191 演習5-13
本文で解説した2次元配列の初期化を、実際にプログラムを作成して確認せよ。
// p191_演習5-13
#include <iostream>
using namespace std;
int main()
{
int a[3][2] = { {0},
{2, 3},
{4},
};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++)
cout << a[i][j] << " ";
cout << '\n';
}
cout << "------\n";
int b[3][2] = {0, 1, 2};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++)
cout << b[i][j] << " ";
cout << '\n';
}
cout << "------\n";
int c[3][2] = {0};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++)
cout << c[i][j] << " ";
cout << '\n';
}
}

--
《その34》 多次元配列(p.187演習5-10,演習5-11)
新版明解C++入門編 p.187 演習5-10
4行3列の行列と3行4列の行列の積を求めるプログラムを作成せよ。各構成要素の値はキーボードから読み込むこと。
// p187_演習5-10
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
int a[4][3]; int b[3][4]; int c[4][4];
cout << "4行3列の行列aの要素を読み込む\n";
for (int i = 0; i < 4; i++)
for (int j = 0; j < 3; j++) {
cout << "a[" << i << "][" << j << "] = "; cin >> a[i][j];
}
cout << "3行4列の行列bの要素を読み込む\n";
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++) {
cout << "b[" << i << "][" << j << "] = "; cin >> b[i][j];
}
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
c[i][j] = 0;
for (int k = 0; k < 3; k++)
c[i][j] += a[i][k] * b[k][j];
}
cout << "\n◆行列a\n";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++)
cout << setw(4) << a[i][j];
cout << '\n';
}
cout << "\n◆行列b\n";
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++)
cout << setw(4) << b[i][j];
cout << '\n';
}
cout << "\n◆行列aと行列bの積\n";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
cout << setw(4) << c[i][j];
cout << '\n';
}
}

新版明解C++入門編 p.187 演習5-11
6人の2科目(国語・数学)の点数を読み込んで、科目ごとの合計点と平均点、学生ごとの合計点と平均点を求めるプログラムを作成せよ。
// p187_演習5-11
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
// 国 数
int a[6][2] = { { 56, 25},
{100, 89},
{ 77, 36},
{ 49, 80},
{100, 100},
{ 17, 2}, };
int subject[2] = {0};
for (int i = 0; i < 6; i++)
for (int j = 0; j < 2; j++)
subject[j] += a[i][j];
cout << "国_合計 : " << setw(4)
<< subject[0] << '\n'
<< "国_平均 : " << setw(6)
<< fixed
<< setprecision(1)
<< (double)subject[0] / 6 << '\n';
cout << "数_合計 : " << setw(4)
<< subject[1] << '\n'
<< "数_平均 : " << setw(6)
<< (double)subject[1] / 6 << "\n\n";
int student[6] = {0};
for (int i = 0; i < 6; i++)
for (int j = 0; j < 2; j++)
student[i] += a[i][j];
for (int i = 0; i < 6; i++)
cout << "生徒№" << i + 1
<< " … 2教科合計 " << setw(3)
<< student[i]
<< " 2教科平均 " << setw(5)
<< (double)student[i] / 2 << '\n';
}

--
2017年09月19日
《その33》 配列の要素の並びの変更(p.181演習5-8),配列のコピー(p.183演習5-9)
新版明解C++入門編 p.181 演習5-8
配列の並びをシャッフルする(要素の並びがランダムになるようにかき混ぜる)プログラムを作成せよ。
// p181_演習5-8
#include <iomanip>
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
const int n = 6;
int a[n];
int b[n]; // シャッフル後の要素順に値を格納
int idx[n]; // 0~nの異なるn個の整数をランダムに格納
srand(unsigned int(time(NULL)));
cout << "シャッフル前 … ";
for (int i = 0; i < n; i++) {
a[i] = rand() % 100;
cout << "a[" << i << "] = " << setw(2) << a[i] << ' ';
}
cout << '\n';
for (int i = 0; i < n; i++) {
bool fail = false; // idx[i]の値に重複が無ければfalse,あればtrue
do {
idx[i] = rand() % n;
for (int j = 0; j < i; j++) {
if (idx[i] == idx[j]) {
fail = true; break;
}
else
fail = false;
}
b[i] = a[idx[i]];
} while (fail);
}
cout << "シャッフル後 … ";
for (int i = 0; i < n; i++) {
a[i] = b[i]; // 配列aを配列bで上書き
cout << "a[" << i << "] = " << setw(2) << a[i] << ' ';
}
cout << '\n';
}


新版明解C++入門編 p.183 演習5-9
配列aの全要素を配列bに対して逆順にコピーするプログラムを作成せよ。
// p183_演習5-9
#include <iostream>
using namespace std;
int main()
{
const int n = 5;
int a[n];
int b[n];
cout << "整数値を入力\n";
for (int i = 0; i < n; i++) {
cout << "a[" << i << "] : "; cin >> a[i];
}
cout << '\n';
for (int i = 0; i < n; i++)
b[i] = a[n - i - 1];
for (int i = 0; i < n; i++)
cout << "b[" << i << "] = " << b[i] << '\n';
}

--
2017年09月18日
《その32》 配列(p.179演習5-4,演習5-5,演習5-6,演習5-7)
新版明解C++入門編 p.179 演習5-4
連続する要素が同じ値とならないように、演習 5-3 のプログラムを改変したプログラムを作成せよ。
たとえば、{1, 3, 5, 5, 3, 2} とならないようにすること。
// p179_演習5-4
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
const int num = 6;
int a[num];
for (int i = 0; i < num; i++) {
a[i] = rand() % 10 + 1;
while (i > 0 && a[i] == a[i - 1])
a[i] = rand() % 10 + 1;
cout << "a[" << i << "] = " << a[i] << " ";
}
cout << '\n';
}

新版明解C++入門編 p.179 演習5-5
異なる要素が同じ値とならないように、演習 5-3 のプログラムを改変したプログラムを作成せよ。
たとえば、{1, 3, 5, 6, 1, 2} とならないようにすること。
// p179_演習5-5
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
const int num = 6;
int a[num];
for (int i = 0; i < num; i++) {
bool fail = false; // 他の要素に同じ値が無ければ0,あれば1
do {
a[i] = rand() % 10 + 1;
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
fail = true; break;
}
else
fail = false;
}
} while (fail);
}
for (int i = 0; i < num; i++)
cout << "a[" << i << "] = " << a[i] << " ";
cout << '\n';
}

新版明解C++入門編 p.179 演習5-6
要素型が int型で要素数が 15の配列の全要素に 1 ~ 10 の乱数を代入して、棒グラフで値を表示するプログラムを作成せよ。
棒グラフは記号文字 '*' を横方向に並べたものとする。
// p179_演習5-6
#include <iomanip>
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
const int num = 15;
int a[num];
for (int i = 0; i < num; i++)
a[i] = rand() % 11;
for (int i = 0; i < num; i++) {
cout << "a[" << setw(2) << i << "] = " << setw(2) << a[i] << " ";
for (int j = 0; j < a[i]; j++)
cout << "*";
cout << '\n';
}
}

新版明解C++入門編 p.179 演習5-7
前問を書きかえて、縦方向の棒グラフによって値を表示するプログラムを作成せよ。添字を 10で割った剰余を最下段に表示すること。。
// p179_演習5-7
#include <iomanip>
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
const int num = 15;
int a[num];
for (int i = 0; i < num; i++)
a[i] = rand() % 11;
for (int h = 10; h > 0; h--) {
for (int i = 0; i < num; i++) {
if (a[i] >= h)
cout << " * ";
else
cout << " ";
}
cout << '\n';
}
for (int i = 0; i < num; i++)
cout << "---";
cout << '\n';
for (int i = 0; i < num; i++)
cout << setw(2) << a[i] << " ";
cout << " ← 発生した乱数(0~10)の値\n";
for (int i = 0; i < num; i++)
cout << setw(2) << i << " ";
cout << " ← 配列a[n]の添字nの値\n";
for (int i = 0; i < num; i++)
cout << setw(2) << i % 10 << " ";
cout << " ← 添字を10で割った剰余\n";
}

--
《その31》 定値オブジェクトで表す要素数(p.178演習5-1,演習5-2,演習5-3)
新版明解C++入門編 p.178 演習5-1
要素型が int型で要素数が 5の配列の要素に対して、先頭から順に 5, 4, 3, 2, 1 を代入して表示するプログラムを作成せよ。
// p178_演習5-1
#include <iostream>
using namespace std;
int main()
{
const int num = 5;
int a[num];
for (int i = 0; i < num; i++) {
a[i] = num - i;
}
for (int i = 0; i < num; i++)
cout << "a[" << i << "] = " << a[i] << '\n';
}

新版明解C++入門編 p.178 演習5-2
要素型が double型で要素数が 5の配列の全要素に 0.0 を代入して表示するプログラムを作成せよ。
// p178_演習5-2
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
const int num = 5;
double a[num] = { 0.0 };
cout << fixed << setprecision(1);
for (int i = 0; i < num; i++)
cout << "a[" << i << "] = " << a[i] << '\n';
}

新版明解C++入門編 p.178 演習5-3
要素型が int型で要素数が 6の配列の全要素を 1 ~ 10 の乱数で埋め尽くす( 1以上 10以下のランダムな値を代入する)プログラムを作成せよ。
// p178_演習5-3
#include <ctime>
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));
const int num = 6;
int a[num];
for (int i = 0; i < num; i++) {
a[i] = rand() % 10 + 1;
cout << "a[" << i << "] = " << a[i] << " ";
}
cout << '\n';
}

--
2017年09月17日
《その30》 列挙体(p.163演習4-12,p.165演習4-13)
新版明解C++入門編 p.162 List 4-17 のプログラムで、重要かなと個人的に思った箇所は つぎの2つです。
① while (type < Dog || type > Invalid);
② animal_selected = static_cast<animal>(type);
① のポイントは、列挙体である animal型の Dog や Invalid を、そのままキャスト無しで 整数型である type と比較することができるということ。
② のポイントは、列挙体 animal_selected = type; と書くことはできない点です。つまり、整数を列挙型へ代入するときにはキャストが必要だということです。
◆ 列挙型から整数への変換ではキャストが不要
◆ 整数から列挙型への変換ではキャストが必要
新版明解C++入門編 p.163 演習4-12
トランプの記号(ダイヤ、ハート、クラブ、スペード)の四つの列挙子をもつ列挙体を定義せよ。各列挙子の値は、先頭から順に 0, 1, 2, 3 とし、List 4-17と同様にキーボードから値を読み込んで表示すること。
// p163_演習4-12
#include <iostream>
using namespace std;
int main()
{
enum suit { Diamond, Heart, Club, Spade };
int type;
do {
cout << "0…ダイヤ 1…ハート 2…クラブ 3…スペード : "; cin >> type;
} while (type < Diamond || type > Spade); // キャストが不要
suit selected = static_cast<suit>(type); // キャストが必要
switch (selected) {
case Diamond: cout << "ダイヤが好きです!\n" ; break;
case Heart: cout << "ハートが好きです!\n" ; break;
case Club: cout << "クラブが好きです!\n" ; break;
case Spade: cout << "スペードが好きです!\n"; break;
}
}

新版明解C++入門編 p.165 演習4-13
性別、季節、曜日などを表す列挙体を自由に定義し、それを用いたプログラムを作成せよ。
「自由に」ということなので、何月かを数字で入力すると その月の呼び名を 旧暦で表示するプログラムにしました。
最初に、名前のある普通の列挙体を使うプログラムを作って、次に、それを名前のない列挙体を使うプログラムに変更してみました。
// p165_演習4-13_1
#include <iostream>
using namespace std;
int main()
{
enum months { January = 1, February, March, April, May, June,
July, August, September, October, November, December};
int num;
do {
cout << "何月?:"; cin >> num;
} while (num < January || num > December);
months selected = static_cast<months>(num);
switch (selected) {
case January : cout << "睦月\n" ; break;
case February : cout << "如月\n" ; break;
case March : cout << "弥生\n" ; break;
case April : cout << "卯月\n" ; break;
case May : cout << "皐月\n" ; break;
case June : cout << "水無月\n" ; break;
case July : cout << "文月\n" ; break;
case August : cout << "葉月\n" ; break;
case September : cout << "長月\n" ; break;
case October : cout << "神無月\n" ; break;
case November : cout << "霜月\n" ; break;
case December : cout << "師走\n" ; break;
}
}

次に、上のプログラムを 名前のない列挙体を使う形に変更してみました。
// p165_演習4-13_2
#include <iostream>
using namespace std;
int main()
{
enum /*months*/ { January = 1, February, March, April, May, June,
July, August, September, October, November, December};
int num;
do {
cout << "何月?:"; cin >> num;
} while (num < January || num > December);
// months selected = static_cast<months>(num);
// switch (selected) {
switch (num) {
case January : cout << "睦月\n" ; break;
case February : cout << "如月\n" ; break;
case March : cout << "弥生\n" ; break;
case April : cout << "卯月\n" ; break;
case May : cout << "皐月\n" ; break;
case June : cout << "水無月\n" ; break;
case July : cout << "文月\n" ; break;
case August : cout << "葉月\n" ; break;
case September : cout << "長月\n" ; break;
case October : cout << "神無月\n" ; break;
case November : cout << "霜月\n" ; break;
case December : cout << "師走\n" ; break;
}
}

--
2017年09月16日
《その29》 繰返しの制御(p.159演習4-10,演習4-11)
新版明解C++入門編 p.159 演習4-10
List 4-15のように、float型の変数を 0.0 から 1.0 まで 0.001 ずつ増やしていく様子と、List 4-16 のように、int型の変数を 0 から 1000 までインクリメントした値を 1000 で割った値を求める様子を、横に並べて表示するプログラムを作成せよ。
// p159_演習4-10
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
float xf = 0.0f; // 0.001fを繰り返し加えて作る実数
float xi; // 1ずつ増える整数nを1000で割った実数
float sumf = 0.0f; // xfの合計
float sumi = 0.0f; // xiの合計
cout << fixed << setprecision(6);
cout << " float int\n";
cout << "------------------\n";
for (int n = 0; n <= 1000; n++) { // 1ずつ増える整数n
xi = static_cast<float>(n) / 1000; // 整数nを1000で割った実数xi
if (n <= 4 || n >= 498 && n <= 502 || n >= 996)
cout << xf << " " << xi << '\n';
if (n == 200 || n == 800)
cout << "…中略… …中略…\n";
sumf += xf;
sumi += xi;
xf += 0.001f; // 実数xfに0.001fを加える
}
cout << "------------------\n";
cout << "floatの合計 … " << sumf << '\n';
cout << "int の合計 … " << sumi << '\n';
}

新版明解C++入門編 p.159 演習4-11
float型の変数を 0.0 から 1.0 まで 0.001 ずつ増やしながら、その値と、その値の2乗を表示するプログラムを作成せよ。
// p159_演習4-11
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
cout << fixed << setprecision(6);
cout << " 元の値 2乗値\n";
int n = 0;
for (float x = 0.0f; x <= 1.0f; x += 0.001f) {
if (x < 0.005) cout << x << " " << x * x << '\n';
if (++n == 500) cout << " ・・・ ・・・\n";
if (x > 0.995) cout << x << " " << x * x << '\n';
}
}

--
2017年09月15日
《その28》 操作子 setprecision
p.158 に、つぎのような記述があります。
『setprecision操作子は、《精度》を指定します。なお、ここでの《精度》は、出力記法などによって解釈が異なります。固定小数点記法による出力における《精度》は、小数部の桁数とみなされます。』
このことについて、いちおう確認してみました。
◆ 浮動小数点数を 固定小数点記法で出力
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
float a = 12.3456789012345;
double b = 12.3456789012345;
cout << fixed << setprecision(10) << "a … " << a << '\n';
cout << "b … " << b << '\n';
}

fixed操作子 + setprecision(10)操作子 の指示で、確かに小数部桁数は 10になっています。
◆ 浮動小数点数を 指数付き記法で出力
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
float a = 12.3456789012345;
double b = 12.3456789012345;
cout << scientific << setprecision(10) << "a … " << a << '\n';
cout << "b … " << b << '\n';
}

scientific操作子 + setprecision(10)操作子 で指示した場合も、小数部桁数は 10になっています。
◆ 浮動小数点数を setprecision操作子を使わずに 固定小数点記法で出力
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
float a = 12.3456789012345;
double b = 12.3456789012345;
cout << fixed/* << setprecision(10)*/ << "a … " << a << '\n';
cout << "b … " << b << '\n';
}

setprecision(10)操作子を使わず fixed操作子のみの出力では、小数部桁数が 6になります。
◆ 浮動小数点数を fixed操作子も scientific操作子も使わず setprecision操作子だけを使って出力
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
float a = 12.3456789012345;
double b = 12.3456789012345;
cout/* << fixed*/ << setprecision(10) << "a … " << a << '\n';
cout << "b … " << b << '\n';
}

setprecision操作子のみの場合は、出力結果をみると 小数部桁数が安定していません。
--