Wie kann ich eine Funktion erstellen, die ein Array zurückgibt? Ich habe das 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 hingewiesen werden sollte.
Zunächst einmal können Sie kein Array-Objekt zuweisen, wie Sie es hier tun:
char A[WIDTH][HEIGHT];
A=rand_grid(WIDTH,HEIGHT);
Objekte vom Typ Array sind nicht änderbar.
Zweitens können Funktionen in C keine Array-Typen zurückgeben. Sie können zurückkehren Zeiger zu Arrays, obwohl:
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 etwas verwirrend; es liest sich wie
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 konstanter integraler Ausdruck zur Kompilierzeit 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 von Ihnen geposteten Snippet möchten Sie ein Array nehmen, das Sie bereits zugewiesen haben, und seinen Inhalt initialisieren. Denken Sie daran, dass in den meisten Kontexten ein Ausdruck eines Array-Typs implizit in einen Zeiger auf den Basistyp konvertiert wird. IOW, wenn Sie ein N-Element-Array von T an eine Funktion übergeben, erhält die Funktion tatsächlich einen Zeiger auf T:
void foo (T *p) {...}
...
T arr[N];
foo(arr);
Für 2-D-Arrays ist es etwas hässlicher:
void foo (T (*p)[M]) {...}
...
T arr[N][M];
foo(arr);
Dies hängt auch davon ab, dass M zur Kompilierzeit bekannt ist, was die Nützlichkeit der Funktion einschränkt. Was Sie möchten, ist eine Funktion, die mit einem 2-D-Array beliebiger Größe umgehen kann. Der beste Weg, den ich kenne, um dies zu erreichen, besteht darin, anstatt einen Zeiger auf das Array zu übergeben, die Adresse des ersten Elements im Array zu übergeben[1]und übergeben Sie die Anzahl der Zeilen und Spalten als separate Parameter:
void foo(T *base, size_t rows, size_t cols) {...}
...
T arr[N][M];
foo (&arr[0][0], N, M);
Ihre rand_grid-Funktion würde also 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);
...
}
- Obwohl die Ausdrücke
&A[0][0]
und A
denselben Wert (die Basisadresse von A) liefern, sind die Typen der beiden Ausdrücke unterschiedlich. Der erste Ausdruck ergibt einen einfachen Zeiger auf char (char *
), während die zweite zu einem Zeiger auf ein 2-D-Array von char (char (*)[HEIGHT]
).
Du kannst nicht. Sie können entweder den Zeiger auf das Array als Parameter übergeben und ihn von der Funktion ändern lassen, oder die Funktion selbst kann Daten zuweisen und den Zeiger 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);
}
Bearbeiten: Wie Café darauf hinwies, kann man das eigentlich zurückgeben struct
mit einem Array darin, aber natürlich würde das kein C-Programmierer mit klarem Verstand tun.
Sie können niemals einen Stapel zurückgeben (“auto
“) Variable von etwas anderem als einem primitiven (Wert-)Typ, und struct
s von solchen. Bei anderen Typen müssen Sie den Speicher mithilfe von aus dem Heap zuweisen malloc()
oder packen Sie das Array (mit fester Größe) in a struct
.
Wenn Sie ein Array mit fester Größe verwenden, können Sie es als modellieren struct
und verwenden Sie struct-return:
#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 Zeiger zu verwenden:
void board_init(Board *b);
Da der erstere Fall von struct-return (vom Compiler) in den letzteren umgeschrieben werden kann. Das nennt man Renditeoptimierung.
Wenn Sie das wirklich wollen, können Sie versuchen, das Array A statisch zu machen, auf diese Weise wird der Speicher für A nicht durch den Funktionsumfang bestimmt und Sie können das Array tatsächlich zurückgeben (in Form eines Zeigers natürlich).
Dies ist jedoch kein guter Weg, um das zu erreichen, was Sie erreichen möchten. Stattdessen übergeben Sie das Array an die Funktion rand_grid
. Dafür ist die Pass-by-Adresse gedacht.
Alle Methoden, die mir bekannt sind, um ein Array von einer Funktion zurückzugeben, haben Schwächen und Stärken.
Das Einschließen in eine Struktur vermeidet den Aufwand für das Zuweisen und Freigeben von Speicher und vermeidet das Erinnern an die Freigabe. Sie haben diese Probleme bei jeder Lösung, die malloc, calloc und realloc verwendet. Andererseits erfordert das Umschließen einer Struktur die Kenntnis der maximal möglichen Größe des Arrays und verschwendet bei großen Arrays deutlich Speicher und Ausführungszeit (z. B. das Laden einer Datei in den Speicher und das Weitergeben des Dateiinhalts von Funktion zu Funktion). durch Kopieren).
Rufen Sie srand() nicht mehr als einmal in Ihrem Programm auf: Das verlangsamt Ihr Programm unnötig und vor allem verringert es die Zufälligkeit der rand()-Funktion.
– pmg
21. September 2009 um 8:57 Uhr