Zurückgeben eines Arrays mit C

Lesezeit: 12 Minuten

Benutzeravatar von user1506919
Benutzer1506919

Ich bin relativ neu in C und brauche Hilfe bei Methoden, die mit Arrays umgehen. Da ich aus der Java-Programmierung komme, bin ich es gewohnt zu sagen int [] method()um ein Array zurückzugeben. Ich habe jedoch herausgefunden, dass Sie bei C Zeiger für Arrays verwenden müssen, wenn Sie sie zurückgeben. Als neuer Programmierer verstehe ich das wirklich überhaupt nicht, selbst bei den vielen Foren, die ich durchgesehen habe.

Grundsätzlich versuche ich, eine Methode zu schreiben, die ein char-Array in C zurückgibt. Ich werde die Methode (nennen wir sie returnArray) mit einem Array bereitstellen. Es erstellt ein neues Array aus dem vorherigen Array und gibt einen Zeiger darauf zurück. Ich brauche nur etwas Hilfe, wie ich damit anfangen kann und wie ich den Zeiger lesen kann, sobald er aus dem Array gesendet wird. Jede Hilfe, die dies erklärt, wird geschätzt.

Vorgeschlagenes Codeformat für die Array-Rückgabefunktion

char *returnArray(char array []){
 char returned [10];
 //methods to pull values from array, interpret them, and then create new array
 return &(returned[0]); //is this correct?
} 

Aufrufer der Funktion

int main(){
 int i=0;
 char array []={1,0,0,0,0,1,1};
 char arrayCount=0;
 char* returnedArray = returnArray(&arrayCount); ///is this correct?
 for (i=0; i<10;i++)
  printf(%d, ",", returnedArray[i]);  //is this correctly formatted?
}

Ich habe das noch nicht getestet, da mein C-Compiler im Moment nicht funktioniert, aber ich würde das gerne herausfinden

  • Hat das Rückgabearray eine bekannte Größe, wie in Ihrem Codebeispiel angegeben? Das einzige andere Problem, das ich neben den in den Antworten erwähnten Stack-Problemen sehe, ist, dass Sie nicht wissen, wie groß es ist, wenn Ihr Rückgabe-Array eine unbestimmte Größe hat, da Zeiger/Arrays in C funktionieren.

    – seltsame freie Welt

    25. Juli 2012 um 18:56 Uhr

  • Ja, ich kenne die Größe des eingehenden Arrays jederzeit. Die Größe des Eingabe- und Ausgabearrays ändert sich nicht.

    – Benutzer1506919

    25. Juli 2012 um 19:01 Uhr

  • Die Entwicklung der Sprache C* – bell-labs.com/usr/dmr/www/chist.html

    – x4444

    31. Dezember 2017 um 7:45 Uhr

Benutzeravatar von Ed S
Ed S.

Sie können keine Arrays von Funktionen in C zurückgeben. Sie können (sollten) dies auch nicht tun:

char *returnArray(char array []){
 char returned [10];
 //methods to pull values from array, interpret them, and then create new array
 return &(returned[0]); //is this correct?
} 

returned wird mit automatischer Speicherdauer erstellt und Verweise darauf werden ungültig, sobald es seinen Deklarationsbereich verlässt, dh wenn die Funktion zurückkehrt.

Sie müssen den Speicher innerhalb der Funktion dynamisch zuweisen oder einen vorab zugewiesenen Puffer füllen, der vom Aufrufer bereitgestellt wird.

Option 1:

Weisen Sie den Speicher innerhalb der Funktion dynamisch zu (Aufrufer, der für die Freigabe verantwortlich ist ret)

char *foo(int count) {
    char *ret = malloc(count);
    if(!ret)
        return NULL;

    for(int i = 0; i < count; ++i) 
        ret[i] = i;

    return ret;
}

Nennen Sie es so:

