c で可変サイズの配列を取る関数を作成しようとしています。
void sort(int s, int e, int arr[*]){
...
}
可変長配列の場合、関数宣言で制限する必要があると書かれています。どういう意味ですか?私はLLVMコンパイラ2.0でxcode 4.0を使用しています。
助けてくれてありがとう。
c で可変サイズの配列を取る関数を作成しようとしています。
void sort(int s, int e, int arr[*]){
...
}
可変長配列の場合、関数宣言で制限する必要があると書かれています。どういう意味ですか?私はLLVMコンパイラ2.0でxcode 4.0を使用しています。
助けてくれてありがとう。
誰も本当の質問に答えていないことがわかったので、ここで私の質問をします。
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
。
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
に関するかなり明確なエラーメッセージがあります。これは、「関数宣言で制限する必要がある」というメッセージよりもはるかに優れています。
エラー:'[*]'は関数プロトタイプスコープ以外では許可されていません
やりたいことは、引数をint *
;にすることです。配列の長さ (おそらく呼び出し元は知っているが、このルーチンは知らない) を別の引数として渡します。このような引数として配列を渡すことができます。
*
可変長配列の配列ブラケット内での使用は、プロトタイプに限定されており、単なるプレースホルダーとして機能します。関数が後で定義されるとき、配列のサイズは、ファイル スコープで、またはパラメーターの 1 つとして使用可能な変数に格納される必要があります。簡単な例を次に示します。
void foo(int, int[*]);
/* asterisk is placeholder */
void foo(int size, int array[size]) {
/* note size of array is specified now */
}