関数と引数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
華子

関数と引数について

#1

投稿記事 by 華子 » 11年前

はじめまして
以前からこの質問掲示板を見させていただき、みなさんの意見を参考にさせていただいています。

さっそく質問なんですが、
要点だけ話ますと
printfのように、任意の数(printfの場合%dの数)引数を定義できる関数の作り方
ifやwhileのように中括弧を使える関数の使い方
です。

私は龍神録を参考にSTGを作っているのですが、
敵の移動パターンをいくつか作り、それを一つの関数にまとめたのですが、
その移動パターンをまとめた時、
・移動して、一定の時間がたつと引数waitの時間だけ停止、その後また移動を始める
・引数angleの値だけ旋回して移動
これらを一つにまとめEnemyMoveという関数を作り、

コード:


//敵の移動パターンと描画をする関数
void EnemyMove(int x,int y,int number,int movepattern,int wait,int angle){

 //ゲームのカウントと引数のカウントがあうと、敵を描画移動させるフラグを立てる処理

    if(movepattern==0)
      //移動して、一定の時間がたつと引数waitの時間だけ停止、その後また移動を始める処理
  if(movepattern==1)
  //引数angleの値だけ旋回して移動する処理

 DrawGraph(x,y,enemy[number].img,TRUE);//敵キャラの描画
  
}

void EnemyMain(){
  EnemyMove(100,100,0,0,150,0);
  EnemyMove(200,100,1,0,150,0);
 
  EnemyMove( 50,  0,2,1,0,PI);
  EnemyMove( 50, 50,3,1,0,PI);

  EnemyMove( 100,100,4,1,0,PI/2);

}


質問と関係ない部分をだいぶ省略していますが、
EnemyMainにEnemyMoveを追加することで書いた関数の数だけ敵が表示できるようになっています
この時、引数MovePatternが0の時(つまり移動中一旦停止する移動パターン)の時、引数angleは移動の処理に関係なく、
1の時(移動時に旋回する移動パターン)の時はwaitの変数が必要ありません

これを引数MovePatternに0が入った時、1が入った時、さらにはまた移動パターンを追加することになると思いますが、引数MovePattern以降の引数の名前や数が変わるように関数を作成したいのです。


もうひとつの
ifやwhileのように中括弧を使える関数の使い方
についてですが

コード:

#include <stdio.h>

void a(int x){
 //なんらかの処理
}

void main(){

 int x=2;

 a(x){
  printf("ABC\n");
 }

 return 0;

}

上記のプログラムの関数aのように関数をaを使用する際、中括弧を使用する関数を作りたいです。

説明不足かもしれませんが回答よろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 関数と引数について

#2

投稿記事 by softya(ソフト屋) » 11年前

その1の質問に関しては、引数の数を変えれる可変引数は害が多いので使用はしないほうが良いです。避けて下さい。
別の方法として省略時にデフォルト値を入れることはC++では可能です。

その2の質問は意図がわかりません。どの様な動作を期待されているのでしょう。説明して頂けますか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華子

Re: 関数と引数について

#3

投稿記事 by 華子 » 11年前

返信ありがとうございます