int main() {
    char *p = foo(10);
    if(p) {
        // do stuff with p
        free(p);
    }

    return 0;
}

Option 2:

Füllen Sie einen vorab zugewiesenen Puffer, der vom Aufrufer bereitgestellt wird (Aufrufer weist zu buf und geht an die Funktion über)

void foo(char *buf, int count) {
    for(int i = 0; i < count; ++i)
        buf[i] = i;
}

Und nenne es so:

int main() {
    char arr[10] = {0};
    foo(arr, 10);
    // No need to deallocate because we allocated 
    // arr with automatic storage duration.
    // If we had dynamically allocated it
    // (i.e. malloc or some variant) then we 
    // would need to call free(arr)
}

  • Option 3: (ein statisches Array)

    – muuuuh

    25. Juli 2012 um 18:55 Uhr


  • @moooeeeep: Ja, ich habe das absichtlich weggelassen, um die Dinge einfach zu halten, aber ja, Sie können einen Zeiger auf statische Daten zurückgeben, die innerhalb der Funktion deklariert wurden.

    – Ed S.

    25. Juli 2012 um 18:56 Uhr


  • @ user1506919: Ich würde eigentlich Option 2 bevorzugen, da klar ist, wer Speicher zuweist und freigibt, aber ich füge ein Beispiel für Sie hinzu.

    – Ed S.

    25. Juli 2012 um 19:02 Uhr

  • Option 4: Gibt eine Struktur zurück, die ein Array fester Größe enthält.

    – Todd Lehmann

    21. Mai 2015 um 0:10 Uhr

  • Option 5: Geben Sie eine Union zurück, die ein Array fester Größe enthält.

    – sqr163

    18. Mai 2017 um 21:47 Uhr

Cs Behandlung von Arrays ist sehr anders als Java, und Sie müssen Ihr Denken entsprechend anpassen. Arrays in C sind keine erstklassigen Objekte (das heißt, ein Array-Ausdruck behält in den meisten Kontexten nicht seine “Array-Eigenschaften”). In C ist ein Ausdruck vom Typ „N-element array of T” wird implizit in einen Ausdruck vom Typ “Zeiger auf T“, außer wenn der Array-Ausdruck ein Operand von ist sizeof oder unär & -Operatoren oder wenn der Array-Ausdruck ein Zeichenfolgenliteral ist, das zum Initialisieren eines anderen Arrays in einer Deklaration verwendet wird.

Das bedeutet unter anderem, dass Sie einen Array-Ausdruck nicht an eine Funktion übergeben und empfangen lassen können als Array-Typ; Die Funktion erhält tatsächlich einen Zeigertyp:

void foo(char *a, size_t asize)
{
  // do something with a
}

int bar(void)
{
  char str[6] = "Hello";
  foo(str, sizeof str);
}

Im Aufruf an fooder Ausdruck str wird vom Typ konvertiert char [6] zu char *weshalb der erste Parameter von foo ist deklariert char *a Anstatt von char a[6]. Im sizeof strda der Array-Ausdruck ein Operand von ist sizeof -Operator, wird er nicht in einen Zeigertyp konvertiert, sodass Sie die Anzahl der Bytes im Array (6) erhalten.

Wenn du bist Ja wirklich Interessierte können Dennis Ritchies lesen Die Entwicklung der C-Sprache um zu verstehen, woher diese Behandlung kommt.

Das Ergebnis ist, dass Funktionen keine Array-Typen zurückgeben können, was in Ordnung ist, da Array-Ausdrücke auch nicht das Ziel einer Zuweisung sein können.

Die sicherste Methode besteht darin, dass der Aufrufer das Array definiert und seine Adresse und Größe an die Funktion übergibt, die darauf schreiben soll:

void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize)
{
  ...
  dstArray[i] = some_value_derived_from(srcArray[i]);
  ...
}

