アフィリエイト広告を利用しています

広告

この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
posted by fanblog

2017年09月30日

《その57》 cin.getline(line, sizeof(line)); (p.314演習8-5)


新版明解C++入門編 p.314 演習8-5
 文字列 s の全文字を先頭から順に 1行に 1文字ずつ表示する関数 putv を作成せよ。
    void putv(const char* s);

プログラムの仕様を次のようにしようと思います。

スペース文字も含めた文字列を、キーボードから char str[11] に読み込む。
( 読み込み可能な文字数はナル文字も含めて11文字までなので、
キーボードから10文字を超える入力はできない。)

11文字以上入力しても、10文字までしか受け取らないようにする。

この仕様を実現するために、

cin.getline(str, 11, '\n');

を利用します。
これで、文字数上限値は11、受け取る文字は '\n' 入力の前までということになります。

なお、3 番目の引数の既定値は改行文字なので省略しても大丈夫です。
'\n' を 'a' などとすることもできます。その場合、受け取るのは 'a' の直前までです。


// p314_演習8-5
#include <iostream>
using namespace std;

void putv(const char* s)
{
while (*s) {
cout << *s++ << '\n';
}
}

int main()
{
char str[11];
cout << "文字列を入力:"; cin.getline(str, 11, '\n');
cout << "受け取った文字列 … " << str << '\n';
putv(str);
}

b08_05.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

2017年09月29日

《その56》 cstringライブラリ(p.306)


strlen関数
------------------------------------
文字列処理を行うライブラリ関数は、ヘッダで提供されています。
strlen関数は、文字列の長さを求めるための関数です。

ヘッダ #include <cstring>
形式  size_t strlen(const char* s);
解説  s が指す文字列の長さ(ナル文字は含まない)を求める。
返却値 求めた文字列の長さを返す。
------------------------------------p.306

この関数の実現例として、

------------------------------------
#include <cstddef>
size_t strlen(const char* s)
{
size_t len = 0;

while (*s++)
len++;
return len;
}
------------------------------------p.306

というコードが示されています。
#include <cstddef> は、size_t型 の定義のためと思われます。

この strlen関数の働きを確認するために、次のような簡単なプログラムを作りました。

// プログラム【1】
#include <cstddef>
#include <iostream>
using namespace std;

size_t strlen(const char* s)
{
size_t len = 0;

while (*s++)
len++;
return len;
}

int main()
{
char s[255];
cout << "文字列を入力 : "; cin >> s;
cout << "文字列\"" << s << "\"の長さ … " << strlen(s) << '\n';
}

c08_001.png

予想通りの結果です。

ところが!! 上のプログラムの関数strlen を除去してしまっても、プログラムが問題なく動作することに気付いてしまいました!
#include <cstring> を記述してないので、
ライブラリ関数strlen は使えないと思っていた
のですが・・・。

// プログラム【2】
#include <cstddef>
#include <iostream>
using namespace std;
/*
size_t strlen(const char* s)
{
size_t len = 0;

while (*s++)
len++;
return len;
}
*/

int main()
{
char s[255];
cout << "文字列を入力 : "; cin >> s;
cout << "文字列\"" << s << "\"の長さ … " << strlen(s) << '\n';
}

このプログラムで、全く同じ結果が得られてしまいます。

ということは、「ライブラリ関数strlen」 と 「プログラムに記述したstrlen関数」 が同居していたことになります。
では、最初の プログラム【1】では、いったいどちらの strlen関数が使われたのか。

それを確かめるために プログラム【1】 の strlen関数内に
   cout << "こっちだよ!/n";
という行を加えてみました。

// プログラム【3】
#include <cstddef>
#include <iostream>
using namespace std;

size_t strlen(const char* s)
{
size_t len = 0;
cout << "こっちだよ!\n";
while (*s++)
len++;
return len;
}

int main()
{
char s[255];
cout << "文字列を入力 : "; cin >> s;
cout << "文字列\"" << s << "\"の長さ … " << strlen(s) << '\n';
}


コンパイルは無事に成功しました。ですが、実行してみたところ・・・

c08_002.png

プログラム【3】で加えた
   cout << "こっちだよ!/n";
には、文法上のミスはないので、二つのstrlen関数が競合してしまったのでしょうか。

それを確かめるため、こんどは、strlen関数の名前を srtlen2 に変更してみました。それ以外は一切変更していません。