省略時にデフォルト値を入れることについてどのように書けば可能でしょうか?
また、可変引数についてですが
私はmicrosoftVC++を使用し、ゲームの作成に取り掛かっています。
VC++に限った話ではないのかもしれませんが、
関数を作成し、それを使用する際、EnemyMove( まで書くと、引数名が表示されます。
引数名が変わることがわかるので、可変引数を使用しても問題ないような気もします。どのような害があるか教えてもらえますか?

二つ目の質問については説明不足でした。すいませんでした。
たとえばprintfの前後にprintf("ABC\n");と入力させたい場合、

コード:

main(){
  printABC(){
    printf("EFG\n");
  }
  return 0;
}
////////実行結果////////////
ABC
EFG
ABC


このように前後に計2つの関数を書かずに、中括弧で囲むことで1つの関数で前後2つにprintf("ABC\n");が入るような関数を作りたいのです。

また、引数の値で前後に入力される値がABCでなくEFGになったりするようにしたいです。

nil
記事: 428
登録日時: 12年前

Re: 関数と引数について

#4

投稿記事 by nil » 11年前

引数の個数が可変であるということは何が渡されるかわからない、また渡されないかもしれない、ということです。
C言語で例を挙げるとするならば、

コード:

printf( "%x%x%x%x%x%x%x%x%x%x\n" );
こう書けばメモリの中が覗けます。

デフォルト値は関数宣言に
void Func( int a, int b=0, int c=3 );
などというふうに書くことで可能になります。

中括弧ですが、マクロを用いれば可能でしょうが
これはC++としての文法を崩すものですのでおすすめはできません。
また、必要な意味もわかりません。
普通に関数化なさったほうが賢明です。

コード:

void printABC( const char* str ){
    printf( "ABC\n" );
    printf( "EFG\n" );
    printf( "ABC\n" );
}
int main(){
    printABC( "EFG" );
}
最後に編集したユーザー nil on 2012年11月24日(土) 17:06 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 関数と引数について

#5

投稿記事 by softya(ソフト屋) » 11年前

華子 さんが書きました:関数を作成し、それを使用する際、EnemyMove( まで書くと、引数名が表示されます。
引数名が変わることがわかるので、可変引数を使用しても問題ないような気もします。どのような害があるか教えてもらえますか?
可変引数を使うと表示されなくなります。
つまり未定にすることで可変引数を可能にするので型チェックも行われません。
型が不明になるので処理は自己責任になります。
これは,バグの確率を飛躍的に高めます。
「動的引数」
http://wisdom.sakura.ne.jp/programming/c/c62.html
華子 さんが書きました:省略時にデフォルト値を入れることについてどのように書けば可能でしょうか?
C++オプションでコンパイルしている場合限定ですが、プロトタイプ宣言で
void EnemyMove(int x,int y,int number,int movepattern,int wait=0,int angle=0);
と書くだけです。この場合は、waitとangleが省略できます。
華子 さんが書きました:このように前後に計2つの関数を書かずに、中括弧で囲むことで1つの関数で前後2つにprintf("ABC\n");が入るような関数を作りたいのです。

また、引数の値で前後に入力される値がABCでなくEFGになったりするようにしたいです。
すいません。これ論理性が破綻していると思います。
ABCが2つ表示されるというプログラムの流れがまったく見えません。
ABC
EFG
ABC
と出力される想定のコードを全部書いてみて下さい。
こう書いただけで出力されるとは思っていませんよね?

コード:

main(){
  printABC(){
    printf("EFG\n");
  }
  return 0;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華子

Re: 関数と引数について

#6

投稿記事 by 華子 » 11年前

返信ありがとうございます

今回私が質問した内容は
可変引数、マクロ宣言、どちらもあまり使用しない方がよいということですね

また自分で資料を見てこれらのことについて勉強します。
今回はありがとうございました

華子

Re: 関数と引数について

#7

投稿記事 by 華子 » 11年前

ソフト屋さん返信ありがとうございます
可変引数(動的引数)についてはあきらめます
参考のURL拝見させていただきます。
ありがとうございます
プロトタイプ宣言で
void EnemyMove(int x,int y,int number,int movepattern,int wait=0,int angle=0);
と書くだけです。この場合は、waitとangleが省略できます。
こう書くと、全てのEnemyMoveに対してwait=0、angle=0が適用されませんか
0以外の値が必要な場合はどのようになるのでしょうか
それともこう書いておけば、たとえばwait必要な時、angleについては書かなくても0が入力されているということでしょうか


2つ目の質問についてですが

コード:

main(){
  printABC(){
    printf("EFG\n");
  }
  return 0;
} 
実行結果
ABC
EFG
ABC

と中括弧内の関数の前後にABCと入力される関数printABCの適切な書き方を知りたく、あえて前の返答に書いたvoid printfABC( を書きませんでした
省略しすぎましたすいませんでした。

コード:

#include <stdio.h>
void printfABC(){
  //中括弧内の関数の前後にABCと出力させる処理
}
int main(){
  printABC(){
    printf("EFG\n");
    printf("HIJ\n");
  }
  return 0;
}

引数の中に文字を入れるよう返答をいただきましたが、
このようにABCに挟まれる関数が2つ以上ある場合、
その挟まれる関数が任意に変化する場合
この場合引数に入れる場合、1つ目の質問のように動的引数を使用しなければならないと思いました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 関数と引数について

#8

投稿記事 by softya(ソフト屋) » 11年前

華子 さんが書きました: こう書くと、全てのEnemyMoveに対してwait=0、angle=0が適用されませんか
0以外の値が必要な場合はどのようになるのでしょうか
それともこう書いておけば、たとえばwait必要な時、angleについては書かなくても0が入力されているということでしょうか
実引数が省略された時の仮引数の値を設定するための文法です。
省略されなければ、実引数の値がそのまま入ります。

2つ目の質問は、やっぱりやりたいことがわかりませんが、あえて書くとしたらコールバックでしょうか。
※ 関数内関数はC/C++では書けません。javascriptの様な無名関数もありません。

コード:

#include <stdio.h>

void printfABC( void (*callBackFunc)(void) ) {
	//	中括弧内の関数の前後にABCと出力させる処理
	printf("ABC\n");
	callBackFunc();//引数の関数をコールバックで呼び出し。
	printf("ABC\n");
}

//コールバックされる関数
void printEFG(void) {
	printf("EFG\n");
	printf("HIJ\n");
}

int main(){
	printfABC( printEFG ); //printfABCをprintEFG を引数として呼び出す。
	return 0;
}
華子 さんが書きました: このようにABCに挟まれる関数が2つ以上ある場合、
その挟まれる関数が任意に変化する場合
この場合引数に入れる場合、1つ目の質問のように動的引数を使用しなければならないと思いました。
複数渡すなら配列にして下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: 関数と引数について

#9

投稿記事 by beatle » 11年前

中括弧{ }の効果を誤解しているような気がします。中括弧はブロック文を作り出すものでして、例えば

コード:

int main() {
  {
    int i = 0;
    printf("%d\n", i);
  }

  {
    int i = 0;
    printf("%d\n", i);
  }
}
こんな風に、複数の文(=ステートメント、int i = 0;とか、printf("%d\n", i);とか)をまとめて一つの文「複文」を作ります。
{ }で囲まれたものが関数になるわけではないのです。

そして、関数の引数に渡せるのは「式」だけですので、{ }で囲んだ複文を引数として渡すことはできません。

華子

Re: 関数と引数について

#10

投稿記事 by 華子 » 11年前

返信ありがとうございます。

コールバックに関しても参考にさせていただきます

解決しているのに、質問してしまい申し訳ありませんでした
そして、それにも関わらず回答していただいたこと心より感謝いたします。
ありがとうございました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 関数と引数について

#11

投稿記事 by softya(ソフト屋) » 11年前

私が解決マークを外してしまったので、もう一度解決マークをしてよいでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華子

Re: 関数と引数について

#12

投稿記事 by 華子 » 11年前

お願いします
わざわざすいません

たかぎ
記事: 328
登録日時: 13年前
住所: 大阪
連絡を取る:

Re: 関数と引数について

#13

投稿記事 by たかぎ » 11年前

二つ目の質問については、マクロを使って強引に実現することも可能です。
例えば、こんな感じにです。

コード:

#include <stdio.h>
#include <memory>

struct printABC_impl
{
  printABC_impl()
  {
    printf("ABC\n");
  }
  ~printABC_impl()
  {
    printf("ABC\n");
  }
};

#define printABC() if (auto p = std::make_shared<printABC_impl>())

int main()
{
  printABC()
  {
    printf("EFG\n");
  }
}
決してお勧めはしませんが、稀にどうしてもこのような技法が必要になることもありますからね。

閉鎖

“C言語何でも質問掲示板” へ戻る