与えられた任意の数値配列に対して桁上げを行う関数を作成しようとしています。 問題は、ポインタの性質のために、Cが配列を適切に反復処理するためにデータ型を知る必要があることです。 タイプを知らなくても配列を渡す方法はありますか?たぶんvoid型を使用していますか?Cの関数に任意の配列型を渡す
void ordenation (void *array, ...) {}
与えられた任意の数値配列に対して桁上げを行う関数を作成しようとしています。 問題は、ポインタの性質のために、Cが配列を適切に反復処理するためにデータ型を知る必要があることです。 タイプを知らなくても配列を渡す方法はありますか?たぶんvoid型を使用していますか?Cの関数に任意の配列型を渡す
void ordenation (void *array, ...) {}
ここで私はあなたの質問を理解しています。 Cで複数の数値型(float、intなど)の配列を受け入れることができる関数を作成しようとしています。
これは、関数のオーバーロードと呼ばれます。 _Generic演算子を介してC11で実行することができます。 function overloading in C
別のオプションは、すべて異なるパラメータリストを使用して異なる名前で関数を作成することです。したがって:
void ordenation_i(int *array);
void ordenation_f(float *array);
別の方法では、void *型を使用します。それはあなたがそれにポインタを渡すことができ、それはあなたが探しているものではないかもしれないことを意味するでしょう。 void *を浮動小数点のような別のものへのポインタにキャストする必要があります。その操作が失敗した場合、問題が発生する可能性があります。
void ordenation(void *array){
float* array_casted = (float*) array;
// Do stuff
}
このコードの問題は、配列が浮動小数点配列としてのみ使用できるようになったことです。
最後に、C++コンパイラを使用することもできます。それは任意のCコードをコンパイルし、デフォルトで関数のオーバーロードを取得します。
void ordenation(int array[]){
//do stuff
}
void ordenation(float array[]){
//do stuff
}
あなたは機能void ordenation (void *array)
を作成し、限り関数を呼び出すときにこのordenation ((void*)array)
のように入力配列をキャストとして関数に任意のデータ型の配列を渡すことができます。関数内で配列を使用できるようにするには、対応する配列のデータ型を示すために2番目の入力を追加してください。 (私は、この点はCが関数のオーバーロードを許さないためだと仮定しています)
'int *'への任意のポインタをキャストし、それが動作することを期待することはOKではありません。これは 'void *'のためのものです。 –
十分に公正で、私は私の答えを編集しました。 – Ben
あなたは絶対に安全void *
を使用して、このような関数に任意のオブジェクトへのポインタを渡すことができます。問題は、他の人が指摘しているように、あなたがその関数に入ったらそのオブジェクトで何かをしなければならないということです。タイプを知る必要があるでしょう。配列へのポインタを渡すためには、実際の作業を完了させるために何らかの方法でそれを必要とします。
別の回答として、C11ジェネリックで行うこともできますが、別の方法として、配列へのポインタだけでなく、関数ポインタを使用して実行したいコードへのポインタを渡すこともできます。例えば
は、任意の数値配列の各要素に2を追加する次のコードは、(私はint
、long
とdouble
のためにそれを実装しましたが、それは、残りの標準数値型のために実装する些細なのです)。 add_two()
関数自体は、どんなタイプの配列を受け取っているかわからない。しかし、これを達成するために、あなたも行い機能にそれをポインタを渡す必要がノウハウ:出力と
#include <stdio.h>
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t));
void add_two_int(void * array, size_t idx);
void add_two_long(void * array, size_t idx);
void add_two_double(void * array, size_t idx);
int main(void)
{
int n[] = {1, 2, 3, 4, 5};
add_two(n, 5, add_two_int);
for (size_t i = 0; i < 5; ++i) {
printf("%zu: %d\n", i, n[i]);
}
long l[] = {1L, 2L, 3L, 4L, 5L};
add_two(l, 5, add_two_long);
for (size_t i = 0; i < 5; ++i) {
printf("%zu: %ld\n", i, l[i]);
}
double d[] = {1.0, 2.0, 3.0, 4.0, 5.0};
add_two(d, 5, add_two_double);
for (size_t i = 0; i < 5; ++i) {
printf("%zu: %f\n", i, d[i]);
}
return 0;
}
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t))
{
for (size_t i = 0; i < sz; ++i) {
add_func(array, i);
}
}
void add_two_int(void * array, size_t idx)
{
int * n = array;
n[idx] += 2;
}
void add_two_long(void * array, size_t idx)
{
long * l = array;
l[idx] += 2;
}
void add_two_double(void * array, size_t idx)
{
double * d = array;
d[idx] += 2;
}
:中くらいありませんこの単純な例ではもちろん
[email protected]:~/src/sandbox$ ./genarray
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3.000000
1: 4.000000
2: 5.000000
3: 6.000000
4: 7.000000
[email protected]:~/src/sandbox$
、 add_two()
の機能を書くことに本当に有益な方法は、ちょうどadd_two_int()
と友人を書いてそれらを直接使用するのと比較して。しかし、例えばadd_two()
のようなものをライブラリに入れたいという複雑な例では、add_two()
を変更したり、ライブラリを再構築したり再デプロイしたりせずに、任意のタイプと新しいタイプに対処できる方法です。
また、私は関数add_two()
と命名しましたが、明らかに各要素の順番どおりにそれを実行するだけです。したがって、関数subtract_two_int(void * array, size_t idx)
を書くと、例えばadd_two()
に渡すことができます。実際には、名前にもかかわらず、各要素から2つ減算されます。
関数内でポインタを間接参照する必要があるので、正しい型を渡すのはなぜですか?あなたのコードを表示し、より多くの情報を提供してください。どちらかがXY問題であるか、あなたの意図が明確ではありません。 – Olaf
嫌疑とはなんですか? – EOF
これはポインタには関係しませんが、Cは静的に型付けされているためです。 Cで全ジェネリックコードを書くことは非常に悪い考えです。必要に応じて、Pythonのような動的に型付けされた言語を使用します。 – Olaf