// プログラム【4】
#include <cstddef>
#include <iostream>
using namespace std;

size_t strlen2(const char* s)
{
size_t len = 0;
cout << "こっちだよ!\n";
while (*s++)
len++;
return len;
}

int main()
{
char s[255];
cout << "文字列を入力 : "; cin >> s;
cout << "文字列\"" << s << "\"の長さ … " << strlen2(s) << '\n';
}

c08_003.png

strlen2関数はちゃんと働きました。

以上のことから、プログラム【3】では、二つの strlen関数が競合していることがはっきりしました。
では、なぜプログラム【1】のときは、競合せずに動作したのでしょうか。

プログラム【1】とプログラム【3】の違いは、
   cout << "こっちだよ!/n";
の有無だけです。

ここから先は、あくまでも想像ですが・・・

プログラム【1】では、「ライブラリ関数strlen」 と「プログラムに記述したstrlen関数」 は、外から見て全く同じ動作をします。
一方、プログラム【3】では、「プログラムに記述したstrlen関数」が、「こっちだよ!」というメッセージを出力するので、二つのstrlen関数の動作が異なります。
それが、【1】が許されて【3】が許されない理由ではないでしょうか。
引数も返却値も同じなので、多重定義は許されないはずですが、「働きも同じなら、まあいいか」ということですかね。

長くなってしまったので、コードは書きませんが、
プログラム【1】のときに、「ライブラリ関数strlen」 と「プログラムに記述したstrlen関数」の どちらが使われたのかを調べてみました。
外から見た動作を変えるとプログラムが停止してしまうため、入出力のコードを書き加えることはできません。
なので、「プログラムに記述したstrlen関数」の中に for文で時間稼ぎのコードを入れてみたところ、プログラム【1】の動作が極端に遅くなりました。

プログラム【1】では、「ライブラリ関数strlen」ではなく、「プログラムに記述したstrlen関数」が使われたようです。



新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

2017年09月28日

《その55》 コマンドライン引数(p.304)


コマンドライン引数

 main関数は、プログラムの起動時にコマンドラインから与えられるパラメータを、文字列の配列として受け取ることができます。

◆1.  まず、以下のコードを書きました。

// command_line_test
#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
cout << "引き数 int argc = " << argc << '\n';

for (int i = 0; i < argc; i++)
cout << "argv[" << i << "] = " << argv[i] << '\n';
}

 このコードの int main(int argc, char** argv) の部分に、
  二つの引数 int argc と char** argv がありますが、main関数は、
  この引数を利用してコマンドラインから与えられるパラメータを受け取ります。


◆2.  コンパイルして、実行ファイルcommand_line_test.exe を作ります。

 実行ファイルを作る手順は、このブログの 《その1》 〜 《その5》 に書いてありますので、忘れた方はそちらをご覧ください。


◆3. 作製した実行ファイルcommand_line_test.exe を、パスを通したフォルダに置きます。

 フォルダにパスを通す手順は、ネット上にたくさんあるので、そちらを参照してください。


◆4. とりあえず、コマンドプロンプトのコマンドラインから、次のように入力して、
command_line_test.exeを起動してみました。

   command_line_test AAA BBB CCC あいうえお かきくけこ

 プログラムが起動しmain関数が呼び出されると、
   int main(int argc, char** argv) の 引数int argc に
   「 プログラム名command_line_test AAA BBB CCC あいうえお かきくけこ 」
   の個数である 6 が渡されます。
 また、引数char** argv は、ポインタを要素とする配列で、
   「 AAA BBB CCC あいうえお かきくけこ 」を指す五つのポインタが格納されます。


◆5. プログラムが実行され、画面に次のように表示されました。

b08_999.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

《その54》 ポインタによる文字列 / 文字列の配列(p.303演習8-4)


文字列リテラル

 配列による文字列
    char str[] = "ABC";

cout << str; … "ABC"
要素str[0] … 'A'
要素str[1] … 'B'
要素str[2] … 'C'
要素str[3] … '\0'

str = "XYZ"; // 代入はNG(エラー)


 ポインタによる文字列
    char* ptr = "PQR";

cout << ptr; … "PQR"
要素ptr[0] … 'P'
要素ptr[1] … 'Q'
要素ptr[2] … 'R'
要素ptr[3] … '\0'

pqr = "XYZ"; // 代入はOK

