2016-09-18 8 views
2

は次のとおりです。Cでリンクリストの汎用検索機能を記述していますか?次のように私はC. 機能で、リンクされたリストに、一般的な検索機能を記述しようとしています

void* get_when_true(linked_list *l, 
        int (*condition)(const void*)) { 
     node **walk = &l->head; 
     while (*walk != NULL && !condition((*walk)->data)) { 
       walk = &((*walk)->next); 
     } 
     return (*walk)->data; 
} 

基本的に条件は、各要素に対してテストされる関数の関数ポインタでありますこの関数がtrueを返すたびに、その特定のノードが返されるようになります。

リンクされたリストの各ノードにはIDが格納されています。私の問題は、特定のIDを検索する必要がない場合、その特定のIDのみをチェックできる別の検索機能を作成する必要があるということです。私はID 10を探しにwan't場合は基本的に私は、私は他のいくつかのIDをテストしたい場合は

​​

に関数を記述する必要がある30を言って、私は考えてagain..I異なる機能を記述する必要がありますあなたは私のポイントを持っています。

私はこの問題を解決するためにカリングするとしか思えませんが、残念なことにCはカリングを提供せず、私のコードはすべてのプラットフォームでコンパイルする必要があるため、コンパイラ固有の回避策を使用できません。

検索IDにグローバル変数を使用することは1つの解決策ですが、それを回避することはできません。

この問題を解決するにはどうすればよいですか?

+0

しかし、明日、私はいくつかの構造、int型や文字を格納するために私のリンクリストを使用していますが、私はそれらのすべてを比較したい場合は、その後の構造形式が変更されます私のget_when_true関数はこれ以上一般的なままではありません – Nullpointer

答えて

3

コールバックに渡されるget_when_trueに別のパラメータを追加する必要があります。これはちょうど別のvoid *でもかまいませんので、任意のタイプの構造体を指すことができます。このように使用

int isID(const void *data, void *ctx) { 
    int id = (int)ctx; 
    const struct whatever *a = data; 
    return a->ID == id; 
} 

::私もそう、私は「カンニング」とばかりに、単一の整数をキャスト構造を必要としなかった

ここ
get_when_true(list, (void*)10, isID); 

ここ

void* get_when_true(linked_list *l, void *ctx, 
        int (*condition)(const void* data, void *ctx)) { 
     node **walk = &l->head; 
     while (*walk != NULL && !condition((*walk)->data, ctx)) { 
       walk = &((*walk)->next); 
     } 
     return (*walk)->data; 
} 

は、コールバックですa void*

Cはコールバックをネイティブにサポートしていないため、(コールバック)関数ポインタにデータが「添付」されているため、コールバックを受け入れる関数はコールバックに渡されるvoid*を受け取ります。


Cがクロージャをサポートしていませんが、親関数のスコープ内の変数にアクセスすることができ、ネストされた機能を提供GNUの拡張機能があります。したがって、元のコードを使用してください(私の追加パラメータなし):

int get_when_id(linked_list *l, int id) { 
    int condition(const void *data) { 
     const struct whatever *a = data; 
     return a->ID == id; // id is "closed over" from parent 
    } 

    return get_when_true(list, condition); 
} 

実行可能なスタックが必要です。逆アセンブリを見ると、実際にget_when_trueに渡された関数ポインタがconditionのアドレスではないことがわかります。むしろ、実行可能なアドレスサンクがスタックが生成されたときに生成されます。このサンクは、実際のcondition関数へのクローズオーバー変数へのポインタを渡すので、自動的に利用可能になります。

も参照してください:

+0

ええ。これは良いオプションのように見えます!お返事ありがとうございます – Nullpointer

+1

voidポインターとクロージャーの関係について言及してくれてありがとう! – Nullpointer

+1

ようこそ。両者が直接関係していたことに私は気づくのに時間がかかりました。 GCCのネストされた関数を使った私の追加の例を見てください。 –

関連する問題