9

c で可変サイズの配列を取る関数を作成しようとしています。

void sort(int s, int e, int arr[*]){
    ...
}

可変長配列の場合、関数宣言で制限する必要があると書かれています。どういう意味ですか?私はLLVMコンパイラ2.0でxcode 4.0を使用しています。

助けてくれてありがとう。

4

4 に答える 4

28

誰も本当の質問に答えていないことがわかったので、ここで私の質問をします。

C99 では、C の以前のバージョンのようにコンパイル時だけでなく、実行時に評価される長さで宣言される可変長配列 (VLA) があります。しかし、配列を関数に渡すのは少し注意が必要です。

1 次元配列は常にポインターとして渡されるだけなので、

void sort(size_t n, int arr[n]) {

}

と同等です

void sort(size_t n, int *arr){

}

高次元は関数に十分に渡されます

void toto(size_t n, size_t m, int arr[n][m]){

}

と同等です

void toto(size_t n, size_t m, int (*arr)[m]){

}

そのような関数の内部でそのような定義を使用すると、式として要素にアクセスできarr[i][j]、コンパイラは正しい要素を計算する方法を認識します。

関数のインターフェイスを前方宣言する場所であるプロトタイプにのみ役立つ、発見した構文が登場します

void toto(size_t, size_t, int arr[*][*]);

したがって、ここで配列の次元*をプレースホルダーとして置き換えることができます。しかし、これはディメンションの名前が手元にない場合にのみ役立ちます。また、定義とまったく同じバージョンを使用する方がはるかに明確です。

void toto(size_t n, size_t m, int arr[n][m]);

一般に、それを一貫して使用するためには、パラメーター リストの最初にディメンションを指定することが重要です。そうしないと、コンパイラが の宣言を解析するときにそれらが認識されませんarr

于 2011-08-29T06:11:57.423 に答える
2

C99可変長配列を使用していない場合(使用しているように見えるので、以下を参照)、通常の解決策は、要素へのアクセスに使用するインデックスとともに、最初の要素へのポインターを渡すことです。

これは、で実行しようとしているのと同様に、配列の範囲を出力するコードですsort

#include <stdio.h>

static void fn (int *arr, size_t start, size_t end) {
    size_t idx;
    for (idx = start; idx <= end; idx++) {
        printf ("%d ", arr[idx]);
    }
    putchar ('\n');
}

int main (void) {
    int my_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
    fn (my_array, 4, 6);
    return 0;
}

これにより、要素4から6まで(ゼロベース)が出力され、次のようになります。

5 4 3

注意すべき点がいくつかあります。

  • my_arrayその関数呼び出しで使用fnすると、配列が最初の要素へのポインタに自動的に「減衰」します。これは、実際には、配列を使用するほとんどの(すべてではない)状況で発生するため、明示的に述べる必要はありません&(my_array[0])

  • Cには、標準ライブラリに組み込まれている、と呼ばれる非常に優れたソート関数がすでにありqsortます。多くの場合、それを使用する必要があります(並べ替えに使用する特定のアルゴリズムがある場合、または宿題や独学の演習を行っている場合を除く)。


実際のVLAを使用している場合、[*]構成は関数プロトタイプでのみ有効であり、関数の実際の定義では有効ではないことに注意してください。

だから、ながら:

void xyzzy(int, int[*]);

が有効である場合、以下は無効です。

void xyzzy(int sz, int plugh[*]) { doSomething(); }

これは、プロトタイプではサイズパラメータは必要ありませんが、定義ではサイズパラメータが非常に必要になるためです。そして、あなたはそれを持っているので、あなたはそれを使うべきです:

void xyzzy(int sz, int plugh[sz]) { doSomething(); }

コンパイラには、実際には、これgccに関するかなり明確なエラーメッセージがあります。これは、「関数宣言で制限する必要がある」というメッセージよりもはるかに優れています。

エラー:'[*]'は関数プロトタイプスコープ以外では許可されていません

于 2011-08-29T02:04:26.037 に答える
2

やりたいことは、引数をint *;にすることです。配列の長さ (おそらく呼び出し元は知っているが、このルーチンは知らない) を別の引数として渡します。このような引数として配列を渡すことができます。

于 2011-08-29T01:55:17.970 に答える
1

*可変長配列の配列ブラケット内での使用は、プロトタイプに限定されており、単なるプレースホルダーとして機能します。関数が後で定義されるとき、配列のサイズは、ファイル スコープで、またはパラメーターの 1 つとして使用可能な変数に格納される必要があります。簡単な例を次に示します。

void foo(int, int[*]);
/* asterisk is placeholder */

void foo(int size, int array[size]) {
/* note size of array is specified now */
}
于 2015-07-22T16:31:34.273 に答える