関数ポインタ配列の関数名を検索する方法とは?

このQ&Aのポイント
  • 関数ポインタ配列に格納されている関数名を文字列で検索して、配列の番号を得る方法について教えてください。
  • 関数を50個まで増やす予定なので、追加や削除に耐えられる保守性の高い方法を探しています。
  • 構造体を使って関数名と検索文字列をワンセットにする方法を考えましたが、適切な方法が思いつきませんでした。
回答を見る
  • ベストアンサー

関数ポインタ配列の関数名を検索

関数ポインタ配列に格納されている関数名を文字列で検索して 配列の番号を得たいのですが、どんな方法が考えられるでしょうか? void (*p_func[])(char*) = {   display,   output, }; int main() {   int fncNo;   fncNo = serchFnc( "display" ); //このserchFnc関数を作りたい   p_func[ fncNo ]( "abcd" );   return 0; } 上の例ですとdisplay関数が実行されます。 関数を50個ぐらいまで増やす予定なので追加や削除に耐えられるような 保守性のある方法が理想です。 構造体を使って関数名と検索文字列をワンセットに出来ないか考えたんですけど 適切な方法が思いつきませんでした。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

#include <stdio.h> typedef void (*funcptr)(char*); struct func_t {   const char* name;   funcptr func; }; #define F(f) { #f, f } void a(char* str) {   printf("a%s\n", str); } void b(char* str) {   printf("b%s\n", str); } void c(char* str) {   printf("c%s\n", str); } funcptr searchFunc(const char* n, struct func_t* table) {   while ( table->name != NULL ) {    if ( strcmp(table->name, n) == 0 ) {     return table->func;    }    ++table;   }   return NULL; } int main() {   funcptr p;   struct func_t ftable[] = {    F(a),    F(b),    F(c),    {NULL, NULL}   };   if ( (p = searchFunc("a",ftable)) != NULL ) (*p)("-found");   if ( (p = searchFunc("b",ftable)) != NULL ) (*p)("-found");   if ( (p = searchFunc("c",ftable)) != NULL ) (*p)("-found");   if ( (p = searchFunc("d",ftable)) != NULL ) (*p)("-found");   return 0; }

herbest
質問者

お礼

う…すごい。 見事過ぎます。なるほどこうするのか。 関数ポインタには慣れていなかったんですが、typedefですか~こんな使い方するんですね。 それにしても非の打ち所がない、完璧です。感動しました。 ありがとうございます、大変参考になりました。

その他の回答 (2)

noname#22058
noname#22058
回答No.3

No.2の者です。 私の回答は外してましたね。 επιστημηさんの回答をご参考になさってください。

noname#22058
noname#22058
回答No.2

サンプルです。 #include <stdio.h> #include <string.h> typedef void (*func)(char *); typedef struct _func_table { func function; char *name; } func_table; void display(char *s) { puts("display関数を実行しています。"); puts(s); } void output(char *s) { puts("output関数を実行しています。"); puts(s); } int main(void) { func_table table[] = { { display, "display" }, { output, "output" }, }; char name[10], str[40]; int n, i; printf("実行したい関数名:"); scanf("%s", name); n = sizeof(table) / sizeof(table[0]); for (i = 0; i < n; i++) { if (strcmp(name, table[i].name) == 0) { sprintf(str, "今、実行した関数は、%s", name); table[i].function(str); break; } } if (i == n) puts("関数が見つかりませんでした。"); return 0; }

関連するQ&A

  • C言語 ポインタ 関数

    キーボードから文字列”abcdefg”を入力し、main関数で配列aryに格納する。 main関数から配列aryの先頭アドレスを副関数に引き渡す。 副関数で配列aryの最後尾の要素の内容を';'に変更する。 main関数で配列aryの内容を表示する。 この問題が解けません... #include <stdio.h> int main (void) { char ary[]="abcdef"; int *p; int i,x; p=&ary[0]; func(&i); for (x=0;x<=7;x++){ printf("%s",ary[x]); void func (int i) if(i==\0) i=';' else i++ } return 0 } とりあえずこんな感じなんですけど、出来ませんでした...

  • C言語で、他の関数で配列を書き換えられないようにしたい

    下のCのプログラムでは、func関数は配列aの先頭要素へのポインタを返します。 main関数の側では配列aの中身を表示します。 しかし、main関数のfor文の中の★の部分をコメントアウトせずに入れると、この配列の中身が書き換わってしまいます。  私はfunc関数以外では、この配列の中身をいじられたくないのです。  なんとかfunc関数を工夫して作成して、func関数以外では、配列の中身が変わらないようにしたいのですが、どうすればよいでしょうか。    とは言ったものの、多分できないだろうなあ、という気がします。  できないならばできないでも仕方ないのですが、確信が持てないのです。 条件があります。 funcでは表示は行なわない。 配列aの中身を表示できるように、funcから呼び出し元へ、aのアドレスまたはaの先頭要素のアドレスがわかるような情報を返す。 #include <stdio.h> char *func(int i) { static char a[]="AAAA"; a[i]='z'; return a; } int main(void) { int i; for(i=0; i<4; i++) { char *p=func(i); /* p[i]='X'; ★配列の中身を書き換えてしまう。 */ puts(p); } return 0; }

  • ポインタ配列

    "one","two","three","four","five","six","seven","eight","nine","ten" のポインタ配列の文字列を、ASCIIコード順に並べ変えようと思ったのですが、 もうどこが間違っているかさえわからないぐらいになってしまいました。 まだまだはじめたばかりなもので、わからないことだらけなんで、 できるだけわかりやすい説明おねがいします。 関数の引数に問題があるのじゃないかと思ったのですが、 何かいいアドバイスありましたら、お願いします。 #include <stdio.h> /* 関数のプロトタイプ宣言 */ int strmp(char *,char *); void cpy(char *,char *); int main (void) { /* ポインタ配列の定義 */ char *x[10]={"oneee","twooo","three","fourr","fivee","sixxx","seven","eight","ninee","tennn"}; /* ポインタのポインタの定義 */ char **pp=x; char k[100]; char *p=k; int i,t,a,b,c,d; a=0; /* ポインタ配列を自作関数を使って、ASCIIコードの大きいほうからに並び替える */ for(i=0;i<9;i++) { for(t=1;t<10;t++) { a=strmp(*(pp+i),*(pp+t)); if(a<0) { cpy(p,*(pp+i) ); cpy(*(pp+i),*(pp+t) ); cpy(*(pp+t),p); } } } for(i=0;i<10;i++) { printf("%s ,",x[i]); } printf("\n"); return 0; } /* 文字の比較をする関数 */ int strmp(char *x,char *y) { int i; for(i=0;*(x+i)==*(y+i);i++) { if( *(x+i)=='\0') { return 0; } } return *(x+i)-*(y+i); } /* 文字をコピーする関数 */ void cpy(char *a,char *b) { int i; for(i=0;*(b+i)!='\0';i++) { *(a+i)=*(b+i); } *(a+i)='\0'; }

  • ポインタ変数とポインタのポインタ

    ポインタ変数の宣言 char *a[]; をしたとき僕の中では a[0],a[1]...という、ある文字列A,B,C...の最初のアドレスを指すポインタが、配列になっているものを宣言していると理解していました。 しかしこの次に、ポインタのポインタが出てきました。僕はこれを、 ある変数を指し示すアドレスのアドレスである、と理解しました。 この2つは1つめはいくつかのアドレスを指し示すもの、2つ目は1つのアドレスを指し示すものであるとして、僕の中で異なったものであると理解していましたが、参考書「C標準コースウェア」によると プログラムにおいて、関数でポインタ配列を受け取るときchar *p[]はchar **pとしてもよい と書かれており、またその実例として、 (9-5) #include <stdio.h> void disp (char *p[],int n){ int i; for (i= 1;i<n;i++){ printf("%s\n",p[i]); } } int main(void){ char *girl[] = {"Arica","Candy","Lisa"}; disp (girl,sizeof(girl)/sizeof(girl[0])); return 0; } というプログラムが書かれていました。 ここで一気に訳が分からなくなりました。 char *girl[] = {"Arica","Candy","Lisa"}; と宣言されているため、 girl[0]はAricaという文字列の最初のアドレスを指すポインタ、 *girl[0]はAricaという文字列を直接指し示していると解釈しています。 girlは{"Arica","Candy","Lisa"}という文字列の配列の最初のアドレスを指し示していると考えました。 sizeof(girl)を使った時に不思議なのですが、 girlはどのように配列の終わりを理解しているのでしょうか? (配列の要素数を渡していない点が不思議です。) また、 disp側が受け取ったのは*girl[]であり、いくつかのポインタの配列ですが、渡したものはgirlという要素数がないポインタ1つだけです。 そして最初の疑問が出てくるわけですが、*p[]を**pと書きかえてみると、 文字列のアドレスを示すgirlという名の1つのポインタを渡すと、pという名のポインタのポインタで受け取るというのも、よくわからなくなっています。 おそらくポインタ配列に対する理解がどこかでずれているようですが、自分でどこがわからないのかわからなくなっています。 どうかご教授ください。

  • 2次元配列とポインタの引数受け渡しについて

    2次元配列を関数に渡すときは、引数に渡す2次元配列と同じサイズを指定、もしくは2次元目のサイズのみ合わせて渡す方法がありますが、両方とも違うサイズで同じ関数を使いたいです。 最初は中身が同じで引数で受け取る2次元配列のサイズだけ、それぞれに合わせた引数を持つ関数を2つ作っていたのですが、なんだか冗長な気がしました。 そこで、2次元配列の先頭ポインタとサイズを受け取るようにすればいいのかと思い、テストとして次のプログラムを作成してみました。 #include <stdio.h> void func(unsigned char *a, int y, int x); int main(void) { unsigned char a[10][10]; func(a, 10, 10); printf("%d\n", a[7][4]); return 0; } void func(unsigned char *a, int y, int x) { int i, j; for (i = 0; i < y; i++) { for (j = 0; j < x; j++) { *(a + i*y + j) = i * j; } } } もちろんこれでも動くのですが、やはりこういう書き方はルールにはないので、コンパイルで警告が出ます。 a.c: In function ‘main’: a.c:10: warning: passing argument 1 of ‘func’ from incompatible pointer type a.c:4: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[10]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • 再帰関数でポインタのインクリメントがうまくいかない 

    再帰関数で標準出力に文字列を表示するプログラムを書きました。 #include <stdio.h> void display(char *p); int main(void) { display("おちょめちょめ"); return 0; } void display(char *p) { if(*p){ printf("%c",*p); dis(p++); } } 実行するとbがいっぱい出てきます。?? 一番最後のコードですが、()の中を p=p+1 p+=1 p+1 などにするとちゃんと おちょめちょめ と表示されます。なぜでしょうか。

  • ポインタ配列の値引き渡しについて

    関数を作る際 func(int p[][]) →コンパイルエラー func(int *p[]) →コンパイルOK になるのは何故ですか? 同じことを言っているように思うのですが?

  • 引数で指定された配列の要素数の取得

    どうもこんにちは。 C言語でプログラムを作成しています。 ある関数に配列を渡すことを考えていますが、渡した配列の要素数を取得する方法は何かありますか? 標準の関数を見ても、配列の先頭アドレスのポインタとともに、配列の要素数を渡しているものばかりで、配列のポインタを渡しているものは見かけません。 要素数があらかじめわかっていれば、それを引数の型に指定できますが、呼び出されるまで不明な場合はうまくいきません。 配列の要素数も引数として一緒に渡す必要がありますか? [作ってみたサンプル] #include <stdio.h> #include <stdlib.h> #include <string.h> // func1 と func2 をまとめられないだろうか。。。 void func1(int (*p)[10]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } void func2(int (*p)[5]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } int main(int argc, char *argv[]) { ________int ary1[10] = { 2, 4, 6, 8, 0, 1, 3, 5, 7, 9 }; ________int ary2[5] = { 3, 6, 9, 12, 15 }; ________func1(&ary1); ________func2(&ary2); ________return 0; }

  • 配列の渡し方と表示の仕方

    初心者です。 以下のメイン関数で実行をしたところ、 定義した文字列の最後の文字しか表示されません。 関数に上手く引数として配列が渡されていないか、 表示のさせ方が悪いと思うのですが、よく分かりません。 int main(void) { char str[CASENUM][10] = {'abcdef','abcde','abcd','abc'}; int startIndex[CASENUM] = {2,1,3,1}; char expected[CASENUM][10] = {'abcdef','abcde','abcd','abc'}; int i,m; char res; for(i = 0; i < CASENUM; i++) { printf("%c",str[m][i]); res = *subString(str[i],startIndex[i]); printf("実行結果:%c , 期待結果:%c\n", res, expected[i][10]); } return 0; } よろしくお願いします。

  • c言語 int型の数字をchar型の配列に

    c言語についてです。 int型の数字をchar型の配列に入れたいです。 関数に対してint型の数字を文字列として渡し、 関数内でchar型の配列に格納したいです。 例として、 a(char a[]){  ~~  ~~ } int main(void){ int x = 5678;  ~~  a(x); } とできるようにしたいです。 しかしこれだと5678という値がそのままchar型の一つの配列に入る?ため正しくないです。 欲しい結果としてはちゃんとa関数内で、 a[1] = '5' a[2] = '6' a[3] = '7' a[4] = '8' となってほしいです。 もともと渡す値が”5678”となっていれば結果は正しく出るのですが、 渡す値がint型と決まっているためどうにかして5678を”5678”とすればいいのではないかと考えています。 つまり5678を単純に文字列に変換すればいいのでしょうか? またプログラム内ではsprintfやatolを使用しないで実現させたいです。 難しいかもしれませんがお願いします。 なんだか説明が下手ですみません。 お願いいたします。