関数名をchar型変数で代替したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
eupher
記事: 8
登録日時: 2ヶ月前

関数名をchar型変数で代替したい

#1

投稿記事 by eupher » 1週間前

下記のコードは、main関数内のint型変数a(=10),b(=20)を、合計値を出力する関数sumに渡すプログラムです。

コード:

#include <stdio.h>

void sum( int a, int b ){
	printf( "%d\n", a+b );
}

int main(void){
	int a = 10;
	int b = 20;
	//char name[10] = "sum";
	sum( a, b );
	return 0;
}
このプログラムで、

コード:

sum( a, b );
の"sum"の代わりに、

コード:

char name[10] = "sum";
の"name"を利用できたら便利だなと思ったのですが、可能でしょうか?

アバター
あたっしゅ
記事: 150
登録日時: 7年前
住所: 東京23区
連絡を取る:

Re: 関数名をchar型変数で代替したい

#2

投稿記事 by あたっしゅ » 1週間前

>"name"を利用できたら便利だなと思ったのですが、可能でしょうか?

「"name"を利用できたら便利」というのは、具体的には、どのようなことでしょうか ?

strcpy( name, "sum" );
name( a, b ); // 30
strcpy( name, "sub" );
name( a, b ); // -10

みたいなことでしょうか ?
手提鞄あたっしゅ、[MrAtassyu]

eupher
記事: 8
登録日時: 2ヶ月前

Re: 関数名をchar型変数で代替したい

#3

投稿記事 by eupher » 1週間前

コード:

#include <stdio.h>

void sum1( int a, int b ){
	printf( "%d\n", a+b );
}
void sum2( int a, int b ){
	printf( "%d\n", a+a+b );
}
void sum3( int a, int b ){
	printf( "%d\n", a+b+b );
}

int main(void){
	int a = 10;
	int b = 20;
	char name[10];
	/*1*/
	sum2( a, b );		//関数sum2に値を渡す
	/*2*/
	scanf("%s",name);	//例)"sum2"と入力
	name( a, b );		//関数sum2に値を渡す
	
	return 0;
}
ご回答ありがとうございます。質問内容の不足、失礼致しました。
例えになりますが上のような流れのプログラムが作成できればと思いました。もちろん上のプログラムは実行してもエラーになるのですが、/*1*/のように"sum1"や"sum2"という文字を直接記載しなくても、/*2*/のようにnameに格納された"sum1"や"sum2"が関数名としての役割をできないかなと思っています。

あたっしゅ様の書かれた

コード:

strcpy( name, "sum" );
name( a, b ); // 30
strcpy( name, "sub" );
name( a, b ); // -10
に変えて試したのですがうまく動きませんでした…。string.hもちゃんと書いたのですが、すみません。

かずま

Re: 関数名をchar型変数で代替したい

#4

投稿記事 by かずま » 1週間前

こんなのはいかがですか?

コード:

#include <stdio.h>   // printf, puts, scanf
#include <string.h>  // strcmp

void sum1(int a, int b) { printf("%d\n", a + b); }
void sum2(int a, int b) { printf("%d\n", a + a + b); }
void sum3(int a, int b) { printf("%d\n", a + b + b); }
void error(int a, int b) { puts("error"); }

void (*func(const char *f))(int, int)
{
	if (!strcmp(f, "sum1")) return sum1;
	if (!strcmp(f, "sum2")) return sum2;
	if (!strcmp(f, "sum3")) return sum3;
	return error;
}

int main(void)
{
	int a = 10, b = 20;
	char name[10];

	while (scanf("%s", name) == 1)
		func(name)(a, b);
}

eupher
記事: 8
登録日時: 2ヶ月前

Re: 関数名をchar型変数で代替したい

#5

投稿記事 by eupher » 1週間前

ご回答ありがとうございます。返信が遅れて失礼しました。
早速試したところ、こちらでもうまく動きました。
文字列を戻り値で渡すというのは思いつかなかったのですごく勉強になりました。本当にありがとうございました。


〇解決したコード

コード:

#include <stdio.h>   // printf, puts, scanf
#include <string.h>  // strcmp

void sum1(int a, int b) { printf("%d\n", a + b); }
void sum2(int a, int b) { printf("%d\n", a + a + b); }
void sum3(int a, int b) { printf("%d\n", a + b + b); }
void error(int a, int b) { puts("error"); }

void (*func(const char *f))(int, int)
{
	if (!strcmp(f, "sum1")) return sum1;
	if (!strcmp(f, "sum2")) return sum2;
	if (!strcmp(f, "sum3")) return sum3;
	return error;
}

int main(void)
{
	int a = 10, b = 20;
	char name[10];

	while (scanf("%s", name) == 1)
		func(name)(a, b);
}

かずま

Re: 関数名をchar型変数で代替したい

#6

投稿記事 by かずま » 1週間前

eupher さんが書きました:
1週間前
文字列を戻り値で渡すというのは思いつかなかったのですごく勉強になりました。
関数 func は、文字列 name を引数として渡すと、
「関数へのポインタ」を戻り値で返してくる
ということが本当に分かっていますか?
eupher さんが書きました:
1週間前
〇解決したコード
私の提示したコードと何も変わっていませんね。
自分の書き方に変えましょう。
たとえば、
・f というのは分かりにくい。name にしよう。
・! よりも == 0 のほうが違和感がない。
・if文の中の文には { } を付ける主義だ。
など

コード:

void (*func(const char *name))(int, int)
{
	if (strcmp(name, "sum1") == 0) {
		return sum1;
	}

eupher
記事: 8
登録日時: 2ヶ月前

Re: 関数名をchar型変数で代替したい

#7

投稿記事 by eupher » 6日前

フォーラム(掲示板)ルールにソースコードや解決した方法を明記しろ、と書いてあったので記載しました。不快に思われたのでしたら申し訳ないです。

かずま様の回答を見た際に「なんでfunc関数の前に*がついているんだろう…?」「そもそもvoid型なのにreturnを使ってる…?」とかいろいろ思いましたが、おかげで関数ポインタを知るきっかけになりました。手元の教科書には関数ポインタが載ってなかったのでネットでなんとなく理解した程度ですが、かなり便利です。

せっかくなので私なりに書いてみました。こんなのでも正しい実行結果が出るので驚きです。

コード:

#include <stdio.h>

void sum1( int a, int b ) { printf( "%d\n", a+b ); }
void sum2( int a, int b ) { printf( "%d\n", a+a+b ); }
void sum3( int a, int b ) { printf( "%d\n", a+b+b ); }
void error( void ) { printf( "error" ); }

int main( void )
{
	int a = 10, b = 20, i;
	void (*p[])( int ,int ) = { sum1, sum2, sum3 };
	scanf( "%d" ,&i );
	if( i<1 || 3<i ){
		error();
	}else{
		(*p[i-1])( a, b );
	}
	
	return 0;
}

かずま

Re: 関数名をchar型変数で代替したい

#8

投稿記事 by かずま » 6日前

eupher さんが書きました:
6日前

コード:

	void (*p[])( int ,int ) = { sum1, sum2, sum3 };
関数へのポインタの配列とは、もう型はバッチリですね。

sum1 が関数なら、&sum1 が「関数へのポインタ」ですから、
sum1 の代わりに &sum1 と書くこともできます
sum1 と書いてもいいのは、関数は一部の例外を除いて
常に「関数へのポインタ」に変換されるからです。

関数呼出し演算子「(実引数式の並び)」はオペランドに
「関数へのポインタ」を要求するので、
(*p[i-1])(a, b); は、p[i-1](a, b); と書くこともできます。

これらについてはちょっと前に、関数へのポインタに書きました。

ということで、次のプログラムもちゃんと動きます。

コード:

#include <stdio.h>

int main(void)
{
	  (&printf)("&printf\n");
	   (printf)("printf\n");
	  (*printf)("*printf\n");
	 (**printf)("**printf\n");
	(***printf)("***printf\n");
}
さて、void (*p[])(int, int) = { sum1, sum2, sum3 }; ですが、
これは、

コード:

	void (*p[3])(int, int);
	p[0] = sum1;
	p[1] = sum2;
	p[2] = sum3;
と同じで、配列変数 p の初期化が実行時に行われます。
 static void (*p[])(int, int) = { sum1, sum2, sum3 };
と静的に変数を確保することによって、関数が何十個あっても
実行時の初期化は無くなります。

eupher
記事: 8
登録日時: 2ヶ月前

Re: 関数名をchar型変数で代替したい

#9

投稿記事 by eupher » 5日前

コード:

#include <stdio.h>

void sum1( int a, int b ) { (&printf)( "%d\n", a+b ); }
void sum2( int a, int b ) { (*printf)( "%d\n", a+a+b ); }
void sum3( int a, int b ) { (**printf)( "%d\n", a+b+b ); }
void error( void ) { (***printf)( "error\n" ); }

int main( void )
{
	int a = 10, b = 20, i;
	static void (*p[])( int, int ) = { &sum1, &sum2, &sum3 };
	scanf( "%d" ,&i );
	if( i<1 || 3<i ){
		error();
	}else{
		p[i-1]( a, b );
	}
	
	return 0;
}
ありがとうございます。早速試してみました。
&sum1という書き方は見た目が分かりやすくていいですね。いかにもな「これは住所です」感が初心者の私にはピッタリみたいです。

返信

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