2016-06-20 9 views
1

ich diesen Fehler:Kann ich ein 2D-Array in C zurückgeben?

incompatible pointer types returning 'int [4][2]' from a function with result type 'int *' 

Wenn ich versuche, diesen Ich versuche

int* getValid(int blank[2]){ 

int row = blank[0]; 
int col = blank[1]; 
static int valid[4][2]; 

valid[0][0] = row; 
valid[0][1] = col-1; 
valid[1][0] = row; 
valid[1][1] = col+1; 
valid[2][0] = row-1; 
valid[2][1] = col; 
valid[3][0] = row+1; 
valid[3][1] = col; 

return valid; 

} 

zu tun, um einen 2D-Array zurückzugeben, die ich innerhalb der Funktion zu generieren.

Ich bin meistens Code in Python so Arrays in C sind mein Hintern treten ..

+1

Return ein Zeiger auf eine 1D-Array – Olaf

Antwort

0

In der Tat, müssen Sie einen n-dimensionale Array Zerfall zu einem Zeiger auf eine n-1 Dimension Array lassen. Und wenn Sie ein statisches Array verwenden, können Sie sicher seine Adresse zurückgeben.

Das einzige wäre heikle Sache sein, eine Funktion zu deklarieren einen Zeiger auf ein Array der Größe 2, aber ein typedef hier kann wirklich helfen Rückkehr:

typedef int Arr2[2]; 

Arr2* getValid(int blank[2]){ 

    int row = blank[0]; 
    int col = blank[1]; 
    static int valid[4][2]; 

    valid[0][0] = row; 
    valid[0][1] = col-1; 
    valid[1][0] = row; 
    valid[1][1] = col+1; 
    valid[2][0] = row-1; 
    valid[2][1] = col; 
    valid[3][0] = row+1; 
    valid[3][1] = col; 

    return valid; 

} 

Und Sie können es sicher nutzen wie folgt aus:

Arr2 * arr = getValid(blank); 

for (i=0; i<4; i++) { 
    for (j=0; j<2; j++) { 
     printf(" %d", arr[i][j]); 
    } 
    putc('\n', stdout); 
} 

Kompiliert und läuft ohne Warnung.

Aber Vorsicht:: es ist nur sicher, weil gültig mit statischem Speicher deklariert ist. Gib niemals einen Zeiger auf ein automatisches Array zurück! (Verwendung dynamische Arrays (zugewiesen mit malloc wenn Sie nicht statische Speicher wollen)

+0

Was meinst du mit automatischem Array? Ist es dynamisch zugeordnet? –

+0

[cpp-Referenz] (http://en.cppreference.com/w/c/language/storage_duration) hat eine eingehende Erklärung. Die automatische Speicherdauer ist gegeben, wenn eine Variable im Block- (oder Funktions) bereich ohne einen 'statischen' Spezifizierer deklariert wird. –

+0

Ich kannte den Begriff nicht, aber ich kannte das Konzept. Es macht jetzt Sinn :) Danke! –

1

Sie können ein Array zu/von einer Funktion in C passieren Aber Sie einen Zeiger passieren kann. Und das kann auf ein Array zeigen.

So müssen Sie eine Funktion wie:

#define COLS 2 

int (*getValid(int blank[2]))[COLS] 
{ 
    static int valid[4][COLS]; 
    ... 
    return valid; 
} 

Mind the Klammer. Ich verwende auch COLS für die Länge der inneren Dimension. Dies vermeidet magische Zahlen, d.h. Wiederholung von Konstanten in Ihrem Code. Verwenden Sie dieses Makro für alle Deklarationen, an denen das Array beteiligt ist, einschließlich der Definition.

Dies ist eine "Funktion ohne Argumente, die einen Zeiger auf ein 1D-Array mit COLSint s zurückgibt". Einzelheiten zu Arrays und Zeigern in C finden Sie in einem guten C-Buch und machen Sie eigene Recherchen. Denken Sie daran, dass, während sie verschiedene Arten sind, sie viel gemeinsam haben in der Praxis (Sprache Mechanismen hinter sind schwieriger zu verstehen).

Einfach gesagt, wenn Sie return valid mit der obigen Deklaration der Funktion verwenden, wird der Name des Arrays in einen Zeiger auf das erste Element konvertiert. Was genau du zurückgeben sollst.

Der Anrufer muss den gleichen Zeigertyp (Zeiger auf 1D-Array) für das Ergebnis verwenden:

int (*arr)[COLS] = getValid(...); 

Die Elemente, wie für den Original-Array zugegriffen werden:

arr[row][col] 

Zusätzliche Informationen: Sie sollten kein statisches Array in der Funktion verwenden, es sei denn, Sie möchten den Status zwischen Aufrufen sichern. Besser zuteilen das Array dynamisch mit malloc:

int (*arr)[COLS]; 
arr = malloc(sizeof(*arr) * 4); // 4 rows of the inner array 

Vergessen Sie nicht, zu überprüfen, ob malloc versagt und geeignete Maßnahmen ergreifen.

Vergessen Sie auch nicht die dynamisch zugewiesenen Array freizugeben, wenn Sie mit ihm fertig sind (aber nicht früher):

free(arr); 
+0

Warum die downvotes Es ist richtig scheint, und gründlicher als die akzeptierte Antwort –

+0

@RyanB:.?. Danke, Mindestens einer hat einen Kommentar hinterlassen. Es gibt immer Leute, die DV eine Antwort haben, die sie einfach nicht verstehen. – Olaf

-1

In C-Arrays sind Bürger zweiter Klasse. Um sie herumzuführen, müsstest du eine Struktur einpacken.

I.e.:

struct t_array42int{int o[4][2];} getValid(int *blank){ 

int row = blank[0]; 
int col = blank[1]; 
static struct t_array42int valid_container; 

int (*valid)[2] = valid_container.o; 

valid[0][0] = row; 
valid[0][1] = col-1; 
valid[1][0] = row; 
valid[1][1] = col+1; 
valid[2][0] = row-1; 
valid[2][1] = col; 
valid[3][0] = row+1; 
valid[3][1] = col; 

return valid_container; 

} 

Dann können Sie Ihre Funktion Rückgabewert speichern wie:

struct t_array42int tmp = getValid(something); 

Of-Kurs gibt es Möglichkeiten, diesen Prozess der „Verpackung“ zu vereinfachen, aber die sind oft nicht Standard oder auch verschleiert.

Der Nachteil der Verwendung von Strukturen besteht darin, dass Strukturtypen nicht nach ihrem Elementlayout, sondern (normalerweise) nach ihren Namen verglichen werden. So etwas wie das:

struct { int o[2]; } a; 

struct { int o[2]; } b; 

a = b; //Error 

ist illegal.

sollten Sie schreiben:

struct t_array2int { int o[2]; } a; 

struct t_array2int b; 

a = b; //OK 

statt.

Sie auch einen Zeiger auf das Array zurückkehren könnte statt, weil es Lagerung ist statisch (dh es wird nicht von der Funktion zu existieren aufhören, nach der Rückkehr):

int (*getValid(int *blank))[2]{ 

int row = blank[0]; 
int col = blank[1]; 
static int valid[4][2]; 


valid[0][0] = row; 
valid[0][1] = col-1; 
valid[1][0] = row; 
valid[1][1] = col+1; 
valid[2][0] = row-1; 
valid[2][1] = col; 
valid[3][0] = row+1; 
valid[3][1] = col; 

return valid; 

} 

Der Funktionsprototyp:

int (*getValid(int *blank))[2] 

bedeutet, dass wenn Sie Ihre Funktion getValid mit einem einzigen Argumente von int * Typ nennen - getValid(something) und dereferenzieren, *getValid(something) Sie einen Array erhalten werden, die nicht wiezugegriffen werden könnenund so haben maximal 2 Elemente des Typs int.

Einfaches Beispiel des obigen Beispiels wird:

int (*tmp)[2] = getValid(something); 

Und ich schlage vor, auch Ihre Array-Parameter mit ihrer realen Art zu schreiben (die nie ein Array sein können - der Compiler nur Sie in dem Denken täuscht, dass Arrays können nach Wert übergeben werden). Beispiel: void f(int a[N]) ist auf void f(int *a) eingestellt. Und int * ist nicht dasselbe wie int [N].

Für einen Neuling empfehle ich Sie daran zu erinnern, dass Arrays nicht die gleichen wie Zeiger sind, aber als solche sehr schlecht behandelt werden. Außerdem empfehle ich Ihnen, niemals Funktionen mit Array-Parametern zu schreiben. Und wenn Sie Arrays auf andere Weise verwenden möchten, dann erhalten Sie den Zeiger auf ihr erstes Element, um stattdessen Strukturen zu verwenden - viel sicherer.

Die Hauptsache mit Array-Parameter ist, dass:

void f(int a[2]) 
{ 
    sizeof(a) == sizeof(int *); //evaluates to 1 

    sizeof(a) != sizeof(int [2]); //evaluates to 1 
} 
+0

Namen, die mit Unterstrich beginnen, sind für die Implementierung reserviert. Und ein Unterstrich ist der schlechteste Name überhaupt. – Olaf

+0

Ich habe gerade angefangen darüber zu lernen Zeiger und Speicherzuweisung Nach meinem Verständnis ist der Name eines Arrays einfach ein Zeiger auf das erste Element des Arrays oder ein Zeiger auf das i-te Element im Array. Ist das korrekt? Ich frage, weil Arrays nicht sind das gleiche wie Zeiger –

Verwandte Themen