ページ 1 / 1
関数名をchar型変数で代替したい
Posted: 2018年7月14日(土) 19:16
by eupher
下記のコードは、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"の代わりに、
コード:
char name[10] = "sum";
の"name"を利用できたら便利だなと思ったのですが、可能でしょうか?
Re: 関数名をchar型変数で代替したい
Posted: 2018年7月14日(土) 21:34
by あたっしゅ
>"name"を利用できたら便利だなと思ったのですが、可能でしょうか?
「"name"を利用できたら便利」というのは、具体的には、どのようなことでしょうか ?
strcpy( name, "sum" );
name( a, b ); // 30
strcpy( name, "sub" );
name( a, b ); // -10
みたいなことでしょうか ?
Re: 関数名をchar型変数で代替したい
Posted: 2018年7月14日(土) 22:05
by eupher
コード:
#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型変数で代替したい
Posted: 2018年7月15日(日) 00:08
by かずま
こんなのはいかがですか?
コード:
#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型変数で代替したい
Posted: 2018年7月15日(日) 23:13
by eupher
ご回答ありがとうございます。返信が遅れて失礼しました。
早速試したところ、こちらでもうまく動きました。
文字列を戻り値で渡すというのは思いつかなかったのですごく勉強になりました。本当にありがとうございました。
〇解決したコード
コード:
#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型変数で代替したい
Posted: 2018年7月16日(月) 09:34
by かずま
eupher さんが書きました: ↑7年前
文字列を戻り値で渡すというのは思いつかなかったのですごく勉強になりました。
関数 func は、文字列 name を引数として渡すと、
「関数へのポインタ」を戻り値で返してくる
ということが本当に分かっていますか?
私の提示したコードと何も変わっていませんね。
自分の書き方に変えましょう。
たとえば、
・f というのは分かりにくい。name にしよう。
・! よりも == 0 のほうが違和感がない。
・if文の中の文には { } を付ける主義だ。
など
コード:
void (*func(const char *name))(int, int)
{
if (strcmp(name, "sum1") == 0) {
return sum1;
}
Re: 関数名をchar型変数で代替したい
Posted: 2018年7月17日(火) 04:23
by eupher
フォーラム(掲示板)ルールにソースコードや解決した方法を明記しろ、と書いてあったので記載しました。不快に思われたのでしたら申し訳ないです。
かずま様の回答を見た際に「なんで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型変数で代替したい
Posted: 2018年7月17日(火) 11:21
by かずま
eupher さんが書きました: ↑7年前
コード:
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 };
と静的に変数を確保することによって、関数が何十個あっても
実行時の初期化は無くなります。
Re: 関数名をchar型変数で代替したい
Posted: 2018年7月18日(水) 06:04
by eupher
コード:
#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という書き方は見た目が分かりやすくていいですね。いかにもな「これは住所です」感が初心者の私にはピッタリみたいです。