↓↓クリックして頂けると励みになります。
【14 | ポインター(pointer)】 << 【ホーム】 >> 【16 | while】
C++における関数の宣言は、プログラム内で関数がどのような機能を持ち、どのような引数を受け取り、何を返すかを示すものです。
関数の宣言には2つの主要な要素があります。
関数のプロトタイプ宣言(Function Prototype):
関数のプロトタイプ宣言は、関数がどのような型の引数を取り、何を返すかを示す宣言です。プロトタイプ宣言は通常、関数定義の前に配置されます。これにより、関数が使用される前に、その関数のシグネチャ(signature)がコンパイラに知られるようになります。
関数のシグネチャ(signature)は、その関数の名前と、その関数が受け取る引数の型や数、戻り値の型などの情報を含む、関数の一意な識別子です。シグネチャは、関数がオーバーロードされている場合や、関数が他の関数と区別される必要がある場合に重要な役割を果たします。
関数の定義(Function Definition):
関数の定義は、実際に関数が何を行うかを示すコードブロックです。関数の定義は、関数名、引数のリスト、関数の戻り値の型、および関数の本体から構成されます。
関数の宣言は、ヘッダーファイル(.h)や、他のソースファイルに存在する関数を他のソースファイルから利用する場合に重要です。
プロトタイプ宣言により、他のソースファイルが関数を使用する際に、その関数のシグネチャにアクセスできるようになります。
C++では、関数のプロトタイプ宣言は必須ではありませんが、関数が複数のソースファイルで使用される場合や、関数が他の関数より前に使用される場合には、プロトタイプ宣言をすることが一般的です。
Visual Studio Codeで以下のcppファイルを作成して下さい。
新規作成 【Game1.cpp】
#include <iostream> #include <stdlib.h> int yesno( ); void current_point( ); void enemy_create( ); void hero_create( ); int escape( ); void calc_parameter( int suit, int strong ); void hero_die( ); void show_status( ); void map_create( ); void get_drug(int exist, int strong); int pos_compare(int a_x, int a_y, int b_x, int b_y); void walk_around( char move ); void use_drug( ); void get_enemyitem( ); void fight( ); void command( ); /* enemy */ int enemy_x; int enemy_y; int enemy_life; int enemy_offence; int enemy_defence; int enemy_item_suit; int enemy_item_strong; /* map */ int map_wide_x; int map_wide_y; int map_ent_x; int map_ent_y; int map_floor=0; int map_item_exist; int map_item_strong; int map_item_x; int map_item_y; /* hero */ int hero_point; int hero_x; int hero_y; int hero_life; int hero_life_upper; int hero_offence; int hero_defence; int hero_drug; int hero_sword; int hero_buckler; int hero_armer; int main() { int input; hero_create(); map_create(); current_point(); std::cout << "Input senario Number => "; std::cin >> input; std::cin.clear(); std::cin.ignore(); srand(input); for(;;) { if(enemy_life <= 0) { enemy_create( ); } std::cout << "現在位置 (" << hero_x << "," << hero_y << "):地下 " << map_floor << "階" << std::endl << std::endl; command(); if( pos_compare(map_item_x,map_item_y,hero_x,hero_y)){ get_drug(map_item_exist, map_item_strong); map_item_exist=0; } if( pos_compare(map_ent_x,map_ent_y, hero_x,hero_y)) { std::cout << "階段があった。下に降りますか? "; if(yesno() == 1) { map_create(); enemy_create(); current_point(); std::cout << std::endl << std::endl << "地下 " << map_floor << "階に降りた。" << std::endl << std::endl; } } if (pos_compare(hero_x,hero_y, enemy_x,enemy_y)) { int point=hero_point; fight(); if(point < hero_point) { enemy_create(); } } } } void map_create( ) { map_floor++; map_wide_x = rand()%( 2 + map_floor) + 10; map_wide_y = rand()%( 2 + map_floor) + 10; map_ent_x = rand()%map_wide_x; map_ent_y = rand()%map_wide_y; map_item_exist=1; map_item_strong= rand()%( 10+10*map_floor) + 30; map_item_x=rand()%map_wide_x; map_item_y=rand()%map_wide_y; return; } void show_status( ) { std::cout << std::endl << "現在の状況:" << std::endl; std::cout << "体力: " << hero_life << "/" << hero_life_upper << "\t攻撃力:" << hero_offence << "\t守備力:" << hero_defence << std::endl; std::cout << "\t経験値:" << hero_point << std::endl; std::cout << std::endl; std::cout << "持ち物のレベル" << std::endl; std::cout << "剣:" << hero_sword << "\t盾:" << hero_buckler << "\t鎧:" << hero_armer << std::endl << std::endl; std::cout << "薬の回復力:" << hero_drug << std::endl << std::endl << std::endl; return; } void hero_die( ) { std::cout << "Hero is died at floor " << map_floor << "." << std::endl; std::cout << std::endl; std::cout << "status" << std::endl; std::cout << "hero level " << hero_point/10 << std::endl; std::cout << std::endl; std::cout << "Game Over" << std::endl; exit(0); } void calc_parameter( int suit, int strong ) { if(suit==1) { hero_offence = hero_offence - hero_sword + strong; hero_sword = strong; } else if(suit==2) { hero_defence = hero_defence - hero_buckler + strong; hero_buckler = strong; } else if(suit==3) { hero_defence = hero_defence - hero_armer + strong; hero_armer = strong; } return; } void use_drug( ) { if(hero_drug > 0) { hero_life += hero_drug; if(hero_life_upper < hero_life) { hero_life = hero_life_upper; } hero_drug=0; std::cout << std::endl << "\t薬を使った。\b" << std::endl << std::endl; show_status(); } else { std::cout << std::endl << "\t薬は今持ってない。" << std::endl << std::endl; } } void get_enemyitem( ) { if ( enemy_item_suit!=0 ) { show_status(); std::cout << "\t敵はアイテムを持っていた。" << std::endl; if(enemy_item_suit==1) { std::cout << "剣:level " << enemy_item_strong << std::endl; } else if( enemy_item_suit==2) { std::cout << "盾:level " << enemy_item_strong << std::endl; } else if(enemy_item_suit==3) { std::cout << "鎧:level " << enemy_item_strong ; } std::cout << "装備するか?"; if(yesno()) { std::cout << "\tヒーローの状態が変わった。\b" << std::endl << std::endl; calc_parameter(enemy_item_suit, enemy_item_strong); show_status(); } else { std::cout << "\tアイテムを捨てた!" << std::endl << std::endl; } } else { std::cout << "\t敵はアイテムを持っていなかった。" << std::endl << std::endl; } return; } int escape() { int x, y; x = rand()%10; y = rand()%10; if( x < y ) { return !0; } else { return 0; } } void fight() { int dum; for(;;) { show_status( ); std::cout <<"敵と戦いますか?"; if ( yesno()==0 && escape() == 1){ std::cout << "\t敵から逃げました。" << std::endl << std::endl; break; } else { std::cout << "\t敵と戦います。" << std::endl << std::endl; } std::cout << "Heroの攻撃:"; dum = (hero_offence*(rand()%10)) / (enemy_defence+1); enemy_life -= dum; std::cout << "敵に " << dum << "のダメージ" << std::endl << std::endl; if(enemy_life -= dum){ std::cout << "\t敵を倒した!\b" << std::endl << std::endl; hero_point ++; hero_life_upper+=10; std::cout << "\tレベルが上がった。\b" << std::endl << std::endl; get_enemyitem( ); break; } std::cout << "敵の攻撃:"; dum = (enemy_offence*(rand()%10)) / (hero_defence+1); hero_life -= dum; std::cout << dum << "のダメージを受けた!" << std::endl << std::endl; if (hero_life <=0) { hero_die(); } } return; } void hero_create() { hero_point = 0; hero_life_upper = 100 + rand()%10; hero_life = hero_life_upper; hero_x = 0; hero_y = 0; hero_offence = rand()%5 + 5; hero_defence = rand()%5 + 5; hero_drug = 0; hero_sword = rand()%3 +1; hero_buckler=rand()%3; hero_armer = rand()%2 +1; return; } void enemy_create() { int i; enemy_x = rand() % map_wide_x; enemy_y = rand() % map_wide_y; enemy_life = rand() % 100 + map_floor*50; enemy_offence=rand() % 10 + map_floor; enemy_defence=rand() % (map_floor+2); if ( rand() % 2 == 1 ) { i=rand()%3+1; enemy_item_suit=i; if(i==1) { enemy_item_strong = rand()%(10 + map_floor); } else if ( i==2) { enemy_item_strong = rand() % (5 + map_floor); } else { enemy_item_strong = rand() % (7 + map_floor); } } else { enemy_item_suit = 0; enemy_item_strong = 0; } return; } void command() { char input; std::cout << "Command mode" << std::endl; std::cout << " up: k" << std::endl; std::cout << "left:h status:s right:l" << std::endl; std::cout << " down: j" << std::endl << std::endl; std::cout << "use drug:d Quit:q" << std::endl; for(;;) { std::cout << "command input => "; std::cin >> input; if(!std::cin) { std::cout << "Error:"; std::cin.clear(); std::cin.ignore(); } else { if (input=='d') { use_drug(); std::cin.clear(); std::cin.ignore(); break; } else if (input == 's' ) { show_status(); std::cin.clear(); std::cin.ignore(); break; } else if (input=='j' || input=='k' || input=='l' || input=='h') { walk_around(input); std::cin.clear(); std::cin.ignore(); break; } else if(input=='q') { std::cin.clear(); std::cin.ignore(); exit(0); } } } return; } /* move lower j: left l: right h: upper k */ void walk_around( char move ) { if(move=='l') { if( hero_x == map_wide_x) { std::cout << "その方向には歩けません!" << std::endl; return; } hero_x++; } else if(move=='k') { if(hero_y == map_wide_y) { std::cout << "その方向には歩けません!" << std::endl; return; } hero_y++; } else if (move=='h'){ if(hero_x == 0) { std::cout << "その方向には歩けません!" << std::endl; return; } hero_x--; } else if (move=='j') { if(hero_y == 0) { std::cout << "その方向には歩けません!" << std::endl; return; } hero_y--; } return; } int pos_compare(int a_x, int a_y, int b_x, int b_y) { if ( a_x == b_x && a_y == b_y ) { return !0; } else { return 0; } } void get_drug(int exist, int strong) { if(exist == 1) { std::cout << std::endl; std::cout << "\t薬(" << strong << ")を拾った!\b" << std::endl << std::endl; hero_drug+=strong; } return; } void current_point() { hero_x = rand()%map_wide_x; hero_y = rand()%map_wide_y; return; } int yesno() { char input; for(;;){ std::cout << "yes or no (y/n) => "; std::cin >> input; if(!std::cin) { std::cout << "Error:" << std::endl << std::endl; std::cin.clear(); std::cin.ignore(); } else { if(input=='y' || input=='Y') { std::cin.clear(); std::cin.ignore(); return !0; } else if (input=='n' || input=='N') { std::cin.clear(); std::cin.ignore(); return 0; } } } }
このゲームの内容について説明します。
主人公は地下のダンジョンを冒険し、より深い地下に降りていくのが使命です。
地下の階はある広さがあり、主人公の位置は(7,4)のように座標で表示されます。
敵は1人だけしか一度には出てきませんが、敵を殺すと新たな敵が現れます。
敵は動けませんが、強さや装甲の堅さは乱数で決まります。
主人公が敵と同じマス目にはいると戦闘が始まります。
逃げることも出来ますが、逃走が成功するかどうかも乱数で決まります。
勝って勝利すると、敵が持っている強化アイテムを手に入れられます。(持っていないときもあります。)
またマップには薬が必ず落ちています。
薬には主人公の生命力を回復させる働きがあります。
薬には強さがあり、薬を拾うとその強さが加算されています。
薬は使うとなくなってしまいます。
敵の位置はわかりません。
また、地下への階段がどこかに必ずあります。
まず関数の定義をもう一度書いておきます。
返り値の型 関数名 ( 引数, 引数, ・・・・){ 実行文; }
ここで返り値の型を指定すると関数の返り値を整数以外にとることができます。
例 文字の整数値を与えると対応する文字を返す char mojikansuu(int a) { char c; c = a; return c; }
この例では関数の名前の前にcharがあるので関数mojikansuu()
は文字型の関数となり、返り値は文字型でなければなりません。
もう1つ例をあげます。
例 ポインタを返す char *string() { const char *s = "this is a test."; return s; }
この例はアドレスを返す関数の例です。
「[型]*
」はポインタを意味していますので返り値はアドレスでなくてはなりません。
例では「"this is a test."
」という文字列のアドレスを返しています。
関数の宣言について説明します。
関数を作ったときに、積極的にコンパイラにその関数の型や引数を教えてあげると、コンパイラはもし間違った関数の呼び出しをしたときにきちんとその旨を知らせてくれます。
このようにコンパイラに関数の仕様を知らせるために関数の仕様を書くことを関数の宣言といいます。
関数の宣言はファイルの先頭、すなわち#include文の後に書いておくと良いでしょう。
関数の型 関数名 ( 引数, 引数, ・・・・);
例 char mojikansuu(int a); char *string(void);
もし関数に引数がある場合は引数の型もちゃんと宣言しなければなりません。
ただし引数の変数名は完全なダミーなので名前を変えることもできますし、省略することもできます。
char mojikansuu(int num); char mojikansuu(int);
宣言の最後にセミコロン(;
)をつけることを忘れないようにしなければなりません。
関数の引数がない場合はvoidを使ってください。
これによりコンパイラは「この関数には引数がない」を理解できます。
ただしchar *string();
というように、voidを省略して宣言することもできます。
関数の宣言がない場合はコンパイルエラーがおこりますので、かならずmain関数の前に関数の記述しておく癖をつけておいてください。
関数には引数としてアドレスを渡すことができます。
関数は結果を一つしか返すことができません。
複数の結果を返したいときは変数のアドレスを渡すことで直接その値を操作することができます。
void str(const char *add) ; int main() { const char *s="this is a test."; str(s); std::cout << s << std::endl; } void str(const char *add) { const char *p= add; }
この例の場合、main()
で宣言している文字列"this is a test."
のアドレスを関数str()
に渡しています。
もちろん関数str()
でもそのアドレスを受け取ることができるように、引数の宣言に「const char *add
」を用いている点に注意してください。
その結果addには先の"this is a test"
のアドレスが代入されることになります。
従ってmain()
関数での文字列出力でも「"this is a test."
」となります。
文字型ポインタではこのプログラムで「std::cout << *s << std::endl;
」とすると「"t"
」のみが出力されます。
この違いを覚えておいてください。
グローバル変数について少し書いておきます。
これまで学習してきた変数はすべて関数の中のみで有効でしたが、他の関数からも見ることができるような変数を作ることもできます。
このような変数をグローバル変数といいます。
C言語ではグローバル変数は2種類あり、同じプログラムソースにあるものと違うプログラムソースにあるグローバル変数とは違う扱いになります。
ここでは同じプログラムソースにあるグローバル変数の宣言の仕方を学びます。
ファイル内で有効なグローバル変数を宣言するには関数の外側、ファイルの最初のところで宣言すればよいです。
グローバル変数の例 #include <iostream> int gloval = 1; /*グローバル変数*/ void test() { std::cout << "グローバル変数" << gloval << std::endl; } int main() { std::cout << "グローバル変数" << gloval << std::endl; gloval++; test(); }
この例では最初にグローバル変数は1に設定されていて、main()
の中で表示するときは1になっています。
次にその値を2に増やして関数testを呼ぶと、関数testの中で表示しても確かに2になっています。
最後に文字リテラルについて説明します。
ダブルコーテーション(””
)で囲こみ、出力させる文字列の中に「¥t
」や「¥b
」というのを使用しています。
これを文字リテラルといいます。
文字リテラルは以下のように変換されます。
¥n
改行¥t
水平タブ¥v
垂直タブ¥b
バックスペース¥¥
円記号サンプルプログラムを実行して動作を確認します。
~/Desktop/Programming/CPP $ cd "/Users/heyjude/Desktop/Programming/CPP/" && g++ Game1.cpp -o Game1 && "/Users/heyjude/Desktop /Programming/CPP/"Game1 Input senario Number => 1 現在位置 (2,3):地下 1階 Command mode up: k left:h status:s right:l down: j use drug:d Quit:q command input => j 現在位置 (2,2):地下 1階 Command mode up: k left:h status:s right:l down: j use drug:d Quit:q command input => l 現在位置 (3,2):地下 1階 Command mode up: k left:h status:s right:l down: j use drug:d Quit:q ・・・ ・・・ ・・・ command input => l 階段があった。下に降りますか? yes or no (y/n) => y 地下 2階に降りた。 現在の状況: 体力: 107/107 攻撃力:9 守備力:8 経験値:0 持ち物のレベル 剣:3 盾:1 鎧:1 薬の回復力:0 敵と戦いますか?yes or no (y/n) => y 敵と戦います。 Heroの攻撃:敵に 40のダメージ 敵を倒した! レベルが上がった。 敵はアイテムを持っていなかった。 現在位置 (2,3):地下 2階 Command mode up: k left:h status:s right:l down: j use drug:d Quit:q command input =>
【14 | ポインター(pointer)】 << 【ホーム】 >> 【16 | while】
↓↓クリックして頂けると励みになります。