◆ ポインタによる文字列は、ポインタptrと文字列"PQR"の両方が記憶域を占有する。



文字列の配列

 《配列による文字列》の配列
    char a[][5] = { "LISP", "C", "Ada" };

a[0][0] :"L" , a[0][1] :"I" , a[0][2] :"S" , a[0][3] :"P" , a[0][4] :"\0"
a[1][0] :"C" , a[1][1] :"\0", a[1][2] :"\0", a[1][3] :"\0", a[1][4] :"\0"
a[2][0] :"A" , a[2][1] :"d" , a[2][2] :"a" , a[2][3] :"\0", a[2][4] :"\0"

cout << a[0]; … "LISP"
cout << a[1]; … "C"
cout << a[2]; … "Ada"

sizeof(a); … 15
sizeof(a[0]); … 5
sizeof(a[1]); … 5
sizeof(a[2]); … 5

◆ 初期化子の文字列リテラルが連続して配置されることが保証されている。


 《ポインタによる文字列》の配列
    char* p[] = { "PAUL", "X", "MAC" };

p[0][0] :"P" , p[0][1] :"A" , p[0][2] :"U" , p[0][3] :"L" , p[0][4] :"\0"
p[1][0] :"X" , p[1][1] :"\0"
p[2][0] :"M" , p[2][1] :"A" , p[2][2] :"C" , p[2][3] :"\0"

cout << p[0]; … "PAUL"
cout << p[1]; … "X"
cout << p[2]; … "MAC"

sizeof(p); … 12(ポインタ三つ分のサイズ)
sizeof(p[0]); … 4 (ポインタのサイズ)
sizeof(p[1]); … 4 ( 〃 )
sizeof(p[2]); … 4 ( 〃 )

◆ 初期化子の文字列リテラルが連続して配置されるという保証がない。




新版明解C++入門編 p.303 演習8-4
 List8-11 では、各配列の個数 3 が定数としてプログラム中(for文の制御式)に埋め込まれている。計算によって書きかえたプログラムを作成せよ。

// p303_演習8-4
#include <iostream>
using namespace std;

int main()
{
char a[][5] = {"LISP", "C", "Ada"};
char* p[] = {"PAUL", "X", "MAC"};

for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
cout << "a[" << i << "] = \"" << a[i] << "\"\n";

for (int i = 0; i < sizeof(p) / sizeof(p[0]); i++)
cout << "p[" << i << "] = \"" << p[i] << "\"\n";
}

b08_04.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

《その53》 文字列リテラル(p.294演習8-1,p.295演習8-2,p.297演習8-3)


文字配列の初期化
    char[] = {'A', 'B', 'C', '\0'};
char[] = "ABC";( 終端にナル文字'\0'が挿入される。)

文字列リテラルには静的記憶域期間が与えられる。

文字列リテラルが関数の中にあっても外にあっても同様。

静的記憶域期間
プログラム実行開始時の準備段階でオブジェクトが生成されて、プログラムの
終わりまで生き続け、最後に破棄される。



新版明解C++入門編 p.294 演習8-1
 List8-4の配列 s の宣言を以下のように書きかえたプログラムを作成せよ。
    char s[] = "ABC\0DEF";
実行結果に対する考察を行うこと。

// p294_演習8-1
#include <iostream>
#include <typeinfo>
using namespace std;

int main()
{
char s[] = "ABC\0DEF";
cout << "char s[] = \"ABC\\0DEF\";" << '\n';

cout << '\n';
cout << "cout << s;" << " → " << s << " と表示される。\n";
cout << "sizeof(s)" << " … " << sizeof(s) << '\n';
cout << "sizeof(s[0])" << " … " << sizeof(s[0]) << '\n';
cout << "typeid(s).name()" << " … " << typeid(s).name() << '\n';
cout << "typeid(s[0]).name()" << " … " << typeid(s[0]).name() << '\n';

cout << '\n';
for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
if (s[i] == '\0')
cout << "\\0" << '\n';
else
cout << s[i] << '\n';
}
}

b08_01_.png
考察:
 文字列"ABC\0DEF"は、末尾のナル文字'\0'を含めて8文字分の領域を占有する。
 文字列"ABC\0DEF"は、文字列"ABC\0"と文字列"DEF\0"が隣接した文字列リテラルである。
 cout << s; で表示されるのは最初のナル文字までの「 ABC 」である。