int main(void)
{
  char src[] = "This is a test";
  char dst[sizeof src];
  ...
  returnArray(src, sizeof src, dst, sizeof dst);
  ...
}

Eine andere Methode besteht darin, dass die Funktion das Array dynamisch zuweist und den Zeiger und die Größe zurückgibt:

char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize)
{
  char *dstArray = malloc(srcSize);
  if (dstArray)
  {
    *dstSize = srcSize;
    ...
  }
  return dstArray;
}

int main(void)
{
  char src[] = "This is a test";
  char *dst;
  size_t dstSize;

  dst = returnArray(src, sizeof src, &dstSize);
  ...
  free(dst);
  ...
}

In diesem Fall ist der Aufrufer dafür verantwortlich, das Array mit dem freizugeben free Bibliotheksfunktion.

Beachten Sie, dass dst im obigen Code ist ein einfacher Zeiger auf charkein Zeiger auf ein Array von char. Die Zeiger- und Array-Semantik von C ist so, dass Sie den Indexoperator anwenden können [] zu einem Ausdruck des Array-Typs oder Zeigertyp; beide src[i] und dst[i] wird auf die zugreifen i‘te Element des Arrays (obwohl nur src hat Array-Typ).

Du kann Deklarieren Sie einen Zeiger auf ein N-elementiges Array von T und etwas ähnliches tun:

char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE]
{
  char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr);
  if (dstArr)
  {
    ...
    (*dstArr)[i] = ...;
    ...
  }
  return dstArr;
}

int main(void)
{
  char src[] = "This is a test";
  char (*dst)[SOME_SIZE];
  ...
  dst = returnArray(src, sizeof src);
  ...
  printf("%c", (*dst)[j]);
  ...
}

Mehrere Nachteile mit den oben genannten. Zunächst einmal erwarten ältere Versionen von C SOME_SIZE eine Konstante zur Kompilierzeit zu sein, was bedeutet, dass die Funktion immer nur mit einer Array-Größe funktioniert. Zweitens müssen Sie den Zeiger dereferenzieren, bevor Sie den Index anwenden, was den Code unübersichtlich macht. Zeiger auf Arrays funktionieren besser, wenn Sie es mit mehrdimensionalen Arrays zu tun haben.

  • Ihr Link zu “Die Entwicklung von C” ist unterbrochen … sieht so aus, als sollte er uns hierher führen: bell-labs.com/usr/dmr/www/chist.html

    – Dr.Queso

    25. März 2016 um 2:09 Uhr

  • @Kundor: Was bar empfängt ist ein Zeiger, kein Array. Im Kontext einer Funktionsparameterdeklaration T a[N] und T a[] werden beide so behandelt T *a.

    – Johannes Bode

    14. April 2016 um 12:16 Uhr

  • @JohnBode: Du hast recht! Aus irgendeinem Grund dachte ich, Arrays mit fester Größe würden auf dem Stapel übergeben. Ich erinnere mich an eine Situation vor vielen Jahren, als ich herausfand, dass die Größe eines Arrays in der Parametersignatur angegeben werden musste, aber ich muss verwirrt gewesen sein.

    – Nick Matteo

    14. April 2016 um 13:22 Uhr

  • @JohnBode , im zweiten Codeteil erste Zeile:void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize) Der letzte Parameter sollte in sein size_t Typ nicht char.

    – Sefi

    17. November 2018 um 14:36 ​​Uhr

