70

既知または未知のサイズの配列を関数パラメーターとして渡したい場合、どの構文を使用すればよいか混乱しています。

目的のためにこれらのバリアントがあるとします。

void func1(char* str) {
    //print str
}

void func2(char str[]) {
    //print str
}

void func3(char str[10]) {
    //print str
}

これらのそれぞれを使用することの長所と短所は何ですか?

4

7 に答える 7

87

これらのバリアントはすべて同じです。C では別のスペルを使用できますが、配列サイズで明示的に注釈が付けられた最後のバリアントでさえ、通常のポインターに減衰します。

つまり、最後の実装でも、任意のサイズの配列で関数を呼び出すことができました。

void func3(char str[10]) { }

func("test"); // Works.
func("let's try something longer"); // Not a single f*ck given.

言うまでもなく、これは使用すべきではありません: ユーザーに誤った安心感を与える可能性があります (「ああ、この関数は長さ 10 の配列しか受け入れないので、自分で長さをチェックする必要はありません」)。

Henrik が言ったように、C++ でstd::stringの正しい方法は、std::string&またはstd::string const&(オブジェクトを変更する必要があるかどうか、およびコピーする必要があるかどうかによって異なります) を使用することです。

于 2013-04-22T10:16:43.023 に答える
24

C++ では、コンパイル時に配列の長さがわかっている場合 (たとえば、文字列リテラルを渡した場合)、実際にそのサイズを取得できることに注意してください。

template<unsigned int N>
void func(const char(&str)[N])
{
    // Whatever...
}

int main()
{
    func("test"); // Works, N is 5
}
于 2013-04-22T13:15:20.907 に答える
12

これらはすべて機能的に同一です。C の関数に配列を渡すと、配列は暗黙的に配列の最初の要素へのポインターに変換されます。したがって、これら 3 つの関数は同じ出力 (つまり、へのポインターのサイズ) を出力しますchar

void func1(char* str) {
    printf("sizeof str: %zu\n", sizeof str);
}

void func2(char str[]) {
    printf("sizeof str: %zu\n", sizeof str);
}

void func3(char str[10]) {
    printf("sizeof str: %zu\n", sizeof str);
}

この変換は、配列の最初の次元にのみ適用されます。Aはではなくchar[42][13]変換されます。char (*)[13]char **

void func4(char (*str_array)[13]) {
    printf("sizeof str_array: %zu\n"
           "sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}

char (*)[13]のタイプですstr_array。「13個の配列へのポインタ」の書き方ですchar。これは と書くこともできvoid func4(char str_array[42][13]) { ... }ますが、さまざまなサイズの配列を に渡して実験してみるとわかるように、42 は機能的に意味がありませんfunc4

C99 および C11 (C89 や C++ は除く) では、さまざまなサイズの配列へのポインターを関数に渡すことができます。そのためには、サイズを一緒に渡し、サイズ識別子を に含め[square brackets]ます。例えば:

void func5(size_t size, char (*str_array)[size]) {
    printf("sizeof str_array: %zu\n"
           "sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}

これは、サイズ chars の配列へのポインターを宣言します。配列にアクセスする前に、ポインターを逆参照する必要があることに注意してください。上記の例sizeof str_array[0]では、最初の要素のサイズではなく、配列のサイズに評価されます。例として、11 番目の要素にアクセスするには、(*str_array)[11]またはを使用しますstr_array[0][11]

于 2013-04-22T10:50:56.600 に答える
12

C++ では、 を使用しますvoid func4(const std::string& str)

于 2013-04-22T10:13:49.817 に答える
2

C では、最初の 2 つの定義は同等です。3 番目の定義は本質的に同じですが、配列のサイズについてのアイデアを提供します。

印刷strが意図されている場合は、それらのいずれも安全に使用できます。基本的に、3 つの関数すべてに type のパラメーターが渡され、文字列を印刷するために必要なchar*ものだけが渡されます。 printf()C で渡されるすべてのパラメーターはpass-by-valueモードで行われます。

編集:今後、SOに関する言葉の選択には非常に厳密でなければならないようです.まあ、3番目のケースでは、最終的には縮小されるため、配列のサイズが渡される関数にわかりません最初の 2 つのケースと同じように入力char*する必要があります。配列のサイズが 10 であることを人間が読んでいることを伝えるという意味です。役に立たない.渡される関数の配列サイズについてはまったくわかりません.Mr.Downvoter、SOではカジュアルな態度と過失が許容されないことを指摘してくれてありがとう.

于 2013-04-22T10:16:54.360 に答える
1

追加するには、ポイントで説明します。

1) 皆さんの言うとおりです。

2) 配列は、関数の引数で渡されるときにポインターに分解されます。

3) 基本的な問題は、関数内の配列のサイズを見つけることです。そのために、マクロのようなものを使用できます。

   #define noOfElements(v) sizeof(v)/sizeof(0[v])

   int arr[100]
   myfunction ( arr, noOfElements(arr))

0[v] または v[0] のいずれかをマクロで使用できます。最初のものは、ユーザー定義のデータ型が noOfElements に渡されるのを避けるために使用されます。

お役に立てれば。

于 2013-04-22T11:01:43.713 に答える