新版明解C++入門編 p.295 演習8-2
 以下のように初期化された文字列 s を空文字列にするコードを示せ。
    char s[] = "abc";

 コードはの次のようになると思いますが、これでは画面に何も表示されません。
#include <iostream>
using namespace std;

int main()
{
char s[] = "ABC";
for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
s[i] = '\0';
}

 画面で確認できるように、次のようなプログラムにしました。

// p295_演習8-2
#include <iostream>
using namespace std;

int main()
{
char s[] = "ABC";

cout << "s … " << s << '\n';
for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
if (s[i] == '\0')
cout << "\\0" << '\n';
else
cout << s[i] << '\n';
}

for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
s[i] = '\0';

cout << "\n空文字列にした後\n";
cout << "s … " << s << '\n';
for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++) {
if (s[i] == '\0')
cout << "\\0" << '\n';
else
cout << s[i] << '\n';
}
}

b08_02.png



新版明解C++入門編 p.297 演習8-3
 文字列中の大文字を小文字に変換した上で表示する関数 put_lower を作成せよ。
    void put_lower(const char s[]);

// p297_演習8-3
#include <cctype>
#include <iostream>
using namespace std;

void put_lower(const char s[])
{
for (int i = 0; s[i]; i++)
cout << static_cast<char>(tolower(s[i]));
/*
s[i] == 0 となった時点で for文が終了する。
C++ のプログラムでは、'\n'でなく 0 を使うが一般的。

tolower関数の返却値は int型なので、そのままでは文字コードが
整数値として表示されてしまう。
そのため、char型にキャストした上で表示している。

*/
}

int main()
{
char str[36];

cout << "文字列:";
cin >> str;

put_lower(str);
cout << '\n';
}

b08_03.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

2017年09月27日

《その52》 オブジェクトの動的な生成(p.279演習7-15,p.285演習7-16,演習7-17)


int型オブジェクトの動的な生成

生成
int* x = new int; 不定値で初期化
int* x = new int(); 0で初期化
int* x = new int(5); 初期化子5 を与えて 5で初期化


破棄
delete x;


int型配列オブジェクトの動的な生成

生成
int* x = new int[10]; 不定値で初期化
int* x = new int[10](); 全要素を 0で初期化


破棄
delete[] x;



新版明解C++入門編 p.279 演習7-15
 double型のオブジェクトを生成して 0.0 で初期化するプログラムを作成せよ。

// p279_演習7-15
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
double* d = new double(); // 0.0で初期化
cout << "*d = " << fixed << setprecision(1) << *d << '\n';
delete d;
}

b07_15.png




新版明解C++入門編 p.285 演習7-16
 double型の配列を動的に生成するプログラムを作成せよ。要素数はキーボードから読み込むこと。
また、生成に失敗した場合の処理も行うこと。

// p285_演習7-16
#include <new> // bad_allocの定義
#include <iostream>
using namespace std;

int main()
{
int asize;
double* a;

cout << "double型配列の要素数 : "; cin >> asize;
try {
a = new double[asize];
}
catch (bad_alloc) {
cout << "配列の生成に失敗!\n";
return 1;
}

for (int i = 0; i < asize; i++)
a[i] = i * 1.11;
for (int i = 0; i < asize; i++)
cout << "a[" << i << "] = " << a[i] << '\n';

delete[] a;
}

b07_161.png

b07_162.png




新版明解C++入門編 p.285 演習7-17
 ポインタ p が指すオブジェクトの先頭 nバイトに v を代入する関数 mem_set を作成せよ。
    void mem_set(void* p, int n, unsigned char v);

// p285_演習7-17
#include <iomanip>
#include <iostream>
using namespace std;

void mem_set(void* p, int n, unsigned char v) {
/*
void* p の部分は受け取る引数のポインタ型を選ばない。
(1), (2) では char*型のポインタをキャスト無しで受け取り、
(3), (4) では int*型のポインタをキャスト無しで受け取っている。

*/
char* q = (char*)p;
/*
void*型をchar*型に代入するときはキャストが必要。
*/
for (int i = 0; i < n; i++) {
*(q + i) = v;
}
}