Ich sage nicht, dass dies die beste Lösung oder eine bevorzugte Lösung für das gegebene Problem ist. Es kann jedoch nützlich sein, sich daran zu erinnern, dass Funktionen Strukturen zurückgeben können. Obwohl Funktionen keine Arrays zurückgeben können, können Arrays in Strukturen eingeschlossen werden, und die Funktion kann die Struktur zurückgeben, wodurch sie das Array mit sich trägt. Dies funktioniert für Arrays mit fester Länge.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    typedef
    struct 
    {
        char v[10];
    } CHAR_ARRAY;



    CHAR_ARRAY returnArray(CHAR_ARRAY array_in, int size)
    {
        CHAR_ARRAY returned;

        /*
        . . . methods to pull values from array, interpret them, and then create new array
        */

        for (int i = 0;  i < size; i++ )
            returned.v[i] = array_in.v[i] + 1;

        return returned; // Works!
    } 




    int main(int argc, char * argv[])
    {
        CHAR_ARRAY array = {1,0,0,0,0,1,1};

        char arrayCount = 7;

        CHAR_ARRAY returnedArray = returnArray(array, arrayCount); 

        for (int i = 0; i < arrayCount; i++)
            printf("%d, ", returnedArray.v[i]);  //is this correctly formatted?

        getchar();
        return 0;
    }

Ich bitte um Kommentare zu den Stärken und Schwächen dieser Technik. Ich habe mich nicht darum gekümmert.

  • unklar, warum dies nicht die akzeptierte Antwort ist. Die Frage war nicht, ob es möglich ist, einen Zeiger auf ein Array zurückzugeben.

    Benutzer12411795

    18. Mai 2020 um 16:02 Uhr

  • Ist der zugewiesene Speicher CHAR_ARRAY returned auf dem haufen? Es kann sicherlich nicht auf dem Stapel (im Stapelrahmen von returnArray() Rechts?

    – Minh Tran

    3. Juni 2020 um 2:05 Uhr

  • Ja, das ist die Antwort auf meine Frage: Kann die C-Funktion ein Array zurückgeben? Ja, das kann es, und @Indinfer hat es mit der Verwendung des C-eigenen struc-Datentyps beantwortet. Und natürlich sollte es ein Array mit fester Länge sein. Dies ist C, Sie müssen von vornherein deterministisch sein, es sei denn, Sie haben Zeit, den Schmerz von Zeiger, Adresse, Malloc, Free usw. für nur eine einfache Funktionsrückgabe zu spielen. Prost.

    – KokoEfraim

    7. Mai 2021 um 7:05 Uhr

  • @MinhTran Refer godbolt.org/z/1rYocv3PT – Im Wesentlichen ring_slice wird in eine Funktion umgewandelt, die eine Adresse zum Speichern akzeptiert. Du kannst sehen main reserviert 32 Bytes auf dem Stack für ein Mem2 (sub rsp, 32) und übergibt seine Adresse per rdi zu ring_slice. Ich kenne meine Anrufkonventionen nicht wirklich, aber ich denke rdi ist normalerweise das erste Argument einer Funktion. ring_slice speichert dann seine Ergebnisse dort und gibt dieselbe Adresse zurück (mov rax, rdi).

    – Ekipan

    1. August 2021 um 21:03 Uhr

Benutzeravatar von pyrospade
Pyrospad

Wie wäre es mit dieser herrlich bösen Umsetzung?

array.h

#define IMPORT_ARRAY(TYPE)    \
    \
struct TYPE##Array {    \
    TYPE* contents;    \
    size_t size;    \
};    \
    \
struct TYPE##Array new_##TYPE##Array() {    \
    struct TYPE##Array a;    \
    a.contents = NULL;    \
    a.size = 0;    \
    return a;    \
}    \
    \
void array_add(struct TYPE##Array* o, TYPE value) {    \
    TYPE* a = malloc((o->size + 1) * sizeof(TYPE));    \
    TYPE i;    \
    for(i = 0; i < o->size; ++i) {    \
        a[i] = o->contents[i];    \
    }    \
    ++(o->size);    \
    a[o->size - 1] = value;    \
    free(o->contents);    \
    o->contents = a;    \
}    \
void array_destroy(struct TYPE##Array* o) {    \
    free(o->contents);    \
}    \
TYPE* array_begin(struct TYPE##Array* o) {    \
    return o->contents;    \
}    \
TYPE* array_end(struct TYPE##Array* o) {    \
    return o->contents + o->size;    \
}

