Rückgabe eines zweidimensionalen Arrays in C?

7

Ich habe vor kurzem begonnen, C nur zum Spaß zu programmieren. Ich bin ein sehr fähiger Programmierer in C# .NET und Java im Desktop-Bereich, aber das stellt sich heraus, dass es eine zu große Herausforderung für mich ist.

Ich versuche, etwas so "einfach" wie ein zweidimensionales Array aus einer Funktion zu tun. Ich habe versucht, dafür im Internet zu recherchieren, aber es war schwer für mich, etwas zu finden, das funktioniert hat.

Hier ist was ich bisher habe. Es gibt das Array nicht ganz zurück, es füllt nur einen. Aber selbst das wird nicht kompiliert (ich bin sicher, dass die Gründe für Sie offensichtlich sein müssen, wenn Sie ein erfahrener C Programmierer sind).

%Vor%

Und Verwendung:

%Vor%

Was mache ich falsch? Es sollte erwähnt werden, dass n eine Konstante ist, die den Wert 3 hat.

Bearbeiten : Hier ist ein Compilerfehler beim Versuch, die Konstante zu definieren: Ссылка

    
Mathias Lykkegaard Lorenzen 27.01.2014, 21:08
quelle

7 Antworten

5

C behandelt Arrays nicht wie die meisten anderen Sprachen; Sie müssen die folgenden Konzepte verstehen, wenn Sie mit Arrays in C arbeiten möchten.

Außer wenn es der Operand des Operators sizeof oder unary & ist oder ein String-Literal verwendet wird, um ein anderes Array in einer Deklaration zu initialisieren, wird ein Ausdruck vom Typ "N- Elementarray von T "wird in einen Ausdruck vom Typ" pointer to T "konvertiert (" decay "), und der Wert des Ausdrucks wird die Adresse des ersten Elements des Arrays sein. Dieses Ergebnis ist kein Lvalue; Es kann nicht das Ziel einer Zuweisung sein, noch kann es ein Operand für die Operatoren ++ oder -- sein.

Aus diesem Grund können Sie keine Funktion zum Zurückgeben eines Array-Typs definieren. Der Array-Ausdruck wird als Teil der return -Anweisung in einen Zeigertyp konvertiert, und außerdem kann das Ergebnis sowieso keinem anderen Array-Ausdruck zugewiesen werden.

Ob Sie es glauben oder nicht, es gibt einen soliden technischen Grund dafür; Als er C anfänglich entwickelte, lieh sich Dennis Ritchie viele Konzepte aus der B-Programmiersprache. B war eine "typlose" Sprache; Alles wurde als vorzeichenloses Wort oder "Zelle" gespeichert. Gedächtnis wurde als eine lineare Anordnung von "Zellen" gesehen. Wenn Sie ein Array als

deklariert haben %Vor%

B würde N "Zellen" für den Array-Inhalt beiseite legen, zusammen mit einer zusätzlichen Zelle, die an arr gebunden ist, um den Offset an das erste Element zu speichern (im Grunde ein Zeiger, aber ohne Typ-Semantik). Array-Zugriffe wurden definiert als *(arr+i) ; Sie haben i -Zellen von der in a gespeicherten Adresse versetzt und das Ergebnis dereferenziert. Dies funktionierte großartig für C, bis Ritchie damit begann, der Sprache Strukturtypen hinzuzufügen. Er wollte, dass der Inhalt der Struktur nicht nur die Daten in abstrakten Begriffen beschreibt, sondern dass sie die Bits physisch darstellen. Das Beispiel, das er benutzte, war so etwas wie

%Vor%

Er wollte 2 Bytes für den Knoten reservieren, unmittelbar gefolgt von 14 Bytes für das name-Element. Und er wollte, dass ein Array solcher Strukturen so angelegt wurde, dass Sie 2 Bytes hatten, gefolgt von 14 Bytes gefolgt von 2 Bytes, gefolgt von 14 Bytes usw. Er konnte keinen guten Weg finden, mit dem Array-Zeiger umzugehen er hat es ganz losgeworden. Anstatt den Speicher für den Zeiger beiseite zu legen, berechnet C ihn einfach aus dem Array-Ausdruck selbst. Aus diesem Grund können Sie einem Array-Ausdruck nichts zuweisen. Es gibt nichts, was den Wert auf zuweist.

Also, wie gibst du ein 2D-Array von einer Funktion zurück?

Sie nicht. Sie können einen -Zeiger an ein 2D-Array zurückgeben, beispielsweise:

%Vor%

Der Nachteil dieses Ansatzes ist, dass N zur Kompilierzeit bekannt sein muss.

Wenn Sie einen C99-Compiler oder einen C2011-Compiler verwenden, der Arrays mit variabler Länge unterstützt, können Sie Folgendes tun:

%Vor%

Wenn keine Arrays variabler Länge verfügbar sind, muss mindestens die Spaltendimension eine Kompilierzeitkonstante sein:

%Vor%

Sie können Speicher stückweise in etwas zuweisen, das wie ein 2D-Array funktioniert, aber die Zeilen müssen nicht unbedingt zusammenhängend sein:

%Vor%

p ist nicht ein Array; Es zeigt auf eine Reihe von Zeigern auf int . Für alle praktischen Zwecke können Sie dies verwenden, als wäre es ein 2D-Array:

%Vor%

Beachten Sie, dass C keine Speicherbereinigung hat; Sie sind dafür verantwortlich, Ihre eigenen Verwirrungen zu beseitigen. In den ersten drei Fällen ist es einfach:

%Vor%

Im letzten Fall müssen Sie, da Sie eine Zuweisung in zwei Schritten vorgenommen haben, eine Freigabe in zwei Schritten durchführen:

%Vor%     
John Bode 27.01.2014, 23:09
quelle
4

Ihre Funktion gibt void zurück, so dass die Zeile return x; überflüssig ist. Abgesehen davon sieht dein Code gut aus. Das heißt, vorausgesetzt, Sie haben #define n 3 irgendwo und nicht so etwas wie const int n = 3; .

    
Carl Norum 27.01.2014 21:11
quelle
4

Sie können kein Array in C, multidimensional oder anders, zurückgeben.

Der Hauptgrund dafür ist, dass die Sprache sagt, dass Sie es nicht können. Ein anderer Grund wäre, dass im Allgemeinen lokale Arrays auf dem Stack zugewiesen und folglich freigegeben werden, wenn die Funktion zurückkehrt, so dass es nicht sinnvoll wäre, sie zurückzugeben.

Das Übergeben eines Zeigers an das Array und das Modifizieren ist in der Regel der richtige Weg.

    
Samuel Edwin Ward 27.01.2014 21:22
quelle
3

Um ein neu erstelltes Array von zur Kompilierungszeit bekannten Dimensionen zurückzugeben (ein Zeiger darauf), können Sie Folgendes tun:

%Vor%

Wenn die Größe zur Kompilierzeit nicht bekannt ist, können Sie nicht einmal einen Zeiger auf ein Array zurückgeben. C unterstützt Arrays variabler Länge, aber nicht die Rückgabetypen von Funktionen. Sie könnten stattdessen einen Zeiger auf ein Array variabler Länge durch einen Parameter zurückgeben. Das erfordert die Verwendung eines Parameters, der ein Zeiger auf einen Zeiger auf ein Array variabler Länge ist, so dass es etwas unordentlich wird.

Auch die bevorzugten Optionen zwischen der dynamischen Zuweisung eines Arrays im Aufrufer, der automatischen Zuweisung eines Arrays im Aufrufer, der dynamischen Zuweisung eines Arrays in der aufgerufenen Funktion und der Verwendung von Arrays variabler Länge oder Arrays fester Länge oder sogar eindimensionaler Arrays Bei der manuellen Indexierung hängt der Kontext davon ab, wie groß das Array sein soll, wie lange es leben wird und für welche Operationen Sie es verwenden möchten. Daher müssten Sie zusätzliche Anleitungen bereitstellen, bevor eine spezifische Empfehlung ausgesprochen werden kann.

    
Eric Postpischil 27.01.2014 21:28
quelle
2

In C gibt es nur pass / return by value (kein Durchlauf durch Referenz). Daher besteht die einzige Möglichkeit, das Array (nach Wert) zu übergeben, darin, seine Adresse an die Funktion zu übergeben, so dass sie sie über einen Zeiger manipulieren kann.

Es ist jedoch nicht möglich, die Adresse eines Arrays als Wert zurückzugeben, da die Funktion nach Ablauf der Zeit, in der die Steuerung den Aufrufer erreicht, den Gültigkeitsbereich verlässt und auch die automatischen Variablen darunter fallen. Also, wenn Sie wirklich müssen, können Sie das Array dynamisch zuweisen, auffüllen und zurückgeben, aber die bevorzugte Methode besteht darin, das Array zu übergeben und es dem Administrator überlassen, das Array beim Aufrufer zu verwalten.

Was den Fehler betrifft, ist die einzige Warnung, die ich dafür in GCC bekomme, warning: 'return' with a value, in function returning void , was einfach bedeutet, dass Sie nichts von einer void Funktion zurückgeben sollten.

void new_array (int x[n][n]); Was Sie hier wirklich machen, ist ein Zeiger auf ein Array von n ganzen Zahlen; der verfallene Typ ist int (*x)[n] . Dies geschieht, weil Arrays in Zeiger zerfallen allgemein. Wenn Sie n zur Kompilierzeit kennen, ist der beste Weg, um zu übergeben:

%Vor%

Und nenn es als

%Vor%     
legends2k 27.01.2014 21:26
quelle
2

Sie können willkürliche Dimensions-Arrays wie jede andere Variable übergeben, wenn Sie sie in eine Struktur einschließen:

%Vor%     
Christopher Key 27.01.2014 22:25
quelle
1

Wahrscheinlich deklarieren Sie n als eine konstante Ganzzahl:

%Vor%

Stattdessen sollten Sie n als Präprozessordefinition definieren:

%Vor%     
barak manos 27.01.2014 21:12
quelle

Tags und Links