int main()
{
/**/cout << "(1) ------------\n";
char abc[27]; // 26文字+'\0'
for (int i = 0; i < 26; i++)
abc[i] = char('a' + i);
abc[26] = '\0'; // 文字列の終端

cout << abc << '\n';
mem_set(abc, 10, '#');
cout << abc << '\n' << '\n';

/**/cout << "(2) ------------\n";
char ABC[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

cout << ABC << '\n';
mem_set(ABC, 10, 'z');
cout << ABC << '\n' << '\n';

/**/cout << "(3)------------\n";
int test1[] = { 1, 2 };
int size = sizeof(test1) / sizeof(test1[0]);

for (int i = 0; i < size; i++)
cout << setw(9) << test1[i] << " ";
cout << '\n';

mem_set(&test1, sizeof(int), char(0xFF));

for (int i = 0; i < size; i++)
cout << setw(9) << test1[i] << " ";
cout << '\n' << '\n';
/*
0x00000001( 1) が
0xFFFFFFFF( -1) になる。

*/

/**/cout << "(4) ------------\n";
int test2[] = { 1, 2, 3, 4 };
size = sizeof(test2) / sizeof(test2[0]);

for (int i = 0; i < size; i++)
cout << setw(9) << test2[i] << " ";
cout << '\n';

mem_set(&test2, sizeof(int) * 2, char(0x00));

for (int i = 0; i < size; i++)
cout << setw(9) << test2[i] << " ";
cout << '\n' << '\n';
/*
0x00000001( 1) 0x00000002( 2) が
0x00000000( 0) 0x00000000( 0) になる。

*/

/**/cout << "(5) ------------\n";
int test3[] = {1, 2, 3};
size = sizeof(test3) / sizeof(test3[0]);

for (int i = 0; i < size; i++)
cout << setw(9) << test3[i] << " ";
cout << '\n';

mem_set(&test3, sizeof(int) * 2, char(1));

for (int i = 0; i < size; i++)
cout << setw(9) << test3[i] << " ";
cout << '\n';
/*
0x00000001( 1) 0x00000002( 2) が
0x01010101(16843009) 0x01010101(16843009) になる。

*/
}

b07_17_.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

2017年09月26日

《その51》 線形探索(p.275演習7-14)


新版明解C++入門編 p.275 演習7-14
 要素数n の配列 a内の keyと等しい全要素の添字を配列 idxに格納する関数 search_idxを作成せよ。
返却するのは key と等しい要素の個数とする。
    int search_idx(int* a, int* idx, int n, int key);
 たとえば、a に受け取った配列の要素が {1, 7, 5, 7, 2, 4, 7} で key が 7であれば、idx に
{1, 3, 6} を格納した上で 3を返却する。

// p275_演習7-14
#include <iostream>
using namespace std;

int search_idx(int* a, int* idx, int n, int key)
{
int n_match = 0; // n_match … keyと等しい要素の個数
for (int i = 0; i < n; i++)
if (a[i] == key) {
idx[n_match++] = i;
}
return n_match;
}

int main()
{
const int n = 10;
int a[n], idx[n]; // 配列idxの要素数は最大でn個。
int key;

for (int i = 0; i < n; i++) {
cout << "a[" << i << "] : "; cin >> a[i];
idx[i] = -1; // 配列idxの全要素を -1にする。
}

cout << "配列a = {";
for (int i = 0; i < n - 1; i++)
cout << a[i] << ", ";
cout << a[n - 1] << "}\n";

cout << "key : "; cin >> key;
int num = search_idx(a, idx, n, key);

cout << "keyと等しい要素の数 … " << num << '\n';

cout << "idx = {";
for (int i = 0; i < n - 1; i++)
cout << idx[i] << ", ";
cout << idx[n - 1] << "}\n";

cout << "\n------------------------------------\n\n";
/*
演習7-14 のプログラムは以上です。

以下は、p.280「配列オブジェクトの動的生成」の内容を使って
配列idxを改良したコードです。

改良後の配列idx_2 の要素数は、格納する添字の個数とピッタリ
同じになっています。

*/
int* idx_2 = new int[num]; // 配列領域を確保

for (int i = 0; i < num; i++)
idx_2[i] = idx[i];

cout << "idx_2 = {";
for (int i = 0; i < num - 1; i++)
cout << idx_2[i] << ", ";
cout << idx_2[num - 1] << "}\n";

delete [] idx_2; // 確保領域を解放

}

b07_14.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

《その50》 ポインタと配列


ポインターと配列

ちょっと理解がこんがらがってきたような気がするので、再確認してみました。


#include <iostream>
using namespace std;

int main()
{
int a[5] = { 10, 20, 30, 40, 50 };
int* p = a;

cout << " p *p\n";
cout << "-----------\n";
for (int i = 0; i < 5; i++) {
cout << p << " ";
cout << *p++ << '\n';
}
cout << "※ cout << *p++; の繰り返しで配列要素を順に表示することができる。\n\n\n";

cout << "p … " << p << '\n';
cout << "a … " << a << '\n';
cout << "p - a … " << p - a << '\n';
cout << "※ (ポインタの差) = (配列要素の添字の差)\n";
cout << " となる仕様になっている。\n\n";

cout << "a + 2 … " << a + 2 << '\n';
cout << "※ (ポインタ + n) = (n個だけ後の配列要素を指すポインタ)\n";
cout << " となる仕様になっている。\n\n";
}

b07_00000.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

2017年09月25日

《その49》 ポインタによる配列要素の走査(p.270演習7-12,演習7-13)


★このブログでは、新版 明解C++ 入門編(SB Creative 株式会社)に沿って、
 初歩から C++ の学習を進めていきます。
★ソースプログラムのコンパイルには、Visual Studio Community 2017 を利用しています。
 Visual Studio Community 2017 の使い方については、このブログの《その1》〜《その6》をご覧ください。



新版明解C++入門編 p.270 演習7-12
 要素数n の配列 p の全要素に v を代入する関数 fill を作成せよ。
    void fill(int* p, int n, int v);

// p270_演習7-12
#include <iostream>
using namespace std;

void fill(int* p, int n, int v)
{
while (n-- > 0) {
*p++ = v;
}
}

int main(void)
{
int x[5] = {1, 2, 3, 4, 5};
int x_size = sizeof(x) / sizeof(x[0]);
int v;

for (int i = 0; i < x_size; i++)
cout << "x[" << i << "] = " << x[i] << '\n';

cout << "整数値 : "; cin >> v;
fill(x, x_size, v);

for (int i = 0; i < x_size; i++)
cout << "x[" << i << "] = " << x[i] << '\n';
}

b07_12.png




新版明解C++入門編 p.270 演習7-13
 要素数が n である配列 b の全要素を配列 a にコピーする関数を作成せよ。
    void ary_cpy(int* a, const int* b, int n);


// p270_演習7-13
#include <iostream>

using namespace std;

void ary_cpy(int* a, const int* b, int n)
{
while (n-- > 0) {
*a++ = *b++;
}
}

int main(void)
{
const int n = 6;
int p[n], q[n];

for (int i = 0; i < n; i++) {
q[i] = i * i;
cout << "q[" << i << "] = " << q[i] << '\n';
}

ary_cpy(p, q, n);

for (int i = 0; i < n; i++) {
cout << "p[" << i << "] = " << p[i] << '\n';
}
}

b07_13.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

《その48》 ポインタと配列(p.266演習7-4,演習7-5,p.267演習7-6,演習7-7,演習7-8,演習7-9,演習7-10,演習7-11)


新版明解C++入門編 p.266 演習7-4
 typeid演算子を用いて型を表示することによって、List 7-10(p.260)の関数 reverse の仮引数a が配列でなくポインタであることを確認せよ。

// p266_演習7-4
#include <iostream>
#include <typeinfo>
using namespace std;

void reverse(int a[], int n)
{
cout << "aの型:" << typeid(a).name() << '\n';
// ・・・・・・
}

int main()
{
const int n = 5;
int c[n];
// ・・・・・・
reverse(c, n);
// ・・・・・・
}

b07_04.png




新版明解C++入門編 p.266 演習7-5
 List 7-10(p.260)の関数 reverse での2要素の交換を、演習7-2(p.253)で作成した関数 swap の呼出しによって行うように変更したプログラムを作成せよ。

// p266_演習7-5
#include <iostream>
using namespace std;

void swap(int* x, int* y)
{
int t = *x;
*x = *y;
*y = t;
}

void reverse(int* a, int n)
{
for (int i = 0; i < n / 2; i++)
swap(&a[i], &a[n - i - 1]);
}

int main()
{
const int n = 5;
int c[n];

for (int i = 0; i < n; i++) {
cout << "c[" << i << "] : "; cin >> c[i];
}

reverse(c, n);

cout << "------\n";
for (int i = 0; i < n; i++)
cout << "c[" << i << "] = " << c[i] << '\n';
}

b07_05.png




新版明解C++入門編 p.267 演習7-6
 要素数n の配列 a の全要素の合計を求めて返却する関数 sum_of を作成せよ。
    int sum_of(const int a[], int n);


// p267_演習7-6
#include <iostream>
using namespace std;

int sum_of(const int a[], int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
sum += a[i];
return sum;
}

int main()
{
const int n = 5;
int a[n];
cout << "整数値を " << n << "個入力\n";
for (int i = 0; i< n; i++) {
cout << "a[" << i << "] = "; cin >> a[i];
}

cout << "値の合計 : " << sum_of(a, n) << '\n';
}

b07_06.png




新版明解C++入門編 p.267 演習7-7
 要素数 n の配列 a から要素 a[idx] を削除する関数 aryrmv を作成せよ。
    void aryrmv(int a[], int n, int idx);
 削除は a[idx] より後方の全要素を一つ前方にずらすことによって行う。移動されずにあまってしまう末尾要素 a[n - 1] の値は変更しなくてもよい。たとえば、配列 a の要素が {1, 3, 4, 7, 9, 11} のときに aryrmv(a, 6, 2) と呼び出した後の配列 a の要素は {1, 3, 7, 9, 11, 11} となる。

// p267_演習7-7
#include <iostream>
#include <iomanip>
using namespace std;

void aryrmv(int a[], int n, int idx)
{
for (int i = idx - 1; i < n - 1; i++)
a[i] = a[i + 1];
}

int main()
{
int array[8] = { -2, 50, 23, -8, 1, 3, 4, 17 };
for (int i = 0; i < 8; i++)
cout << setw(4) << array[i];
cout << '\n';
int m;
do {
cout << "何番目を消去(1〜7を入力)? "; cin >> m;
} while (m < 1 || m > 7);

aryrmv(array, 8, m);

for (int i = 0; i < 8; i++)
cout << setw(4) << array[i];
cout << '\n';
}

b07_07.png




新版明解C++入門編 p.267 演習7-8
 要素数 n の配列 a から要素 a[idx] を先頭とする k個の要素を削除する関数 arynrmv を作成せよ。
    void arynrmv(int a[], int n, int idx, int k);
 削除は a[idx] より後方の全要素を k個前方にずらすことによって行うこと。なお、移動されずにあまってしまう要素の値は変更しなくてよい。

// p267_演習7-8
#include <iostream>
#include <iomanip>
using namespace std;

void arynrmv(int a[], int n, int idx, int k)
{
for (int i = idx - 1; i < n; i++) {
if (i + k < n)
a[i] = a[ i + k];
// else // ☆
// a[i] = 0; // ☆

}
}

int main()
{
int array[8] = {-2, 50, 23, -8, 1, 3, 4, 17};
for (int i = 0; i < 8; i++)
cout << setw(4) << array[i];
cout << '\n';
int idx, k;
int f = 0;
do {
if (f++ > 0)
cout << "入力値が不正!\n";
cout << "何番目(1〜8)から何個消去するかを入力\n";
cout << "何番目から? "; cin >> idx;
cout << "何個を消去? "; cin >> k;
} while (idx < 1 || idx > 8 || k < 0 || idx + k > 9);

arynrmv(array, 8, idx, k);

for (int i = 0; i < 8; i++)
cout << setw(4) << array[i];
cout << '\n';
}

3番目から1個を消去(演習7-7 と同じ結果になります。)
b07_0801.png

5番目から2個を消去
b07_0802.png

5番目から4個を消去
 この場合は後方に要素がないので、問題の指示通りの仕様では、最終的な数字の並びが最初と同じになってしまいます。

b07_0803.png


上のプログラムのピンク色の部分のコメントアウトを外すと、後方からずれてくる要素が足りない場合は 0になるので、そのほうが自然な気がします。
以下の2画像は、ピンク色の部分のコメントアウトを外して実行した結果です。

b07_0811.png

b07_0812.png




新版明解C++入門編 p.267 演習7-9
 要素数 n の配列 a の要素 a[idx] に x を挿入する関数 aryins を作成せよ。
    void aryins(int a[], int n, int idx, int k);
 挿入に伴って a[idx] 〜 a[n-2] を一つ後方にずらさなければならない。
たとえば、配列 a の要素が {1, 3, 4, 7, 9, 11} のときに aryins(a, 6, 2, 99) と呼び出した後
の配列 a の要素は {1, 3, 99, 4, 7, 9} となる。

// p267_演習7-9
#include <iostream>
#include <iomanip>
using namespace std;

void aryins(int a[], int n, int idx, int x)
{
for (int i = n - 1; i > idx - 1; i--)
a[i] = a[i - 1];
a[idx - 1] = x;
}

int main()
{
int array[6] = { 1, 3, 4, 7, 9 ,11 };
for (int i = 0; i < 6; i++)
cout << setw(4) << array[i];
cout << '\n';
int idx, x;
do {
cout << "何番目(1〜6)にどんな整数を挿入するかを入力\n";
cout << "何番目に? "; cin >> idx;
cout << "整数値は? "; cin >> x;
} while (idx < 1 || idx > 6);

aryins(array, 6, idx, x);

for (int i = 0; i < 6; i++)
cout << setw(4) << array[i];
cout << '\n';
}

b07_09.png




新版明解C++入門編 p.267 演習7-10
 n行5列の int型2次元配列 a の各行の最大値を、要素数 n の 1次元配列 m に格納する関数 maxline を作成せよ。
    void maxline(int a[][5], int m[], int n);
たとえば、aに受け取った 3行5列の配列の構成要素が
{ {1, 2, 5, 4, 8}, {6, 7, 4, 2, 3}, {3, 0, 5, 9, 1} } であれば、mに {8, 7, 9} を格納すること。

// p267_演習7-10
#include <iostream>
#include <iomanip>
using namespace std;

void maxline(int a[][5], int m[], int n)
{
for (int i = 0; i < n; i++) {
int max = a[i][0];
for (int j = 1; j < 5; j++)
if (max < a[i][j])
max = a[i][j];
m[i] = max;
}
}

int main()
{
const int row = 4;

int array[row][5] = {
{ 11, 2, 5, 4, 8 },
{ 6, 17, 4, 2, 3 },
{ 3, 0, 5, 7, 6 },
{ 0, 1, 26, 2, 1 },
};
int m[row];
for (int i = 0; i < row; i++) {
for (int j = 0; j < 5; j++)
cout << setw(3) << array[i][j];
cout << '\n';
}
cout << '\n';

maxline(array, m, row);

for (int i = 0; i < row; i++) {
cout << "m[" << i << "] … " << setw(3) << m[i];
cout << '\n';
}
}

b07_10.png




新版明解C++入門編 p.267 演習7-11
 n行5列の int型2次元配列 a の全構成要素の値を縦横に並べて表示する関数 print2d を作成せよ。
    void print2d(int a[][5], int n);
 各構成要素がどのような値であっても、各列の数値の先頭(左端)がそろうように、最低限のスペースを空けること。

// p267_演習7-11
#include <iostream>
#include <iomanip>
using namespace std;

int digits(int n) // 整数の桁数(マイナス記号を含む)を返す。
{
int dgts = 0; // 桁数
int negative_number = 0; // 正なら桁数に1を加えない。
if (n < 0) {
negative_number = 1; // 負なら桁数に"-"の分として1を加える。
n = -n;
}
do {
dgts++;
n /= 10;
} while (n >= 1);

return dgts + negative_number;
}

void print2d(int a[][5], int n)
{
int dgts[5];
for (int j = 0; j < 5; j++) {
int min = a[0][j];
int max = a[0][j];
for (int i = 1; i < n; i++) {
if (min > a[i][j])
min = a[i][j];
if (max < a[i][j])
max = a[i][j];
}
dgts[j] = digits(max) > digits(min) ? digits(max) : digits(min);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < 5; j++)
cout << setw(dgts[j] + 1) << left << a[i][j];
// ↑ 第j列の幅を確保
// "-"の分も考慮した桁数に1を加えた幅
cout << '\n';
}
}

int main()
{
const int rows = 5;

int array[rows][5] = {
{ 32 , -1, 32, 45, 67 },
{ 535, 0, 2, 128, -127 },
{ 2 , 5, -123, 9, 5 },
{ 1 , 2, 3, -12345, -1 },
{ 2 , 5, -123, 9, 12345 },
};

print2d(array, rows);
cout << '\n';
}

b07_11.png

新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/8/30 21:02時点)









--

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2017年09月 >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。