書いた人
積木製作という会社で働いている下っ端えんじにゃーのヤマシタです。
錦もく会(https://kinmokukai-2.peatix.com/view) という、もくもく会の主催者とかやってます。
概要
普段C#でUnityを触っている同僚から、
C/C++の勉強をしたいという相談をもらったので、
ざっくりとまとめました。
本当にざっくりなので、時間があれば手直しします。
あと、ソースコードがすべて画像なのはコピペじゃなくて写経してもらうためです。
写経すると3倍くらい覚えます(当社比)
対象読者
C#やUnityを使ってプログラムを動かせることが前提です。
超入門なので、掘り下げるための土台を提供することが主目的となっています。
Windowsでのプログラムを前提にしています。
環境準備
プロジェクトを作ろう
VisualC++を開いて
今回は「全般」から「空のプロジェクト」を作ります。
下の方に「名前」「場所」「ソリューション名」を指定しましょう。
ソリューションとは、複数のプロジェクトをまとめて管理する入れ物で、
ライブラリなどを作るようになると関係してきますが、
今回はあまり気にしません。
動作に必要なファイルの準備
動作させるには「main関数が書かれたcpp」ファイルが必要です。
プロジェクトの中に「ソースファイル」というフォルダがあると思うので、
そこで「追加>新しい項目」を選択。
メニューで「FizzBuzz.cpp」というソースファイルを作りましょう。
同様にして「ヘッダーファイル」フォルダにも、
FizzBuzz.hというヘッダーファイルを作りました。
この写真と同じ状態になれば大丈夫。
やってみよう
Hello World
この写真にあるコードを写経して、
HelloWorldを動かしてみましょう。
F5かShift+F5のショートカットで実行できます。
C#で使っているものとほぼ変わりません。
ちょっと見慣れないものについて説明していきます。
includeに関する解説
こちらはプリコンパイル文と呼ばれる特別な命令です。
プリコンパイル文については長くなるので、
少し下の部分にまとめておきました。
「関数の引数にあるchar* argv
」
「配列」や「ポインタ」などと関わるため、
こちらはそもそも今回では解説しません。
配列を使う次回以降に詳しく説明します。
「printf("...\n")」
なんとなくノリでわかると思いますが、
printf
この関数に渡した文字が出力されます。
ちなみに、文字列の最後についている\n
はちょっと特殊でエスケープ文字と言います。
エスケープ文字は特殊な機能のために用意されていて、
この\n
は文字列として改行を表します。
C/C++では非常によく使いますので、覚えてください。
「system("pause");」
ちょっと特殊な存在ですが、
これを書かないで実行してみてください。
実行したときに出てくる窓が一瞬で消えると思います。
system
この関数はOSで定義されたシステム機能を呼び出しています
system("pause")
この場合は一時停止機能を呼び出しているわけですね。
これを使うことで、窓がすぐに消えちゃう問題を解決しています。
窓がすぐに消えちゃう問題の解決には他にもいくつかありますので、興味があれば調べてください。
とりあえずもうちょっとプログラムを写経して
Cを動かす感覚をつかんでみましょう。
プリコンパイル文
超入門ということでざっくり解説します。
#include "---"
#include <--->
ファイルの先頭に書いている二種類のinclude文は、
プリコンパイル文と呼ばれるものです。
コンピュータはプログラムを実行するときに「ビルド」を行います。
ビルドは二段階に分かれています。
コンパイル: 手元のファイルをファイルをコンピュータの読めるオブジェクトコードに変換する。
.c/.cppという名前のファイルごとにオブジェクトコードが生成される。
リンク: コンパイルしたファイル群を合わせて実行可能な形にする
プリコンパイル文は、
このコンパイルを実行する前の段階でコンパイラに行わせる命令文です。
中でもinclude
はC/C++にとって必須の命令で、
指定した名前のファイルを自動的に探して、その部分に張り付けします。
今回の場合、
自作したファイルであるFizzBuzz.h
と、
標準ライブラリであるstdio.h, stdlib.h, string
を使いたいので、
includeを使ってこのファイルの頭にコピペしてもらっています。
ちなみに、この標準ライブラリも含めて、
ファイルの中身が見たい場合はVisualStudioだと
ファイル名を右クリックしてみることができます。
基本の文法
C/C++の基本文法をまとめて使ってみました。
関数の実装(7): 戻値の型 関数名 (引数の型 引数の名前) { 処理 }
変数の宣言(9): 変数の型 変数名 = 初期化の値;
繰り返し(15): for(変数の宣言; 継続条件; 二回目以降最初に行う処理){ 処理 }
分岐(16): if(条件){ 真の処理 } else { 偽の処理 }
「printf("num is smaller then 10 (%d)\n",num);の%dについて」
%d
この文字が「フォーマット指定子」と呼ばれる記号で、
文字列の後に指定した数値(%dは整数限定)と置き換えられて表示されます。
関数の分割
処理の内容は先ほどと同じで、ほぼコピペしただけですが、
checkという関数を使って、printfにも少し工夫をしています。
また、string(文字列型)も使うことにしました。
「string」
このstringを使うために、#include <string>
とusing namespace std;
を追加しています。
using namespaceは「stdという入れ物の中のstringを使うよ」という宣言です。
stringは基本的にstdという入れ物の中に隠されているので、この宣言無しでは使えません。
「関数の順序」
もしこのプログラムと大体同じものを書いたのに動かない場合、
もしかしたら関数の順番としてcheckが下になっているかもしれません。
C/C++では「ある関数の処理を呼び出す場合、呼び出される側は先に宣言されていなければいけない」というルールがあります。
そのため、checkは必ずmainより先になくてはいけませんので注意してください。
「機能の切り分け」
基本的にプログラムは「小さな処理を組み合わせて書く」方が良いといえます。
今回は「ある数字(num)が、別の数字(3)とどんな関係のあるのかを文字列で表す」という機能を、
checkという関数に切り分けたわけです。
「戻り値と引数のconst」
main関数とcheck関数の違いとして、
戻り値や引数についているconstが少し気になるかもしれません。
constは値の書き換えを禁止する定数に使います。
引数のconstは関数の中でその値が書き換わらない。
戻り値のconstは戻された後にその値が書き換わらない。
C#などを使っていた人には不便にするだけに見えるでしょうが、
C/C++を使う大きなメリットの一つがこの「書き換え防止」機能です。
一度中身が入った変数の中身が変化しないため、非常にデバッグしやすいという利点があります。
複雑なコードを書かないと実感はできないですが、これからもあちこちに使います。
よくわからなければ無視しても構いません。
関数の改良
一度に二つのコードを出していますが、
一つ目は元の関数を少し「汎用的にして」「elseをなくした」だけ。
二つ目は「関数の宣言と実装を切り分けた」だけです。
結果も合わせて画像にしました。
「汎用的にして」
関数は使いまわしができるように作っていくとよいでしょう。
前回はチェックされる側の値だけを入れましたが、
今回はチェックする側の値も引数として設定できるようにしています。
こうすることで二つの整数を指定すると、
その大小を文字列で返すという汎用的な関数ができたことになります。
「elseをなくした」
プログラムをするとき、ちょっとだけ上手な書き方をするコツとして、
returnを上手に使ってelseを使わないようにするというのがあります。
Aの場合の処理はここまで、という形でifの中でreturnを使うことでelseの処理を省略する。
それだけでかなり見た目がすっきりしますね。
「関数の宣言と実装を切り分けた」
Cでは「ある関数がほかの関数を呼び出すには、その関数が事前に宣言されていなくてはいけない」というルールがあります。
ただし「同じ名前の関数を何度も実装することはできない」というルールもあります。
同じプログラムの中に複数の同じ名前の関数があると、
どの動きをするのかコンピュータには判断できないためです。
ただ、これが少し厄介で、
今回はまだ問題になっていませんが、
もしcheckの中でmainを呼びたい場合は「どちらを先に書いても、もう一方が呼べない」状態になります。
そこで
「関数の宣言と実装を切り分けることで、実装を一度だけにする」という、
なんだかちょっとずるい方法をとります。
宣言で名前を予約しておくことで、呼び出しができるようになります。
そして、実装で中身の処理を書いて実際に動かせるようにします。
(名前だけたくさんあっても、結局どんな動きをすればよいかは一つなので迷わずに済みますよね)
ヘッダーを使う
今回は「関数の宣言を別のファイルに書く」ことにしました。
「関数の宣言を別のファイルに書く」
前回、関数の宣言と実装を切り分けましたが、
もう少し説明をすると「宣言は何度でもできる」「実装は一度しかできない」というルールがあります。
そして「宣言を先にしていないと関数を呼び出せない」ことも思い出してください。
もし複数のファイルで同じ関数を使いたいときはどうすればよいでしょうか。
全部のファイルに宣言を手動でコピペするのは面倒です。
答えは簡単。プリコンパイル文を使って、
ヘッダーファイルをコンパイラーにコピペさせることで、
色々なファイルからその関数を呼べるようにしています。
「ヘッダーファイル」
プリコンパイル文で「ファイル名を指定してコピペする」と説明していますが、
これは良くも悪くも、実際に本当に貼り付けを行っています。
そこでCにはヘッダーという仕組みが用意されました。
ヘッダーには「こんな関数が呼べるよという宣言だけ用意」して、
実装は個々のファイルで行うわけです。
チャレンジしてみよう
ここで練習問題にチャレンジしてみましょう。
すでに伝えている内容と、基本的な演算の知識(+-*/%)があれば解ける問題です。
0から20までの数字全部について
基本的には数字を表示し
3の倍数なら数字ではなくfizzを
5の倍数なら数字ではなくbuzzを
両方ならfizzbuzzを表示してください。
例答のソースコードは最下部のコメント欄に貼り付けしてあります。
よければ「俺はこう書いたよ!」みたいなのも見せてください。
おわりに
さて、超入門らしく駆け足でしたが、
なんとなくCでも処理を書けそうな気になってきたでしょうか。
次はもうちょっとゲームらしい処理などをやってみたいと思います。