Haupt c

#include <stdlib.h>
#include "array.h"

IMPORT_ARRAY(int);

struct intArray return_an_array() {
    struct intArray a;
    a = new_intArray();
    array_add(&a, 1);
    array_add(&a, 2);
    array_add(&a, 3);
    return a;
}

int main() {
    struct intArray a;
    int* it;
    int* begin;
    int* end;
    a = return_an_array();
    begin = array_begin(&a);
    end = array_end(&a);
    for(it = begin; it != end; ++it) {
        printf("%d ", *it);
    }
    array_destroy(&a);
    getchar();
    return 0;
}

Benutzeravatar von mengo
Mengo

Sie können dies mit Heap-Speicher (through malloc() Aufruf) wie andere hier gemeldete Antworten, aber Sie müssen immer den Speicher verwalten (use frei() Funktion jedes Mal, wenn Sie Ihre Funktion aufrufen). Sie können dies auch mit einem statischen Array tun:

char* returnArrayPointer() 
{
static char array[SIZE];

// do something in your array here

return array; 
}

Sie können es dann verwenden, ohne sich Gedanken über die Speicherverwaltung machen zu müssen.

int main() 
{
char* myArray = returnArrayPointer();
/* use your array here */
/* don't worry to free memory here */
}

In diesem Beispiel müssen Sie das Schlüsselwort static in der Array-Definition verwenden, um die Array-Lebensdauer auf anwendungslang festzulegen, damit sie nach der return-Anweisung nicht zerstört wird. Auf diese Weise belegen Sie natürlich für die gesamte Anwendungslebensdauer SIZE-Bytes in Ihrem Speicher, also dimensionieren Sie ihn richtig!

  • Wie gut ist es, Zeiger auf den internen Speicher einer Funktion zu übergeben? Vergessen Sie Multithreading, das ist im seriellen Code schlecht.

    – Benutzer426

    14. November 2021 um 15:44 Uhr

In Ihrem Fall erstellen Sie ein Array auf dem Stapel, und sobald Sie den Funktionsbereich verlassen, wird das Array freigegeben. Erstellen Sie stattdessen ein dynamisch zugewiesenes Array und geben Sie einen Zeiger darauf zurück.

char * returnArray(char *arr, int size) {
    char *new_arr = malloc(sizeof(char) * size);
    for(int i = 0; i < size; ++i) {
        new_arr[i] = arr[i];
    }
    return new_arr;
}

int main() {

    char arr[7]= {1,0,0,0,0,1,1};
    char *new_arr = returnArray(arr, 7);

    // don't forget to free the memory after you're done with the array
    free(new_arr);

}

  • Wie gut ist es, Zeiger auf den internen Speicher einer Funktion zu übergeben? Vergessen Sie Multithreading, das ist im seriellen Code schlecht.

    – Benutzer426

    14. November 2021 um 15:44 Uhr

Benutzeravatar von Michael Dorgan
Michael Dorgan

Ihre Methode gibt eine lokale Stapelvariable zurück, die schlecht fehlschlägt. Um ein Array zurückzugeben, erstellen Sie eines außerhalb der Funktion, übergeben Sie es per Adresse an die Funktion und ändern Sie es dann, oder erstellen Sie ein Array auf dem Heap und geben Sie diese Variable zurück. Beides funktioniert, aber das erste erfordert keine dynamische Speicherzuweisung, damit es richtig funktioniert.

void returnArray(int size, char *retArray)
{
  // work directly with retArray or memcpy into it from elsewhere like
  // memcpy(retArray, localArray, size); 
}

#define ARRAY_SIZE 20

int main(void)
{
  char foo[ARRAY_SIZE];
  returnArray(ARRAY_SIZE, foo);
}

1425610cookie-checkZurückgeben eines Arrays mit C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy