3

ここに投稿されたK&Rの第7章の問題の解決策を読んでいます。基本的に、プログラムは、プログラムの名前 ("upper" または "lower") に応じて、標準入力を小文字または大文字に変換します。次のように、変換関数の名前をある種の辞書に保存しているようです。

int (*convcase[2])(int) = {toupper, tolower};

その後、プログラムの名前が au で始まるか l で始まるかに応じて、これらの関数にアクセスします。

if(argc > 0)
  {
    if(toupper((unsigned char)argv[0][0]) == 'U')
    {
      func = 0;
    }
    else
    {
      func = 1;
    }

    while((ch = getchar()) != EOF)
    {
      ch = (*convcase[func])((unsigned char)ch);
      putchar(ch);
    }
  }

そのコード ブロックが何をしているのかは理解できますが、convcase の初期宣言のようなものは見たことがありません。マクロ、列挙型、および配列のある種の奇妙な組み合わせのようです。(1) convcase がポインタである理由を説明できる人はいますか。(2) その名前の後の (int) キャストとは何ですか。(3) toupper と tolower は char * ではないため、その宣言内にあるものは正確には何ですか? (4) いつ/なぜこの種のセットアップを使用するか。複数の関数呼び出しが可能な場合に、スペースを節約するための簡単なマクロのようなツールですか?

4

1 に答える 1

3
  1. convcase2 つの関数ポインタの配列です。ポインターではありません。配列式は、ポインターが予期される場所で使用されると、暗黙的にポインターに変換されます。
  2. それはキャストではありません。および関数が行うintように、関数が引数を受け入れることを指定しています。touppertolower
  3. convcaseは関数ポインタtoupperおよびで初期化されますtolower
  4. この質問は関数ポインタに関するものだと思います。関数ポインタの抽象化が必要な場合は、関数ポインタを使用します。この例は、関数ポインターの不必要な使用であると思います。この場合、ユーザー入力に応じてスペイン語または日本語に変更する機能は、関数ポインターの使用を正当化する可能性が高くなりconvcase[0]ます。convcase[1]さらに、関数ポインターを引数で使用して、追加の抽象化を提供できます。たとえば、qsort関数は、オブジェクトの比較子に関数ポインターを使用するため、任意の型の配列を並べ替えることができます。関数をcomparerintとして使用して入力をソートする例を次に示します。int_compare
#define nelem(array) (sizeof (array) / sizeof *(array))

int int_compare(const void *p1, const void *p2) {
    int x = *(int *)p1, y = *(int *)p2;
    return (x > y) - (y > x);
}

int main(void) {
    int value[16];
    for (size_t x = 0; x < nelem(value); x++) {
        if (scanf("%d", &value[x]) != 1) {
            break;
        }
    }

    qsort(value, sizeof *value, x, int_compare);
    return 0;
}
于 2013-03-10T18:01:18.327 に答える