it-swarm.com.de

Unterschied zwischen übergebendem Array, Array fester Größe und Basisadresse des Arrays als Funktionsparameter

Ich bin verwirrt, welche Syntax ich verwenden soll, wenn ich ein Array bekannter oder unbekannter Größe als Funktionsparameter übergeben möchte.

Angenommen, ich habe diese Varianten für den Zweck:

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

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

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

Was sind die Vor- und Nachteile einer jeden davon?

55
mr5

Alle diese Varianten sind gleich. Mit C können Sie nur alternative Schreibweisen verwenden, aber selbst die letzte mit einer Arraygröße explizit kommentierte Variante verwandelt sich in einen normalen Zeiger.

Das heißt, selbst mit der letzten Implementierung können Sie die Funktion mit einem Array von any size aufrufen:

void func3(char str[10]) { }

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

Unnötig zu erwähnen, dass dies nicht verwendet werden sollte: Dies könnte dem Benutzer ein falsches Sicherheitsgefühl vermitteln („Oh, diese Funktion akzeptiert nur ein Array der Länge 10, sodass ich die Länge nicht selbst überprüfen muss ”).

Wie Henrik sagte, ist der richtige Weg in C++std::string, std::string& oder std::string const& (abhängig davon, ob Sie das Objekt ändern müssen und ob Sie kopieren möchten).

71
Konrad Rudolph

Beachten Sie, dass Sie in C++, wenn die Länge des Arrays zur Kompilierungszeit bekannt ist (z. B. wenn Sie ein Zeichenfolgenliteral übergeben haben), die tatsächliche Größe abrufen können:

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

int main()
{
    func("test"); // Works, N is 5
}
20
Morwenn

Verwenden Sie in C++ void func4(const std::string& str).

11
Henrik

Diese sind alle funktional identisch. Wenn Sie ein Array an eine Funktion in C übergeben, wird das Array implizit in einen Zeiger auf das erste Element des Arrays konvertiert. Daher geben diese drei Funktionen dieselbe Ausgabe aus (dh die Größe eines Zeigers auf 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);
}

Diese Konvertierung gilt nur für die erste Dimension eines Arrays. Ein char[42][13] Wird in ein char (*)[13], not a char ** Umgewandelt.

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] ist der Typ von str_array. So schreiben Sie "einen Zeiger auf ein Array von 13 chars". Dies könnte auch als void func4(char str_array[42][13]) { ... } geschrieben worden sein, obwohl die 42 funktional bedeutungslos ist, wie Sie durch Experimentieren sehen können, indem Sie Arrays unterschiedlicher Größe in func4 Übergeben.

In C99 und C11 (aber nicht in C89 oder C++) können Sie einen Zeiger auf ein Array unterschiedlicher Größe an eine Funktion übergeben, indem Sie deren Größe mitgeben und den Größenbezeichner in [square brackets] Einfügen. Beispielsweise:

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]);
}

Dies deklariert einen Zeiger auf ein Array von sizechars. Beachten Sie, dass Sie den Zeiger dereferenzieren müssen, bevor Sie auf das Array zugreifen können. Im obigen Beispiel ergibt sizeof str_array[0] Die Größe des Arrays und nicht die Größe des ersten Elements. Verwenden Sie beispielsweise (*str_array)[11] Oder str_array[0][11], Um auf das 11. Element zuzugreifen.

9
autistic

Zum Nachrüsten, in Punkten beschreiben.

1) Wie alle sagten, ist es dasselbe.

2) Arrays werden in Zeiger zerlegt, wenn sie in den Funktionsargumenten übergeben werden.

3) Grundlegendes Problem könnte sein, die Größe eines Arrays in der Funktion zu finden. Dafür können wir Makros verwenden.

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

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

in dem Makro kann entweder 0 [v] oder v [0] verwendet werden, wobei der erste verwendet wird, um zu vermeiden, dass ein benutzerdefinierter Datentyp an noOfElements übergeben wird.

Hoffe das hilft.

1
Whoami

In einem eindimensionalen Array werden sie alle vom Compiler gleich behandelt. Für ein zweidimensionales oder mehrdimensionales Array (z. B. myArray[10][10]) ist nützlich, da hiermit die Zeilen-/Spaltenlänge eines Arrays bestimmt werden kann.

1
user2301717

In C sind die ersten beiden Definitionen äquivalent. Die dritte Definition ist im Wesentlichen dieselbe, gibt jedoch eine Vorstellung von der Größe des Arrays.

Wenn Sie die Absicht haben, str zu drucken, können Sie jede dieser Funktionen sicher verwenden. Im Wesentlichen wird allen drei Funktionen ein Parameter vom Typ char* Übergeben, genau das, was printf() benötigt um einen String zu drucken. Und damit Sie nicht wissen, wie es auch aussehen mag, werden alle Parameter, die in C übergeben werden, im Modus pass-by-value ausgeführt.

Edit: Scheint, als müsste ich bei meiner Wortwahl sehr streng vorgehen SO von nun an. Nun, im dritten Fall gibt es keine Ahnung über die Größe des Arrays an die Funktion, an die es übergeben wird, da es wie in den ersten beiden Fällen reduziert wird, um char* einzugeben. Ich wollte damit sagen, dass es dem Menschen irgendwie sagt, dass er es liest dass die Größe des Arrays 10 ist. Auch ist es in C. nicht falsch/illegal. Aber für das Programm ist es so gut wie nutzlos. Es gibt überhaupt keine Ahnung, wie groß das Array für die Funktion ist, an die es übergeben wird. Downvoter, vielen Dank für den Hinweis, dass beiläufige Haltung und Nachlässigkeit bei SO nicht toleriert werden.

1