it-swarm.com.de

Rückgabe eines Arrays mit C

Ich bin relativ neu in C und brauche Hilfe bei Methoden, die mit Arrays umgehen. Aus der Java Programmierung kommend, bin ich es gewohnt, int [] method() zu sagen, um ein Array zurückzugeben Arrays, wenn Sie sie zurückgeben. Als neuer Programmierer verstehe ich das überhaupt nicht, auch 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 versehen. Es wird ein neues Array aus dem vorherigen Array erstellt und ein Zeiger darauf zurückgegeben. Ich brauche nur einige Hilfe, um dies zu starten und den Zeiger zu lesen, sobald er aus dem Array gesendet wurde. Jede Hilfe, die dies erklärt, wird gebeten.

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 dies noch nicht getestet, da mein C-Compiler im Moment nicht funktioniert, aber ich möchte dies herausfinden

129
user1506919

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 der deklarierte Gültigkeitsbereich verlassen wird, d. h. wenn die Funktion zurückkehrt.

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

Option 1:

den Speicher innerhalb der Funktion dynamisch zuweisen (Aufrufer, der für die Freigabe von ret verantwortlich ist)

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

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

    return ret;
}

Nenne es so:

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

    return 0;
}

Option 2:

füllen Sie einen vom Aufrufer bereitgestellten vorab zugewiesenen Puffer (der Aufrufer weist buf zu und übergibt ihn an die Funktion).

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)
}
193
Ed S.

Cs Behandlung von Arrays unterscheidet sich sehr von der von Java, und Sie müssen Ihr Denken entsprechend anpassen. Arrays in C sind keine erstklassigen Objekte (dh ein Array-Ausdruck behält in den meisten Kontexten nicht seine "Array-Ness" bei). In C wird ein Ausdruck vom Typ "N-Element-Array von T" implizit in einen Ausdruck vom Typ "Zeiger auf T" konvertiert ("Zerfall"), außer wenn der Array-Ausdruck ist ein Operand der Operatoren sizeof oder unary &, oder wenn der Array-Ausdruck ein String-Literal ist, das zum Initialisieren eines anderen Arrays in einer Deklaration verwendet wird.

Dies bedeutet unter anderem, dass Sie einen Array-Ausdruck nicht an eine Funktion übergeben und ihn als Array-Typ empfangen lassen können ; 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);
}

Beim Aufruf von foo wird der Ausdruck str vom Typ char [6] In char * Konvertiert, weshalb der erste Parameter von foo wird als char *a anstelle von char a[6] deklariert. Da der Array-Ausdruck in sizeof str Ein Operand des Operators sizeof ist, wird er nicht in einen Zeigertyp konvertiert, sodass Sie die Anzahl der Bytes im Array (6) erhalten.

Wenn Sie wirklich interessiert sind, können Sie Dennis Ritchies Die Entwicklung der C-Sprache lesen, 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 weitergibt, 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, die Zuordnung des Arrays mit der Bibliotheksfunktion free aufzuheben.

Beachten Sie, dass dst im obigen Code ein einfacher Zeiger auf char ist, kein Zeiger auf ein Array von char. Die Zeiger- und Array-Semantik von C ist so, dass Sie den tiefgestellten Operator [] Entweder auf einen Ausdruck vom Typ Array oder Zeiger anwenden können. Sowohl src[i] als auch dst[i] greifen auf das i'te Element des Arrays zu (obwohl nur src den Array-Typ hat).

Sie können einen Zeiger auf ein N-Element-Array von T deklarieren 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]);
  ...
}

Einige Nachteile mit den oben genannten. Zuallererst erwarten ältere Versionen von C, dass SOME_SIZE Eine Konstante zur Kompilierungszeit ist, was bedeutet, dass die Funktion immer nur mit einer Arraygröße funktioniert. Zweitens müssen Sie den Zeiger dereferenzieren, bevor Sie den Index anwenden, der den Code unübersichtlich macht. Zeiger auf Arrays funktionieren besser, wenn Sie mit mehrdimensionalen Arrays arbeiten.

24
John Bode

Wie wäre es mit dieser köstlich bösen Implementierung?

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;
}
8
pyrospade

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 das Array mitgeführt wird. 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.

6
Indinfer

In Ihrem Fall erstellen Sie ein Array auf dem Stapel, und sobald Sie den Funktionsumfang verlassen, wird die Zuordnung des Arrays aufgehoben. 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);

}
6
Man of One Way

Sie können den Heap-Speicher verwenden (durch malloc () Aufruf), wie andere hier gemeldete Antworten, aber Sie müssen den Speicher immer verwalten (verwenden Sie free () Funktion bei jedem Aufruf Ihre Funktion). 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 um die Speicherverwaltung kümmern 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 Lebensdauer des Arrays anwendungslang festzulegen, damit es nach der return-Anweisung nicht zerstört wird. Auf diese Weise belegen Sie natürlich SIZE-Bytes in Ihrem Speicher für die gesamte Anwendungslebensdauer, also passen Sie die Größe an!

4
mengo

Ihre Methode gibt eine lokale Stapelvariable zurück, bei der ein Fehler auftritt. Um ein Array zurückzugeben, erstellen Sie ein Array außerhalb der Funktion, übergeben Sie es als 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 wird funktionieren, aber das erste erfordert keine dynamische Speicherzuordnung, 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);
}
2
Michael Dorgan

Sie können Code wie folgt verwenden:

char *MyFunction(some arguments...)
{
    char *pointer = malloc(size for the new array);
    if (!pointer)
        An error occurred, abort or do something about the error.
    return pointer; // Return address of memory to the caller.
}

Wenn Sie dies tun, sollte der Speicher später freigegeben werden, indem die Adresse an free übergeben wird.

Es gibt noch andere Möglichkeiten. Eine Routine kann einen Zeiger auf ein Array (oder einen Teil eines Arrays) zurückgeben, der Teil einer vorhandenen Struktur ist. Der Aufrufer übergibt möglicherweise ein Array, und die Routine schreibt lediglich in das Array, anstatt Speicherplatz für ein neues Array zuzuweisen.

0