diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 8a92df73..aa2356b6 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -137,32 +137,119 @@ export default withMermaid({ ], }, { - text: "[WIP] 6. 繰り返し処理", + text: "6. 繰り返し処理", link: "/cpp/chapter-6/", items: [ - { text: "[WIP] 6.1 for文", link: "/cpp/chapter-6/1" }, - { text: "[WIP] 6.2 while文", link: "/cpp/chapter-6/2" }, - { text: "[WIP] 6.3 配列", link: "/cpp/chapter-6/3" }, - { text: "[WIP] 6.4 string型②とchar型", link: "/cpp/chapter-6/4" }, - { text: "[WIP] 6.5 continueとbreak", link: "/cpp/chapter-6/5" }, + { text: "6.1 for文", link: "/cpp/chapter-6/1" }, + { text: "6.2 while文", link: "/cpp/chapter-6/2" }, + { text: "6.3 配列", link: "/cpp/chapter-6/3" }, + { text: "6.4 string型②とchar型", link: "/cpp/chapter-6/4" }, + { text: "6.5 breakとcontinue", link: "/cpp/chapter-6/5" }, + { + text: "6.Q 練習問題", + link: "/cpp/chapter-6/problems/", + collapsed: true, + items: [ + { + text: "Count Down(★☆☆)", + link: "/cpp/chapter-6/problems/count-down", + }, + { + text: "Even Numbers in Range(★☆☆)", + link: "/cpp/chapter-6/problems/even-number-in-range", + }, + { + text: "DO NOT FAIL(★☆☆)", + link: "/cpp/chapter-6/problems/do-not-fail", + }, + { + text: "lower or UPPER(★☆☆)", + link: "/cpp/chapter-6/problems/lower-or-upper", + }, + { + text: "Prime Check(★★☆)", + link: "/cpp/chapter-6/problems/prime-check", + }, + { + text: "Fibonatti(★★☆)", + link: "/cpp/chapter-6/problems/fibonatti", + }, + + { + text: "fizz-buzz 2D(★★★)", + link: "/cpp/chapter-6/problems/fizz-buzz-2d", + }, + ], + }, ], }, { - text: "[WIP] 7. 関数", + text: "7. 関数", link: "/cpp/chapter-7/", items: [ - { text: "[WIP] 7.1 関数とは", link: "/cpp/chapter-7/1" }, - { text: "[WIP] 7.2 引数", link: "/cpp/chapter-7/2" }, - { text: "[WIP] 7.3 返り値", link: "/cpp/chapter-7/3" }, - { text: "[WIP] 7.4 [発展] 参照渡し", link: "/cpp/chapter-7/4" }, + { text: "7.1 関数とは", link: "/cpp/chapter-7/1" }, + { text: "7.2 引数", link: "/cpp/chapter-7/2" }, + { text: "7.3 返り値", link: "/cpp/chapter-7/3" }, + { text: "7.4 [発展] 参照渡し", link: "/cpp/chapter-7/4" }, + { + text: "7.Q 練習問題", + link: "/cpp/chapter-7/problems/", + collapsed: true, + items: [ + { + text: "Max of Three(★☆☆)", + link: "/cpp/chapter-7/problems/max-of-three", + }, + { + text: "Swap Two Numbers(★★☆)", + link: "/cpp/chapter-7/problems/swap-two", + }, + ], + }, ], }, { - text: "[WIP] 8. 構造体", + text: "8. 構造体", link: "/cpp/chapter-8/", items: [ - { text: "[WIP] 8.1 構造体とは", link: "/cpp/chapter-8/1" }, - { text: "[WIP] 8.2 メソッド", link: "/cpp/chapter-8/2" }, + { text: "8.1 構造体とは", link: "/cpp/chapter-8/1" }, + { text: "8.2 メソッド", link: "/cpp/chapter-8/2" }, + { + text: "8.Q 練習問題", + link: "/cpp/chapter-8/problems/", + collapsed: true, + items: [ + { + text: "Order(★★☆)", + link: "/cpp/chapter-8/problems/order", + }, + ], + }, + ], + }, + { + text: "(2025年度版テキスト)
VIII. 発展事項 (WIP)", + link: "/text/chapter-8/", + items: [ + { text: "計算量とオーダー", link: "/text/chapter-8/complexity" }, + { text: "再帰関数", link: "/text/chapter-8/recursive-function" }, + { text: "実行時間", link: "/text/chapter-8/exec-time" }, + { text: "カプセル化", link: "/text/chapter-8/capsule" }, + { + text: "練習問題", + link: "/text/chapter-8/practice/", + collapsed: true, + items: [ + { + text: "Capsulated Zer0-Star", + link: "/text/chapter-8/practice/capsulate-user", + }, + { + text: "Exponentation", + link: "/text/chapter-8/practice/exponentation", + }, + ], + }, ], }, { @@ -172,7 +259,7 @@ export default withMermaid({ ], "/text/": [ { - text: "[WIP] 2026年度版テキスト", + text: "2026年度版テキスト", link: "/cpp/preface/", }, { diff --git a/docs/cpp/chapter-6/1.md b/docs/cpp/chapter-6/1.md index 5664c18e..d0b3fcb4 100644 --- a/docs/cpp/chapter-6/1.md +++ b/docs/cpp/chapter-6/1.md @@ -1,6 +1,9 @@ -# [WIP] 6.1 for文 +# 6.1 for文 + +## 6.1.1 for文の基本 + +繰り返しの処理には**for文**と呼ばれる構文を用いる。for文は以下のように記述できる。 -繰り返しの処理 `for` は以下のように記述する。 ```cpp:line-numbers for (int i=0; i<5; i++) { @@ -8,8 +11,9 @@ for (int i=0; i<5; i++) { } ``` -``` -[output] +このプログラムの出力は以下のようになる。 + +```Output:line-numbers 0 1 2 @@ -17,13 +21,13 @@ for (int i=0; i<5; i++) { 4 ``` -新しい演算`++` が出ているが、これは **変数の値を1増やす** という演算である。 `i = i+1;` と同値。 +コードの中に`i++`と書かれている部分がある。これは**変数iの値を1増やす**演算(インクリメント)であり、`i = i+1;`と同値である。 -for 文がどのように動作しているかを解説すると、`for` の後に `;` 区切りで 3 つ情報を指定している。 +for文がどのように動作しているかを解説する。for文は、`for`の後に`;`区切りで3つの情報を指定している。 -```cpp +```cpp:line-numbers for ([初期化];[条件];[継続処理]) { - [実行文] + [実行文] } ``` @@ -49,4 +53,68 @@ flowchart LR cond --> |No| e["End"] ``` -つまり、0,1,2,3,4 の整数を出力するプログラムである。これを使えば、例えば $7^4$ 等がプログラムで計算できる。 +つまり、0, 1, 2, 3, 4の整数を出力するプログラムである。したがって、以下のようなコードも、上のコードと全く同じ出力となる。 + +```cpp:line-numbers +for (int i=1; i<=5; i++) { + cout << i-1 << endl; +} +``` + +```cpp:line-numbers +for (int count=10; count<15; count++) { + cout << count-10 << endl; +} +``` + +```cpp:line-numbers +for (int num=0; num<10; num+=2) { + cout << num/2 << endl; +} +``` + +```cpp:line-numbers +for (int x=5; x>0; x--) { + cout << 5-x << endl; +} +``` + +`i--`は`i -= 1`や`i = i-1`と同じ意味であり、デクリメントと呼ばれる。 + +for文において、初期化で定義した変数のスコープはそのfor文内となる。 + +for文の初期化は省略することもできる。以下は初期化を省略した例である。この例では、変数`i`をfor文の外でも使うことができる。 + +```cpp:line-numbers +int i = 0; +for (; i<5; i++) { + cout << i << endl; +} +``` + +for文を使えば、階乗や累乗なども計算できる。 + +## 6.1.2 多重ループ + +for文の中にfor文を入れ子にすることもできる。以下は2重ループの例である。 + +```cpp:line-numbers +for (int i=0; i<2; i++) { + for (int j=0; j<3; j++) { + cout << i << " " << j << endl; + } +} +``` + +```Output:line-numbers +0 0 +0 1 +0 2 +1 0 +1 1 +1 2 +``` + +外側のfor文と内側のfor文で、繰り返しに使う変数名を同じにしてしまわないよう、注意しよう。繰り返しに使う変数には、`i`が使われることが多い。また、多重ループでは、`i`, `j`, `k`...と続けていくが多い。しかし、これらはあくまでも慣習的なものであり、必ずしも従わなければいけない、というわけではない。変数名は自由につけることができる。 + + diff --git a/docs/cpp/chapter-6/2.md b/docs/cpp/chapter-6/2.md index 9a192e62..f4ea23a5 100644 --- a/docs/cpp/chapter-6/2.md +++ b/docs/cpp/chapter-6/2.md @@ -1,4 +1,8 @@ -# [WIP] 6.2 while文 +# 6.2 while文 + +## 6.2.1 while文とは + +**条件を満たすまで**処理を繰り返したい、というときには`while`文を用いる。while文は、`while`の後にある`()`内の条件文が、真の間実行される繰り返し処理である。 ```cpp:line-numbers int a = 10; @@ -8,9 +12,7 @@ while (a > 0) { } ``` -while文は、 `while` の中の条件文が真の間実行される繰り返し処理。 - -上記のコードだと、 10,9,8,7,6,5,4,3,2,1 と順に出力される。 +上記のコードだと、10,9,8,7,6,5,4,3,2,1と順に出力される。 ```mermaid flowchart LR diff --git a/docs/cpp/chapter-6/3.md b/docs/cpp/chapter-6/3.md index b714850e..a0957a19 100644 --- a/docs/cpp/chapter-6/3.md +++ b/docs/cpp/chapter-6/3.md @@ -1,10 +1,10 @@ -# [WIP] 6.3 配列 +# 6.3 配列 -プログラミングでは、同じ様な変数を複数作りたいときがある。例えば、100人の点数の平均点を取りたい時に変数は100個必要となる。このときに、配列を使う。 +## 6.3.1 配列の基本 -配列とは、変数の集合のようなものである。 +プログラミングでは、同じような変数を複数作りたいときがある。例えば、100人の点数の平均点を取りたいときには変数は100個必要となる。このときに、配列を使う。配列とは、変数の集合のようなものである。 -C++ において配列を使う時は、`vector` を用いる。`string` と同様にして、`vector`をインクルードする。 +C++において配列を使う時は、`vector`を用いる。**`string`と同様に、`vector`をインクルードする必要がある。** ```cpp:line-numbers #include @@ -17,14 +17,13 @@ vector array; vector strarray; ``` -このように記述すると空の配列が作成される。以下のように、初めから配列に値を入れることもできる +このように記述すると空の配列が作成される。以下のように、初めから配列に値を入れることもできる。 ```cpp:line-numbers vector arr = {10, 20, 30, 40, 50}; ``` -以下のように、 `[]` の中に数字を書くことで要素を取得できる。数列を考えた時の $a_i$ の $i$ だと思うと良い。この時要素番号は* -*0始まり**である。 +以下のように、`[]`の中に数字を書くことで要素を取得できる。数列を考えた時の$a_i$の$i$だと思うと良い。このとき、要素番号は**0始まり**である。 ```cpp:line-numbers vector arr = {10, 20, 30, 40, 50}; @@ -33,26 +32,27 @@ arr[1] = 100; cout << arr[1] << endl; ``` -``` -[output] +```Output:line-numbers 30 100 ``` -`.size()` とすると、配列の要素数を調べることができる。 +## 6.3.2 size + +`.size()`とすると、配列の要素数を調べることができる。 ```cpp:line-numbers vector arr = {10, 20, 30, 40, 50}; -int siz = arr.size(); -cout << siz << endl; +cout << arr.size() << endl; ``` -``` -[output] +このコードの出力は以下のようになる。 + +```Output:line-numbers 5 ``` -これと、`for` を用いれば、配列の要素を全て取得することができる。 +`.size()`と`for`を用いれば、配列の要素をすべて取得することができる。 ```cpp:line-numbers vector arr = {10, 20, 30, 40, 50}; @@ -61,10 +61,11 @@ for (int i=0; i < arr.size(); i++) { } ``` -`for` 文の中で、 `arr[0]` から `arr[4]` までが1つずつ出力されるコードだという事が理解できるだろうか。`i < arr.size()` -の条件から、`i` は 0 から 4 までの場合で実行される。(5 は `5 < 5` となり条件を満たさない。) +`for`文の中で、`arr[0]`から`arr[4]`までが1つずつ出力されるコードだという事が理解できるだろうか。`i < arr.size()`の条件から、`i`は0から4までの場合で実行される。(5は`5 < 5`となり条件を満たさない。) + +## 6.3.3 push_back -`.push_back()` を用いると、配列の末尾に新しい要素を追加することができる。 +`.push_back()`を用いると、配列の末尾に新しい要素を追加することができる。 ```cpp:line-numbers vector arr = {10, 20, 30, 40, 50}; @@ -74,11 +75,25 @@ cout << arr[5] << endl; cout << arr.size() << endl; ``` -``` -[output] +このコードの出力は以下のようになる。 + +```Output:line-numbers -10 6 ``` -for文と組み合わせると、できる事が非常に広がる。 +for文と組み合わせると、できることが非常に広がる。 + +## 6.3.4 多次元配列 + +配列の中に配列を入れ子にすることで多次元配列を作ることができる。 +以下は2次元配列の例である。(オセロ盤みたいなイメージ) + +```cpp:line-numbers +vector> v = { + {1, 2, 3, 4}, + {3, 5, 1, 2}, + {10, 20, 10, 20}, +}; +``` diff --git a/docs/cpp/chapter-6/4.md b/docs/cpp/chapter-6/4.md index ee7c0f11..7ef5ee63 100644 --- a/docs/cpp/chapter-6/4.md +++ b/docs/cpp/chapter-6/4.md @@ -1,10 +1,12 @@ -# [WIP] 6.4 string型②とchar型 +# 6.4 string型②とchar型 -string は、実際には文字の配列であると捉えると、文字列に対する操作を行うことができる。 +## 6.4.1 string型と配列 + +string型は、実際には文字の配列であると捉えると、文字列に対する操作を行うことができる。 一度、アルファベットと数字・一部の記号だけ、いわゆる「**1バイト文字**」のみで考えよう。ひらがなやカタカナについては後で説明する。 -:::warning +::: danger ひらがな・カタカナ・漢字などの文字を使うと、以下の説明が成り立たなくなってしまうことがある。 ::: @@ -13,44 +15,55 @@ string は、実際には文字の配列であると捉えると、文字列に ```cpp:line-numbers string s = "traP"; cout << s.size() << endl; // 配列と捉えて配列の要素数を取得する。 -cout << s.length() << endl; // length() によって文字列の長さを取得する +cout << s.length() << endl; // length()によって文字列の長さを取得する for (int i=0; i + ここで、アルファベットは順番に並んでいるという事実は覚えておくと良い。 -逆に、char に数値を代入によって文字を代入することもできる。 +逆に、charに数値を代入によって文字を代入することもできる。 ```cpp:line-numbers char c = 81; cout << c << endl; // output: Q ``` -## 6.4.4. 文字の比較 +## 6.4.5 文字の比較 -4.4.3. によれば、1文字1文字は、実際は数値として扱われているのであった。よって、数値と同じように扱えるということは、以下のように比較できるということである。 +6.4.4によれば、1文字1文字は、実際は数値として扱われているのであった。よって、数値と同じように扱えるということは、以下のように比較できるということである。 ```cpp:line-numbers cout << ('A' < 'B') << endl; ``` ここで、アルファベットはASCIIコード上で順番に並んでいるということを思い返すと、 -`('A' <= x && x <= 'Z')` で「文字$x$が大文字アルファベットかどうか」が判定できる。 -更にこれと for 文をうまく使えば、(アルファベットの)辞書順でどちらが先かを実装することができるだろう。 +`('A' <= x && x <= 'Z')`で「文字$x$が大文字アルファベットかどうか」が判定できる。 +更にこれとfor文をうまく使えば、(アルファベットの)辞書順でどちらが先かを実装することができるだろう。 ::: tip -実際には、文字列の辞書順で先かどうかは、`<` `>` の不等号演算子で簡単に実装できる。 +実際には、文字列の辞書順で先かどうかは、`<`や`>`の不等号演算子で簡単に実装できる。 ```cpp:line-numbers string s = "Hello"; @@ -90,28 +104,22 @@ string t = "Bello"; cout << (s < t) << endl; ``` -``` -[output] +```Output:line-numbers 0 ``` -string 型同士で比較するときに、1文字目を比較→同じなら2文字目を比較→… という処理を行って比較されている。 +string型同士で比較するときに、1文字目を比較→同じなら2文字目を比較→…という処理を行って比較されている。 ::: -## 6.4.5. マルチバイト文字 - -::: tip -完全なおまけセクションです。講習の進行状況次第で飛ばします… -::: +## 6.4.6 マルチバイト文字 ところで、ASCIIコード表には日本語特有の文字(ひらがな・カタカナ・漢字)が存在しないことに気づくだろうか。 -これは1バイトで扱える情報が 256 通りしかないから、日本語は1バイトだけでは扱うことができない。 +これは1バイトで扱える情報が256通りしかないから、日本語は1バイトだけでは扱うことができない。 それゆえ、日本語(ひらがなカタカナ等)はマルチバイト文字で表現されている(複数バイトで1文字を表す方式)。 -ここで、`char` 型は、正確には「1バイトの整数型」である。よって、`char` -型ではひらがな等の字を扱うことができない。実際に試してみると、5文字なのに長さは15と表示されてしまうし、1文字目を出力してみようと思ってもうまく出力されない。例えば「こ」の場合は、3文字出力してようやく「こ」が表示されるのである。 +ここで、`char`型は、正確には「1バイトの整数型」である。よって、`char`型ではひらがな等の字を扱うことができない。実際に試してみると、5文字なのに長さは15と表示されてしまうし、1文字目を出力してみようと思ってもうまく出力されない。例えば「こ」の場合は、3文字出力してようやく「こ」が表示されるのである。 ```cpp:line-numbers string dame = "こんにちは"; @@ -120,38 +128,31 @@ cout << dame[0] << endl; cout << dame[0] << dame[1] << dame[2] << endl; ``` -``` -[output] +```Output:line-numbers 15 � こ ``` 多バイト文字を扱える型も存在するが、非常に扱いが面倒なのでここでは扱わない。 -C++ 以外の言語でも大体は文字列を扱えるが、マルチバイト文字に対する扱いは言語によってまちまちだったりするので、よく調べること。 - -::: tip +C++以外の言語でも大体は文字列を扱えるが、マルチバイト文字に対する扱いは言語によってまちまちだったりするので、よく調べること。 -### 6.4.5.1. 文字化け +::: tip 文字化け ここで横道に逸れてしまうが、せっかくの機会なので「文字化け」についても触れておこう。 **歴史的な経緯** -ASCII では日本語文字を扱えないのは明らかだったので、1文字で2バイトを使う文字コード体系が考案された。2バイトであれば -$2^{16}=65536$ 文字を扱えるので、これだけあれば十分だという事である。 +ASCIIでは日本語文字を扱えないのは明らかだったので、1文字で2バイトを使う文字コード体系が考案された。2バイトであれば +$2^{16}=65536$文字を扱えるので、これだけあれば十分だという事である。 しかし、結果としては国内で文字コードが乱立し(Shift-JIS, EUC-JP -等…)、様々衝突するようになった上、国内にとどまらず各国で独自の文字コードが作成されてしまい、混乱を極めてしまったのである(ASCII -で表せないのは日本語だけではなく、アラビア文字・簡体字・ギリシャ文字など様々…)。 +等…)、様々衝突するようになった上、国内にとどまらず各国で独自の文字コードが作成されてしまい、混乱を極めてしまったのである(ASCIIで表せないのは日本語だけではなく、アラビア文字・簡体字・ギリシャ文字など様々…)。 -最終的には、世界の全文字を扱う文字コードとして Unicode (≒ UTF-8) -が策定され、今日ではこれが普及している。しかし完全に普及している訳でもなく、よって、今日見かける文字化けはもっぱら「UTF-8 か -UTF-8 以外か」の文字コードを使って発生しているパターンである。 +最終的には、世界の全文字を扱う文字コードとしてUnicode(≒ UTF-8)が策定され、今日ではこれが普及している。しかし完全に普及している訳でもなく、よって、今日見かける文字化けはもっぱら「UTF-8かUTF-8以外か」の文字コードを使って発生しているパターンである。 -**CJK 問題** +**CJK問題** -また、日本語の漢字が中国語のフォントで表示されている、という謎の現象に遭遇したこともあるかもしれない。これは、Unicode -を制定した際に日本語・中国語(簡体字・繁体字)・韓国語の漢字について、似ている漢字を全て一緒くたにしてしまった事が原因である。 → [Your Code Displays Japanese Wrong](https://heistak.github.io/your-code-displays-japanese-wrong/) +また、日本語の漢字が中国語のフォントで表示されている、という謎の現象に遭遇したこともあるかもしれない。これは、Unicodeを制定した際に日本語・中国語(簡体字・繁体字)・韓国語の漢字について、似ている漢字を全て一緒くたにしてしまった事が原因である。 → [Your Code Displays Japanese Wrong](https://heistak.github.io/your-code-displays-japanese-wrong/) **横道** @@ -160,7 +161,5 @@ UTF-8 以外か」の文字コードを使って発生しているパターン ::: ::: tip -`int` 型は 4バイトの整数型である。扱える情報は $2^{32}$ で、整数は負と正の値を取るから非負整数の部分にに $2^{31}$ -個を割り当てる。$2^{31}=2147483648 -$ なのだが、実はこの値は既にテキストで一度出現している。さてどこだろうか? +`int`型は4バイトの整数型である。扱える情報は$2^{32}$で、整数は負と正の値を取るから非負整数の部分に$2^{31}$個を割り当てる。$2^{31}=2147483648$なのだが、実はこの値は既にテキストで一度出現している。さてどこだろうか? ::: diff --git a/docs/cpp/chapter-6/5.md b/docs/cpp/chapter-6/5.md index 531f1e2c..ba51476f 100644 --- a/docs/cpp/chapter-6/5.md +++ b/docs/cpp/chapter-6/5.md @@ -1,8 +1,8 @@ -# [WIP] 6.5 continueとbreak +# 6.5 breakとcontinue -## 6.5.1. break +## 6.5.1 break -for文・while 文はbreakを用いて途中で終了して抜け出すことができる。 +for文・while文は`break`を用いて途中で終了して抜け出すことができる。 ```cpp:line-numbers vector v = {1, 4, 0, 6, 10}; @@ -15,8 +15,7 @@ for (int i=0; i |No| e["End"] ``` -## 6.5.2. continue +## 6.5.2 continue -continueを用いると、ループの現在のステップを飛ばして、次のステップに進むことができる。 +`continue`を用いると、ループの現在のステップを飛ばして、次のステップに進むことができる。 ```cpp:line-numbers vector v = {1, 4, 0, 6, 10}; @@ -61,41 +60,3 @@ flowchart LR end cond --> |No| e["End"] ``` - -## 6.5.3. 多重ループ - -```cpp:line-numbers -for (int i=0; i<2; i++) { - for (int j=0; j<3; j++) { - cout << i << " " << j << endl; - } -} -``` - -``` -[output] -0 0 -0 1 -0 2 -1 0 -1 1 -1 2 -``` - -for 文の内側に更に for 文を書いて、二重 for を書くことができる。 -また、配列の配列という形で二次元配列を作ることもできる。(オセロ盤みたいなイメージ) - -```cpp:line-numbers -vector> v = { - {1, 2, 3, 4}, - {3, 5, 1, 2}, - {10, 20, 10, 20}, -}; -``` - -::: info -[**\[ IV の練習問題へ\]**](https://md.trap.jp/IE4NUAc_RR-USMIXlevsgA#Section-IV) - -[**\[講習会ページに戻る\]**](https://wiki.trap.jp/Event/welcome/23/lecture/pg-basic) -::: - diff --git a/docs/cpp/chapter-6/index.md b/docs/cpp/chapter-6/index.md index 4b457d37..7939eedc 100644 --- a/docs/cpp/chapter-6/index.md +++ b/docs/cpp/chapter-6/index.md @@ -1,4 +1,5 @@ -# [WIP] 6. 繰り返し処理 +# 6. 繰り返し処理 -第六章では、繰り返し処理について紹介します。 -ここまで身につけてしまえば、とりあえず頭の中に思い浮かべたものは理論上は作れるようになります。 +プログラムを書いていると、1つの処理を繰り返し行いたいことがある。第6章では、この**繰り返し処理**を紹介する。 + +ここまで身につけてしまえば、頭の中に思い浮かべたものは**理論上は**作れるようになるだろう。 diff --git a/docs/cpp/chapter-6/problems/count-down.md b/docs/cpp/chapter-6/problems/count-down.md new file mode 100644 index 00000000..cb971008 --- /dev/null +++ b/docs/cpp/chapter-6/problems/count-down.md @@ -0,0 +1,69 @@ +# 6.Q Count Down(★☆☆) + +## 問題 + +整数$N$を1つ入力として受け取り、$N$から$1$までを**大きい順**に1行ずつ出力しよう。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +5 +``` + +#### 出力 + +```Output:line-numbers +5 +4 +3 +2 +1 +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +1 +``` + +#### 出力 + +```Output:line-numbers +1 +``` + +## ヒント + +::: details ヒント1 +`for`文は減っていくようにも書ける。 +::: + +::: details ヒント2 +`i--`や`i -= 1`を使うと1ずつ減らせる。 +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int main() { + int n; + cin >> n; + + for (int i = n; i >= 1; i--) { + cout << i << endl; + } +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/do-not-fail.md b/docs/cpp/chapter-6/problems/do-not-fail.md new file mode 100644 index 00000000..f336e4f6 --- /dev/null +++ b/docs/cpp/chapter-6/problems/do-not-fail.md @@ -0,0 +1,75 @@ +# 6.Q DO NOT FAIL(★☆☆) + +## 問題 + +入力された複数の点数を受け取って、59点以下なら`Failed`と出力しよう。また、`-1`が入力されたら`Passed!`と出力して終了しよう。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +59 +72 +31 +-1 +``` + +#### 出力 + +```Output:line-numbers +Failed +Failed +Passed! +``` + +72の入力に対しては出力を行いません。 + +## ヒント + +::: details ヒント1 +`while (true)`とすることで、明示的に`break`しない限り終了しないループを実装することができます。 + +```cpp +// これは絶対に終了しない (無限ループ) +while(true) { +} + +while(true) { + // 適当な条件でbreakを実行することでループを抜けることが可能 + if (some_condition) { + break; + } +} +``` + +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int main() { + while(true) { + int score; + cin >> score; + + if (score == -1) { + cout << "Passed!" << endl; + break; + } + + if (score < 60) { + cout << "Failed" << endl; + } + } +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/even-number-in-range.md b/docs/cpp/chapter-6/problems/even-number-in-range.md new file mode 100644 index 00000000..db3ef60f --- /dev/null +++ b/docs/cpp/chapter-6/problems/even-number-in-range.md @@ -0,0 +1,98 @@ +# 6.Q Even Numbers in Range(★☆☆) + +## 問題 + +整数$A, B$を入力として受け取り、$A$以上$B$以下の**偶数**を小さい順に1行ずつ出力しよう。 + +ただし、$A \leq B$とする。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +3 10 +``` + +#### 出力 + +```Output:line-numbers +4 +6 +8 +10 +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +2 5 +``` + +#### 出力 + +```Output:line-numbers +2 +4 +``` + +## ヒント + +::: details ヒント1 +`i % 2 == 0`のとき、`i`は偶数である。 +::: + +::: details ヒント2 +`A`が奇数のときは、最初の偶数は`A + 1`になる。 +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int main() { + int a, b; + cin >> a >> b; + + int start = a; + if (start % 2 != 0) { + start++; + } + + for (int i = start; i <= b; i += 2) { + cout << i << endl; + } +} +``` + +::: + +::: details 解答例2 + +`i++`で1ずつ進め、偶数かどうかを`if`で判定する方法もあります。 + +```cpp +#include +using namespace std; + +int main() { + int a, b; + cin >> a >> b; + + for (int i = a; i <= b; i++) { + if (i % 2 == 0) { + cout << i << endl; + } + } +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/fibonatti.md b/docs/cpp/chapter-6/problems/fibonatti.md new file mode 100644 index 00000000..bd64da93 --- /dev/null +++ b/docs/cpp/chapter-6/problems/fibonatti.md @@ -0,0 +1,105 @@ +# 6.Q Fibonatti(★★☆) + +## 問題 + +正の整数$N$を受け取り、フィボナッチ数列の$N$番目を出力しよう。 + +ただし、フィボナッチ数列は$\{1,1,2,...\}$とします。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +4 +``` + +#### 出力 + +```Output:line-numbers +3 +``` + +$F_4 = 3$ + +### 例2 + +#### 入力 + +```Input:line-numbers +6 +``` + +#### 出力 + +```Output:line-numbers +8 +``` + +$F_6 = 8$ + +## ヒント + +::: details ヒント1 +$F_{n}=F_{n-1}+F_{n-2}$を`for`文で計算しよう。 +::: + +::: details ヒント2 +$F_{n-1}$と$F_{n-2}$を持つ変数`latest`、`second_latest`を作り、ループの中で漸化式を満たすように更新していこう。 +::: + +::: details ヒント3 +`latest`と`second_latest`を同時に更新することはできないので、一時的な変数(`next`など)を使って保持しておこう。 +::: + +## 解答例 + +::: details 解答例1 +for文を使うことでフィボナッチ数列の$N$番目を求めることができる。 + +```cpp +#include +using namespace std; + +int main() { + int n; + cin >> n; + int second_latest = 0, latest = 1; + for (int i = 2; i <= n; i++) { + // i番目を計算 + int next = second_latest + latest; + + // 最新の値を更新 + second_latest = latest; + latest = next; + } + cout << latest << endl; +} +``` + +::: + +::: details 解答例2 +`.push_back`を用いて、フィボナッチ数列の各値を配列に格納していく方法もあります。 + +```cpp +#include +#include +using namespace std; + +int main() { + int n; + cin >> n; + vector fibonatti_sequence = {0, 1}; + for (int i = 2; i <= n; i++) { + // i番目を計算 + int next = fibonatti_sequence[i-1] + fibonatti_sequence[i-2]; + fibonatti_sequence.push_back(next); + } + cout << fibonatti_sequence.back() << endl; +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/fizz-buzz-2d.md b/docs/cpp/chapter-6/problems/fizz-buzz-2d.md new file mode 100644 index 00000000..ff00fa5f --- /dev/null +++ b/docs/cpp/chapter-6/problems/fizz-buzz-2d.md @@ -0,0 +1,95 @@ +# 6.Q fizz-buzz 2D(★★★) + +## 問題 + +整数$H, W$が渡されるので、$H\times W$の二次元配列$a_{i,j}\ (1\leq i\leq H, 1\leq j\leq W)$を出力しよう。 + +ただし、$a_{i,j}$は + +- $i$は3の倍数でなく、$j$は5の倍数でないとき、$i\times j$(数値) +- $i$が3の倍数で、$j$は5の倍数でないとき、`Fi`(文字列) +- $i$は3の倍数でなく、$j$が5の倍数のとき、`Bu`(文字列) +- $i$が3の倍数で、$j$が5の倍数のとき、`FB`(文字列) + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +7 6 +``` + +#### 出力 + +```Output:line-numbers +1 2 3 4 Bu 6 +2 4 6 8 Bu 12 +Fi Fi Fi Fi FB Fi +4 8 12 16 Bu 24 +5 10 15 20 Bu 30 +Fi Fi Fi Fi FB Fi +7 14 21 28 Bu 42 +``` + +$i$行$j$列に$a_{i,j}$を出力している。 + +::: tip 出力の幅を揃える方法 +数字($i\times j$)や文字(`Fi`、`Bu`、`FB`)を出力した後に`\t`を出力すると数字や文字を揃えることができます。 + +例えば、以下のコードで上記のような出力例を再現できます。 + +```cpp +#include +using namespace std; + +int main() { + cout << "1\t2\t3\t4\tBu\t6\t" << endl; + cout << "2\t4\t6\t8\tBu\t12\t" << endl; + cout << "Fi\tFi\tFi\tFi\tFB\tFi\t" << endl; + cout << "4\t8\t12\t16\tBu\t24\t" << endl; + cout << "5\t10\t15\t20\tBu\t30\t" << endl; + cout << "Fi\tFi\tFi\tFi\tFB\tFi\t" << endl; + cout << "7\t14\t21\t28\tBu\t42\t" << endl; +} +``` + +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int main() { + int h, w; + cin >> h >> w; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + if (i % 3 == 2) { + if (j % 5 == 4) { + cout << "FB\t"; + } + else { + cout << "Fi\t"; + } + } + else { + if (j % 5 == 4) { + cout << "Bu\t"; + } + else { + cout << (i+1) * (j+1) << "\t"; + } + } + } + cout << endl; + } +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/index.md b/docs/cpp/chapter-6/problems/index.md index c62e2659..f9da3217 100644 --- a/docs/cpp/chapter-6/problems/index.md +++ b/docs/cpp/chapter-6/problems/index.md @@ -1 +1,17 @@ -# 練習問題 +# 6.Q 練習問題 + +::: tip +練習問題の難易度は3段階に分かれています。 + +* ★☆☆:**できれば解いて理解して欲しい問題**です。とにかく手を動かしましょう。 +* ★★☆:ぜひ解いて欲しいですが、解けなくても問題はありません。 +* ★★★:ややトリッキーな問題が並んでいます。余裕があれば取り組んでみましょう。 +::: + +- [Count Down(★☆☆)](count-down) +- [Even Numbers in Range(★☆☆)](even-number-in-range) +- [lower or UPPER(★☆☆)](lower-or-upper) +- [DO NOT FAIL(★☆☆)](do-not-fail) +- [Prime Check(★★☆)](prime-check) +- [Fibonatti(★★☆)](fibonatti) +- [fizz-buzz 2D(★★★)](fizz-buzz-2d) diff --git a/docs/cpp/chapter-6/problems/lower-or-upper.md b/docs/cpp/chapter-6/problems/lower-or-upper.md new file mode 100644 index 00000000..0d7042f0 --- /dev/null +++ b/docs/cpp/chapter-6/problems/lower-or-upper.md @@ -0,0 +1,64 @@ +# 6.Q lower or UPPER(★☆☆) + +## 問題 + +アルファベット1文字が渡されたとき、それが大文字なら`UPPERCASE`、小文字なら`lowercase`と出力しよう。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +a +``` + +#### 出力 + +```Output:line-numbers +lowercase +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +B +``` + +#### 出力 + +```Output:line-numbers +UPPERCASE +``` + +## ヒント + +::: details ヒント1 +`char`型は1byteの整数値のため、互いに大小関係があります。ASCIIコードの話を思い出してみましょう。 +::: + +## 解答例 + +::: details 解答例 +`char`型は各文字コードに対応する整数値のため、`<`、`>`、`<=`、`>=`などで大小を比較することができます。 + +```cpp +#include +using namespace std; + +int main() { + char c; + cin >> c; + if (c >= 'a') { + cout << "lowercase" << endl; + } + else { + cout << "UPPERCASE" << endl; + } +} +``` + +::: diff --git a/docs/cpp/chapter-6/problems/prime-check.md b/docs/cpp/chapter-6/problems/prime-check.md new file mode 100644 index 00000000..70fa4f73 --- /dev/null +++ b/docs/cpp/chapter-6/problems/prime-check.md @@ -0,0 +1,116 @@ +# 6.Q Prime Check(★★☆) + +## 問題 + +正の整数$N$を1つ入力として受け取り、$N$が素数なら`Prime`、そうでなければ`Not Prime`と出力しよう。 + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +17 +``` + +#### 出力 + +```Output:line-numbers +Prime +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +21 +``` + +#### 出力 + +```Output:line-numbers +Not Prime +``` + +## ヒント + +::: details ヒント1 +$2$から$N-1$までの数で割り切れるかを調べると素数判定ができる。 +::: + +::: details ヒント1 +$N=1$のときを場合分けしておくとプログラムが書きやすい。 +::: + + + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int main() { + int n; + cin >> n; + + if (n == 1) { + cout << "Not Prime" << endl; + return 0; + } + + bool is_prime = true; + for (int i = 2; i < n; i++) { + if (n % i == 0) { + is_prime = false; + break; + } + } + + if (is_prime) { + cout << "Prime" << endl; + } + else { + cout << "Not Prime" << endl; + } +} +``` + +割る数を$2$から増やしていき、`i*i <= N`を満たす範囲だけ調べれば十分なことも知られている。 + + +```cpp +#include +using namespace std; + +int main() { + int n; + cin >> n; + + if (n == 1) { + cout << "Not Prime" << endl; + return 0; + } + + bool is_prime = true; + for (int i = 2; i*i <= n; i++) { + if (n % i == 0) { + is_prime = false; + break; + } + } + + if (is_prime) { + cout << "Prime" << endl; + } + else { + cout << "Not Prime" << endl; + } +} +``` + +::: diff --git a/docs/cpp/chapter-7/1.md b/docs/cpp/chapter-7/1.md index 2ec1313f..baa1b068 100644 --- a/docs/cpp/chapter-7/1.md +++ b/docs/cpp/chapter-7/1.md @@ -1,9 +1,8 @@ -# [WIP] 7.1 関数とは +# 7.1 関数とは -数学における「関数」とは、$f(x)$ 等のように表してある値(この例では $x$ )によって値 $f(x)$ が決まるものであった。 +数学における「関数」とは、$f(x)$等のように表してある値(この例では$x$)によって値$f(x)$が決まるものであった。 -プログラミングにおいてはこれと少し似ているが、ある値を与えた時に、**決められた処理をして**、ある値を返すものを**関数** -と呼ぶ。ここで、関数は値を与える必要はないし、また値を返さなくても良い(決められた処理がなくても良い)という事に注意すること。 +プログラミングにおいてはこれと少し似ているが、ある値を与えた時に、**決められた処理をして**、ある値を返すものを**関数**と呼ぶ。ここで、関数に値を与える必要はないし、また値を返さなくても良いという事に注意すること。 C++言語において、関数は以下のように記述する。 @@ -36,8 +35,7 @@ int main() { ``` -``` -[output] +```Output:line-numbers Hello, traP! ``` @@ -56,7 +54,7 @@ flowchart LR return --> e ``` ----- +--- 関数は何回でも実行できる。 @@ -76,8 +74,7 @@ int main() { } ``` -``` -[output] +```Output:line-numbers Hello, traP! Hello, traP! Hello, traP! @@ -106,12 +103,12 @@ flowchart LR return3 --> e ``` -ここでは `Hello, traP!` と出力する `Hello` 関数を定義している。 -関数を実装するとき、関数の末尾に必ず `return 0;` と記述する(これについては「返り値」の節で扱う) 。 +ここでは`Hello, traP!`と出力する`Hello`関数を定義している。 +関数を実装するとき、関数の末尾に必ず`return 0;`と記述する(これについては[7.3](3)で扱う)。 複数回呼び出すと、複数回実行されている事がわかる。複雑な処理を何回も実行するとき、よく関数を使う。 -また、main も関数の1つである。C++言語においては、コンピューターはこの main 関数を実行すると考えると良い。 +また、mainも関数の1つである。C++言語においては、コンピューターはこのmain関数を最初に実行すると考えると良い。 異なる関数の間では、変数は共有されない。 @@ -133,8 +130,7 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 400 100 ``` @@ -149,7 +145,7 @@ flowchart LR end calc --> setprint subgraph hello["printn()"] - + setprint["n = 200"] --> double["n *= 2"] --> printprint("output n") --> return["return 0"] end return --> printmain diff --git a/docs/cpp/chapter-7/2.md b/docs/cpp/chapter-7/2.md index 3925b727..b7ca5246 100644 --- a/docs/cpp/chapter-7/2.md +++ b/docs/cpp/chapter-7/2.md @@ -1,4 +1,6 @@ -# [WIP] 7.2 引数 +# 7.2 引数 + +## 7.2.1 引数の実装 関数に値を渡すときは、以下のように実装する。 @@ -17,14 +19,13 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 12 9 ``` -この関数に渡す値のことを **引数** と呼ぶ。 -引数の型は `()` の内側で定義される(`(int x)` の部分)。 +この関数に渡す値のことを**引数**と呼ぶ。 +引数の型は`()`の内側で定義される(`(int x)`の部分)。 ```mermaid flowchart LR @@ -45,7 +46,7 @@ flowchart LR return3 --> e ``` -例えば string 型の引数を設定したいなら以下のように実装する。 +例えば`string`型の引数を設定したいなら以下のように実装する。 ```cpp:line-numbers #include @@ -62,8 +63,7 @@ int main() { } ``` -``` -[output] +```Output:line-numbers Hello, traP Hello, Takeno_hito ``` @@ -87,8 +87,7 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 11 15 ``` @@ -113,11 +112,8 @@ int main() { ``` -``` -[output] +```Output:line-numbers 4 ``` -これについての詳細は「参照渡し」の節で扱う。 - - +これについての詳細は[7.4](4)で扱う。 diff --git a/docs/cpp/chapter-7/3.md b/docs/cpp/chapter-7/3.md index 54cb86b0..bacc8d52 100644 --- a/docs/cpp/chapter-7/3.md +++ b/docs/cpp/chapter-7/3.md @@ -1,4 +1,6 @@ -# [WIP] 7.3 返り値 +# 7.3 返り値 + +## 7.3.1 返り値の実装 逆に、関数が値を返すときは以下のように実装する。 @@ -6,7 +8,6 @@ #include using namespace std; - int ten() { return 10; } @@ -18,12 +19,11 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 10 ``` -この時、この「10」を **返り値** と呼ぶ。(10 を return する → 10 を返す) +この時、この「10」を**返り値**と呼ぶ。(10をreturnする → 10を返す) ```mermaid flowchart LR @@ -40,26 +40,22 @@ flowchart LR 返り値の型は、関数名の前で宣言している。引数の話とまとめると、関数の定義方法は次の通り。 -```cpp +```cpp:line-numbers <返り値の型> <関数名> ([引数の名前、型]) {... ``` 返り値の型も自分で好きなように宣言できる。ただし複数の返り値を返すことはできない。 -main 関数の返り値 は int 型である。他の関数の返り値はすべて呼び出した側に渡されるように、main 関数の返り値は OS -に渡される。このOSに渡す値は「終了コード」と呼ばれ、正常時は 0 を返すことが定められている。 +main関数の返り値はint型である。他の関数の返り値はすべて呼び出した側に渡されるように、main関数の返り値はOSに渡される。このOSに渡す値は「終了コード」と呼ばれ、正常時は0を返すことが定められている。 -なので本来ならば main 関数にも関数末尾に `return 0` -を書かなければならないが(そういうテキストも多い)、それを省略しても良いという事になっている(省略すると末尾に `return 0` -が自動的に追加される)。 +なので本来ならばmain関数にも関数末尾に`return 0`を書かなければならないが(そういうテキストも多い)、それを省略しても良いという事になっている(省略すると末尾に`return 0`が自動的に追加される)。 -関数の返り値がないときは、他の型の代わりに **void** 型を用いる。この場合、`return` 文は省略できる。(書きたい場合は `return;` と書く)。 +関数の返り値がないときは、他の型の代わりに**void**型を用いる。この場合、`return`文は省略できる。(書きたい場合は`return;`と書く)。 ```cpp:line-numbers #include using namespace std; - void hello() { cout << "Hello!" << endl; } @@ -69,7 +65,7 @@ int main() { } ``` ----- +--- 引数と返り値を組み合わせることで、数学のような関数が実装できる。 @@ -86,9 +82,8 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 100 ``` -この `square` 関数は、引数 $n$ を受け取り、 $n^2$ を返す関数である。 +この`square`関数は、引数$n$を受け取り、$n^2$を返す関数である。 diff --git a/docs/cpp/chapter-7/4.md b/docs/cpp/chapter-7/4.md index 61eccf35..a6b1c14b 100644 --- a/docs/cpp/chapter-7/4.md +++ b/docs/cpp/chapter-7/4.md @@ -1,12 +1,16 @@ -# [WIP] 7.4 [発展] 参照渡し +# 7.4 [発展] 参照渡し -## 7.4.1. [発展] アドレス +::: info +ここではやや難しい内容を扱っているため、一度飛ばして、練習問題に進んでも構いません。 +::: + +## 7.4.1 アドレス 一度関数から離れて「変数」について考えてみる。 -以前触れた通り、変数は 0 と 1 の組み合わせによって表されているが、プログラムが変数の値を参照するときには、「変数の住所」の情報を持っていなければならない(でなければ、どの変数がどれか分からなくなってしまう)。 -この変数の住所のことを **アドレス** と呼ぶ。変数には「値」と「アドレス」の二種類の情報が備わっている。具体的には、メモリの前から何バイト目に変数が格納されているかの情報が与えられる。 +以前触れた通り、変数は0と1の組み合わせによって表されているが、プログラムが変数の値を参照するときには、「変数の住所」の情報を持っていなければならない(でなければ、どの変数がどれか分からなくなってしまう)。 +この変数の住所のことを**アドレス**と呼ぶ。変数には「値」と「アドレス」の二種類の情報が備わっている。具体的には、メモリの前から何バイト目に変数が格納されているかの情報が与えられる。 -アドレスは変数の前に `&` をつけることで取得することができる。 +アドレスは変数の前に`&`をつけることで取得することができる。 ```cpp:line-numbers #include @@ -19,18 +23,17 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 4 0x7fffe13bd944 ``` アドレスは人によって・実行するたびに変わることに注意。(変わらないこともある) -出力に `0x` がついているが、これは 16 進数であることを表している。 -10~15 に当たる1桁の値として、`abcdef` が用いられる(探してみると 0-9 と a~f しかない文字列を時々見つけられる。これらは16進数である事が多い)。 +出力に`0x`がついているが、これは16進数であることを表している。 +10~15に当たる1桁の値として、`abcdef`が用いられる(探してみると0-9とa~fしかない文字列を時々見つけられる。これらは16進数である事が多い)。 -- 「`int` 型のアドレス」の型は `int *` である。 -- アドレスから元の変数に戻すには、アドレスの前に `*` をつける。 +- 「`int`型のアドレス」の型は`int *`である。 +- アドレスから元の変数に戻すには、アドレスの前に`*`をつける。 ```cpp:line-numbers #include @@ -45,15 +48,14 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 0x7ffc62a31e34 5 ``` -ここで `*p += 1` と書いているが、`p` に `x` のアドレスが入っているので、`x += 1` と書くのと同じことが起きる。 +ここで`*p += 1`と書いているが、`p`に`x`のアドレスが入っているので、`x += 1`と書くのと同じことが起きる。 -## 7.4.2. [発展] 値渡しと参照渡し +## 7.4.2 値渡しと参照渡し ```cpp:line-numbers #include @@ -74,11 +76,11 @@ int main() { 「引数」の節で、関数を呼び出した側の変数は、関数内で操作しても変わらないという事を説明した。 -これについてもう少し詳しく触れると、関数を呼び出すとき、与えられた引数は複製され( = 新しい変数が作られて)、関数内で使用される。 +これについてもう少し詳しく触れると、関数を呼び出すとき、与えられた引数は複製され(= 新しい変数が作られて)、関数内で使用される。 -つまり変数の値のみを渡している。この事を **値渡し** と呼ぶ。 +つまり変数の値のみを渡している。この事を**値渡し**と呼ぶ。 -`main` 関数で作った `x` を `triple` の中で変更できるようにするには、`x` のアドレス を関数に渡せば良い。 +`main`関数で作った`x`を`triple`の中で変更できるようにするには、`x`のアドレスを関数に渡せば良い。 ```cpp:line-numbers #include @@ -97,14 +99,13 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 12 ``` -これを **アドレス渡し** と呼ぶ。関数にわたすのは変数の値ではなく「変数のアドレス」なので、呼び出し側は `triple(&x)` と記述する。 +これを**アドレス渡し**と呼ぶ。関数にわたすのは変数の値ではなく「変数のアドレス」なので、呼び出し側は`triple(&x)`と記述する。 -しかし、`&x` や `*x` をいちいち書くのは面倒なので、これを簡略化した記法が存在する。下のコードを書けば、上のコードと書いたのと同じことになる。 +しかし、`&x`や`*x`をいちいち書くのは面倒なので、これを簡略化した記法が存在する。下のコードを書けば、上のコードと書いたのと同じことになる。 ```cpp:line-numbers #include @@ -123,12 +124,10 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 12 ``` -型の部分を `int` から `int &` に変えるだけで、変数のポインタを渡したことになり、`main` 関数の `x` を `triple` -関数から変更できるようになるのである。 +型の部分を`int`から`int &`に変えるだけで、変数のポインタを渡したことになり、`main`関数の`x`を`triple`関数から変更できるようになるのである。 -この機能を **参照** と言い、この書き方を **参照渡し** と呼ぶ。 +この機能を**参照**と言い、この書き方を**参照渡し**と呼ぶ。 diff --git a/docs/cpp/chapter-7/index.md b/docs/cpp/chapter-7/index.md index b18a166c..3e0a6860 100644 --- a/docs/cpp/chapter-7/index.md +++ b/docs/cpp/chapter-7/index.md @@ -1,3 +1,5 @@ -# [WIP] 7. 関数 +# 7. 関数 -第七章では、関数について扱います。数学における関数とプログラミングにおける関数の違いの説明から始まり、関数について必要な知識を一通りさらいます。 +第7章では、関数を扱う。 + +数学における関数とプログラミングにおける関数の違いの説明から始め、関数について必要な知識を一通りさらう。 diff --git a/docs/cpp/chapter-7/problems/index.md b/docs/cpp/chapter-7/problems/index.md index c62e2659..79ad9c3d 100644 --- a/docs/cpp/chapter-7/problems/index.md +++ b/docs/cpp/chapter-7/problems/index.md @@ -1 +1,12 @@ -# 練習問題 +# 7.Q 練習問題 + +::: tip +練習問題の難易度は3段階に分かれています。 + +* ★☆☆:**できれば解いて理解して欲しい問題**です。とにかく手を動かしましょう。 +* ★★☆:ぜひ解いて欲しいですが、解けなくても問題はありません。 +* ★★★:ややトリッキーな問題が並んでいます。余裕があれば取り組んでみましょう。 +::: + +- [Max of Three(★☆☆)](max-of-three) +- [Swap Two Numbers(★★☆)](swap-two) diff --git a/docs/cpp/chapter-7/problems/max-of-three.md b/docs/cpp/chapter-7/problems/max-of-three.md new file mode 100644 index 00000000..56255285 --- /dev/null +++ b/docs/cpp/chapter-7/problems/max-of-three.md @@ -0,0 +1,88 @@ +# 7.Q Max of Three(★☆☆) + +## 問題 + +整数$a, b, c$が与えられる。$a, b, c$を引数に取り、最大値を返す関数`max_of_three`を作ろう。 + +次のプログラムの`// ここにプログラムを書く`の部分に、関数`max_of_three`を定義して完成させること。`main`関数のコードは変更しないこと。 + +```cpp:line-numbers +#include +using namespace std; + +// ここにプログラムを書く + +int main() { + int a, b, c; + cin >> a >> b >> c + cout << max_of_three(a, b, c) << endl; +} +``` + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +3 9 4 +``` + +#### 出力 + +```Output:line-numbers +9 +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +-5 -2 -10 +``` + +#### 出力 + +```Output:line-numbers +-2 +``` + +## ヒント + +::: details ヒント1 +`if`文で最大値を更新する方法が使えます。 +::: + +::: details ヒント2 +最初に`x`を最大値としておき、`y`や`z`と比較していくと簡単です。 +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +int max_of_three(int x, int y, int z) { + int best = x; + if (y > best) { + best = y; + } + if (z > best) { + best = z; + } + return best; +} + +int main() { + int a, b, c; + cin >> a >> b >> c + cout << max_of_three(a, b, c) << endl; +} +``` + +::: diff --git a/docs/cpp/chapter-7/problems/swap-two.md b/docs/cpp/chapter-7/problems/swap-two.md new file mode 100644 index 00000000..fec4cd11 --- /dev/null +++ b/docs/cpp/chapter-7/problems/swap-two.md @@ -0,0 +1,93 @@ +# 7.Q Swap Two Numbers(★★☆) + +::: info +この問題は[7.4](../4)を読んでから取り組んでください。 +::: + +## 問題 + +整数$a, b$が与えられる。2つの値を入れ替える関数`swap_int`を作ろう。`swap_int`は返り値を持たないものとする。 + +次のプログラムの`// ここにプログラムを書く`の部分に、関数`swap_int`を定義して完成させること。`main`関数のコードは変更しないこと。 + +```cpp:line-numbers +#include +using namespace std; + +// ここにプログラムを書く + +int main() { + int a, b; + cin >> a >> b; + cout << a << " " << b << endl; + swap_int(a, b); + cout << a << " " << b << endl; +} +``` + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +3 10 +``` + +#### 出力 + +```Output:line-numbers +3 10 +10 3 +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +-5 7 +``` + +#### 出力 + +```Output:line-numbers +-5 7 +7 -5 +``` + +## ヒント + +::: details ヒント1 +参照渡しを使うと、関数の中で値を入れ替えた結果が`main`側にも反映されます。([7.4](../4)を参考にしてください。) +::: + +::: details ヒント2 +一時変数を使って`x`と`y`を入れ替えましょう。 +::: + +## 解答例 + +::: details 解答例 + +```cpp +#include +using namespace std; + +void swap_int(int &x, int &y) { + int tmp = x; + x = y; + y = tmp; +} + +int main() { + int a, b; + cin >> a >> b; + cout << a << " " << b << endl; + swap_int(a, b); + cout << a << " " << b << endl; +} +``` + +::: diff --git a/docs/cpp/chapter-8/1.md b/docs/cpp/chapter-8/1.md index f664dff0..be0f9c8e 100644 --- a/docs/cpp/chapter-8/1.md +++ b/docs/cpp/chapter-8/1.md @@ -1,14 +1,19 @@ -# [WIP] 8.1 構造体とは +# 8.1 構造体とは -構造体は、分散したデータを一つにまとめる事ができる型である。 +## 8.1.1 構造体の基本 -例として、traP メンバーの名簿を考えよう。 + + -今この講習に居るメンバーの traP ID、学籍番号、学年 の情報がほしいとする。 +構造体を使うと、複数のデータをまとめて新しい型を定義することができる。 + +例として、traPメンバーの名簿を考えよう。 + +今この講習に居るメンバーの`traP ID`、学籍番号、学年の情報がほしいとする。 これらをプログラムで扱うとき、素朴には以下のように個別に変数を宣言すればよい。 -```cpp +```cpp:line-numbers string trap_id, student_id; int grade; ``` @@ -55,7 +60,7 @@ int main() { これはあまりに長い。 配列を使えば宣言はそれぞれの変数でまとめることはできるが、できれば学生情報は一つの変数にまとめたい。 -ここで、複数の変数をまとめてひとつの値として扱える**構造体 (struct)** を導入し、構造体の **型** を定義する。 +ここで、複数の変数をまとめてひとつの値として扱える**構造体(struct)**を導入し、構造体の**型**を定義する。 ::: tip 他の言語などではクラスやオブジェクトなどと呼ばれる。 @@ -63,42 +68,42 @@ int main() { ::: tip 用語 -- 構造体に属する変数は**メンバ変数 (member variable)** と呼ばれている。 -- ある構造体の型を持った値は、その構造体の**インスタンス (instance)** と呼ばれる。 +- 構造体に属する変数は**メンバ変数**(member variable)と呼ばれている。 +- ある構造体の型を持った値は、その構造体の**インスタンス**(instance)と呼ばれる。 ::: 構造体を用いると、コードは以下のようになる。 -<<<@/text/chapter-6/struct-raw.cpp{cpp:line-numbers} +<<< @/text/chapter-6/struct-raw.cpp{cpp:line-numbers} 少し見やすくなったように感じないだろうか? -<<<@/text/chapter-6/struct.cpp#define{cpp:line-numbers} +<<< @/text/chapter-6/struct.cpp#define{cpp:line-numbers} -この部分で構造体 `Member` を定義している。構造体 `Member` は以下の3つのメンバ変数を持つ。 +この部分で構造体`Member`を定義している。構造体`Member`は以下の3つのメンバ変数を持つ。 -- `string` 型の `trap_id` -- `string` 型の `student_id` -- `int` 型の `grade` +- `string`型の`trap_id` +- `string`型の`student_id` +- `int`型の`grade` 宣言は以下のように対応する。 -<<<@/text/chapter-6/struct.cpp#declare{cpp:line-numbers} +<<< @/text/chapter-6/struct.cpp#declare{cpp:line-numbers} -これは省略されているが、先頭から順に `trap_id = "zer0-star"`, `student_id = "22BXXXXX"`, `grade = 2` とするという宣言である。 +これは省略されているが、先頭から順に`trap_id = "zer0-star"`,`student_id = "22BXXXXX"`,`grade = 2`とするという宣言である。 -次に、構造体を使用する方を見てみよう。`equals` 関数の実装は以下のとおり。 +次に、構造体を使用する方を見てみよう。`equals`関数の実装は以下のとおり。 -<<<@/text/chapter-6/struct.cpp#function{cpp:line-numbers} +<<< @/text/chapter-6/struct.cpp#function{cpp:line-numbers} -関数の引数として、 `int` 型などと同様に `Member` 型を受け取ることができる。 -`Member` 型の変数1つを渡すのは、 `trap_id` `student_id` `grade` の3変数を渡したことと同じになる。 +関数の引数として、`int`型などと同様に`Member`型を受け取ることができる。 +`Member`型の変数1つを渡すのは、`trap_id`、`student_id`、`grade`の3変数を渡したことと同じになる。 -`Member` 型の各変数にアクセスするには、 `member.trap_id` のように、 `.` で変数名とメンバ変数を繋げれば良い。 +`Member`型の各変数にアクセスするには、`member.trap_id`のように、`.`で変数名とメンバ変数を繋げれば良い。 -このようにしたあとは、以下のように構造体を使って `equals` を使用することができる。 +このようにしたあとは、以下のように構造体を使って`equals`を使用することができる。 -<<<@/text/chapter-6/struct.cpp#use{cpp:line-numbers} +<<< @/text/chapter-6/struct.cpp#use{cpp:line-numbers} なんだか仰々しいものに見えるかもしれないが、本質的には複数の変数をまとめて、わかりやすくなるように取り扱っているだけである。 diff --git a/docs/cpp/chapter-8/2.md b/docs/cpp/chapter-8/2.md index 54830b00..54c67a04 100644 --- a/docs/cpp/chapter-8/2.md +++ b/docs/cpp/chapter-8/2.md @@ -1,8 +1,10 @@ -# [WIP] 8.2 メソッド +# 8.2 メソッド + +## 8.2.1 メソッドの基本 実は、構造体の中に宣言できるのは、変数だけではない。関数もである。 構造体の内側で関数を宣言すると、その関数は特別視され、呼び出し元のインスタンスのメンバ変数に直接アクセスすることができる。 -このように、構造体に属しており普通の関数とは扱いが異なる関数を、構造体の**メソッド (method)** と呼ばれる。 +このように、構造体に属しており普通の関数とは扱いが異なる関数を、構造体の**メソッド**(method)と呼ばれる。 メソッド内では、直接自分自身のインスタンスにアクセスする事ができる。 @@ -32,8 +34,7 @@ int main() { } ``` -```txt -[output] +```Output:line-numbers 22B 21B ``` @@ -63,15 +64,14 @@ int main() { } ``` -``` -[output] +```Output:line-numbers 1 ``` ::: tip -メソッド `updateGrade` は、以下のように実装することもできる。が、ここでは深くは扱わない。 +メソッド`updateGrade`は、以下のように実装することもできる。が、ここでは深くは扱わない。 -```cpp +```cpp:line-numbers void updateGrade(int grade) { this->grade = grade; } diff --git a/docs/cpp/chapter-8/index.md b/docs/cpp/chapter-8/index.md index f2e51519..ee165cab 100644 --- a/docs/cpp/chapter-8/index.md +++ b/docs/cpp/chapter-8/index.md @@ -1,4 +1,5 @@ -# [WIP] 8. 構造体 +# 8. 構造体 -第八章では構造体 (struct) について扱います。第7章までとは違い、第8章の知識はなくともプログラミングをする事はできます。 -これは、人間がより便利にプログラミングをする為に導入された概念です。 +第8章では構造体(struct)を扱う。 + +構造体の知識がなくともプログラミングをする事はできる。構造体は、人間がより便利にプログラミングをする為に導入された概念である。 diff --git a/docs/cpp/chapter-8/problems/index.md b/docs/cpp/chapter-8/problems/index.md index c62e2659..9d5c4493 100644 --- a/docs/cpp/chapter-8/problems/index.md +++ b/docs/cpp/chapter-8/problems/index.md @@ -1 +1,11 @@ -# 練習問題 +# 8.Q 練習問題 + +::: tip +練習問題の難易度は3段階に分かれています。 + +* ★☆☆:**できれば解いて理解して欲しい問題**です。とにかく手を動かしましょう。 +* ★★☆:ぜひ解いて欲しいですが、解けなくても問題はありません。 +* ★★★:ややトリッキーな問題が並んでいます。余裕があれば取り組んでみましょう。 +::: + +- [Order(★★☆)](order) diff --git a/docs/cpp/chapter-8/problems/order.md b/docs/cpp/chapter-8/problems/order.md new file mode 100644 index 00000000..f3b65496 --- /dev/null +++ b/docs/cpp/chapter-8/problems/order.md @@ -0,0 +1,134 @@ +# 8.Q Order(★★☆) + +## 問題 + +以下のような商品の一覧が与えられる。 + +| No. | 値段 | 名前 | スペック | +| --- | ------- | ------------ | -------- | +| 0 | 5,000 | 机 | それなり | +| 1 | 100 | チョコ | おいしい | +| 2 | 300,000 | ゲーミングPC | やすい | +| 3 | 100,000 | 安いPC | たかい | + +これらの商品を扱える構造体`Item`を作成しよう。 + +また、以下のクエリに対して、返答しよう。 + +1. 番号が与えられたときに、その商品の名前、値段、スペックを表示する。 +2. 値段が与えられたときに、その**値段以下**の全ての商品の名前、値段、スペックをすべて表示する。 + +```cpp:line-numbers +#include +#include +using namespace std; + +struct Item { + // ここを実装する +}; + +int main() { + vector items = { + Item{5000, "机", "それなり"}, + // ここにアイテムを追加 + }; + + // ここに 1番 2番を 解けるプログラムを書く +} +``` + +## 入出力例 + +### 例1 + +#### 入力 + +```Input:line-numbers +1 0 +``` + +#### 出力 + +```Output:line-numbers +机 5000 それなり +``` + +### 例2 + +#### 入力 + +```Input:line-numbers +2 100001 +``` + +#### 出力 + +```Output:line-numbers +机 5000 それなり +チョコ 100 おいしい +安いPC 100000 たかい +``` + +## ヒント + +::: details ヒント1 +`Item`構造体を宣言して、以下のメンバー変数とメソッドを実装しよう。 +- `price`(`int`型) +- `name`(`string`型) +- `spec`(`string`型) +- `print`メソッド +::: + +::: details ヒント2 +クエリとして入力される`1`または`2`の値に応じて、条件に合致するアイテムの情報を出力しよう。 +::: + +## 解答例 + +::: tip 解答例1 + +::: spoiler クリックして展開 +```cpp:line-numbers +#include +#include +using namespace std; + +struct Item { + int price; + string name; + string spec; + + void print() { + cout << name << " " << price << " " << spec << endl; + } +}; + +int main() { + vector items = { + Item{5000, "机", "それなり"}, + Item{100, "チョコ", "おいしい"}, + Item{300000, "ゲーミングPC", "やすい"}, + Item{100000, "安いPC", "たかい"} + }; + + // クエリの条件分岐 + int query_type; + cin >> query_type; + if (query_type == 1) { + int no; + cin >> no; + items[no].print(); + } else if (query_type == 2) { + int price; + cin >> price; + for (int i=0; i