Deklarieren einer C-function zum Zurückgeben eines Arrays

Wie kann ich eine function erstellen, die ein Array zurückgibt? Ich habe es versucht

const int WIDTH=11; const int HEIGHT=11; int main() { char A[WIDTH][HEIGHT]; A=rand_grid(WIDTH,HEIGHT); return 0; } // Initializes a random board. char[][] rand_grid(int i, int k) { char* A[i][k]; for(j=0;j<i;++j) { for(l=0;l<k;++l) { A[j][l]=ran(10); } } return A; } // Returns a random number from the set {0,...,9}. int ran(int i) { srand((unsigned int) time(0)); return(rand()%10); } 

   

Einige Dinge, auf die ich hinweisen muss.

Zuallererst können Sie ein Array-Objekt nicht so zuweisen, wie Sie es hier tun:

 char A[WIDTH][HEIGHT]; A=rand_grid(WIDTH,HEIGHT); 

Objekte vom Typ Array sind nicht modifizierbar.

Zweitens können functionen in C keine Array-Typen zurückgeben. Sie können jedoch pointers auf Arrays zurückgeben:

 char (*foo(int width))[HEIGHT] { /** * dynamically allocate memory for a widthxHEIGHT array of char */ char (*newArr)[HEIGHT] = malloc(sizeof *newArr * width); /** * initialize array contents here */ return newArr; } 

Die Syntax ist ein wenig verwirrend; es liest sich als

  foo -- foo foo(int width) -- is a function -- taking an int parameter *foo(int width) -- returning a pointer (*foo(int width))[HEIGHT] -- to a HEIGHT-element array char (*foo(int width))[HEIGHT] -- of char 

Für C89 muss HEIGHT im obigen Snippet ein kompilierzeitkonstanter Integralausdruck sein (entweder ein Makro, ein numerisches Literal oder ein arithmetischer Ausdruck, der aus Makros und / oder numerischen Literalen besteht). Ich bin mir nicht sicher, ob das auch für C99 gilt.

Basierend auf dem Snippet, das Sie gepostet haben, möchten Sie ein Array verwenden, das Sie bereits zugewiesen haben, und dessen Inhalt initialisieren. Denken Sie daran, dass in den meisten Kontexten ein Ausdruck eines Array-Typs implizit in einen pointers auf den Basistyp umgewandelt wird. IOW, wenn Sie ein N-Element-Array von T an eine function übergeben, was die function tatsächlich empfängt, ist ein pointers auf T:

 void foo (T *p) {...} ... T arr[N]; foo(arr); 

Für 2-d-Arrays ist es ein bisschen hässlicher:

 void foo (T (*p)[M]) {...} ... T arr[N][M]; foo(arr); 

Dies beruht auch darauf, dass M zur Kompilierungszeit bekannt ist, was die Nützlichkeit der function einschränkt. Was Sie möchten, ist eine function, die mit einem zweidimensionalen Array beliebiger Größe umgehen kann. Der beste Weg, um dies zu erreichen, besteht darin, einen pointers auf das Array zu übergeben, die Adresse des ersten Elements im Array [1] zu übergeben und die Anzahl der Zeilen und Spalten als separate Parameter zu übergeben:

 void foo(T *base, size_t rows, size_t cols) {...} ... T arr[N][M]; foo (&arr[0][0], N, M); 

So würde Ihre rand_grid-function in etwa so aussehen:

 void rand_grid(char *base, size_t rows, size_t cols) { size_t i, j; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { /** * Since base is a simple char *, we must index it * as though it points to a 1-d array. This works if * base points to the first element of a 2-d array, * since multi-dimensional arrays are contiguous. */ base[i*cols+j] = initial_value(); } } } int main(void) { char A[WIDTH][HEIGHT]; rand_grid(&A[0][0], WIDTH, HEIGHT); ... } 

  1. Obwohl die Ausdrücke &A[0][0] und A den gleichen Wert ergeben (die Basisadresse von A), sind die Typen der beiden Ausdrücke unterschiedlich. Der erste Ausdruck wird mit einem einfachen pointers auf char ( char * ) ausgewertet, während der zweite mit einem pointers auf ein 2-d-Array mit char ( char (*)[HEIGHT] ) char (*)[HEIGHT] .

Du kannst nicht. Sie können den pointers entweder als Parameter an ein Array übergeben und die function ändern lassen, oder die function selbst kann Daten zuweisen und den pointers zurückgeben.

in Ihrem Fall

 void rand_grid(char A[WIDTH][HEIGHT]) { A[0][0] = 'A'; // or whatever you intend to do } main() { char A[WIDTH][HEIGHT]; rand_grid(A); } 

Edit : Wie caf darauf hingewiesen hat, kann man die struct tatsächlich mit einem Array darin zurückgeben, aber natürlich würde kein c-Programmierer in ihrer rechten Meinung das tun.

Sie können niemals eine stack-allocated (” auto “) Variable von etwas anderem als einem primitiven (value) Typ und struct s von solchem ​​zurückgeben. Bei anderen Typen müssen Sie den Speicher mithilfe von malloc() aus dem Heapspeicher zuordnen oder das Array (fester Größe) in eine struct .

Wenn Sie ein Array fester Größe verwenden, können Sie es als struct modellieren und struct-return verwenden:

 #define WIDTH 11 #define HEIGHT 11 typedef struct { unsigned char cell[WIDTH * HEIGHT]; } Board; Board board_new(void) { Board b; size_t i; for(i = 0; i < sizeof b.cell / sizeof *b.cell; i++) b.cell[i] = rand() & 255; return b; } 

Dies ist in Ordnung und sollte nicht teurer sein als die Alternative, einen expliziten pointers zu verwenden:

 void board_init(Board *b); 

Da der frühere Fall von struct-return (vom Compiler) zu letzterem umgeschrieben werden kann. Dies wird als Rückgabewertoptimierung bezeichnet .

Wenn Sie das wirklich tun wollen, können Sie versuchen, das Array A statisch zu machen, so wird der Speicher für A nicht durch den functionsumfang bestimmt und Sie können das Array tatsächlich zurückgeben (natürlich in Form eines Pointers).

Aber dies ist kein guter Weg, um das zu erreichen, was Sie erreichen wollen, sondern übergeben Sie das Array an die function rand_grid . Das ist was für eine Adresse ist für bestimmt.

Alle Methoden, von denen ich weiß, dass sie ein Array von einer function zurückgeben, haben Schwächen und Stärken.

Wrapping in einer struc vermeidet den Overhead des Zuweisens und Freigebens von Speicher und vermeidet das Erinnern an das Freigeben. Sie haben diese Probleme bei jeder Lösung, die malloc, calloc und realloc verwendet. Andererseits erfordert das Umhüllen in einer Struktur das Wissen um die maximal mögliche Größe des Arrays und ist mit großer Verschwendung von Speicher und Ausführungszeit für große Arrays verbunden (beispielsweise das Laden einer Datei in den Speicher und das Übergeben der Dateiinhalte von function zu function) durch Kopieren).