Verwendung von malloc zur Zuordnung mehrdimensionaler Arrays mit unterschiedlichen Zeilenlängen

68

Ich habe folgenden CCode:

das funktioniert gut. Aber wenn ich folgendes habe:

wo jedes Element beine andere Länge hat.

Wie ist es möglich , das gleiche zu tun bwie ich für a; dh der folgende Code würde richtig gelten?

asel
quelle

Antworten:

79

Zuerst müssen Sie ein Array von Zeigern wie char **c = malloc( N * sizeof( char* ))und dann jede Zeile mit einem separaten Aufruf zuweisen malloc, wahrscheinlich in der Schleife:

Wenn Sie die Gesamtzahl der Elemente kennen (z. B. N*M), können Sie dies in einer einzigen Zuordnung tun.

Nikolai Fetissov
quelle
2
Wenn Sie N M Bytes in einer einzigen Operation zuweisen , füllen Sie alle c [i] manuell aus: c [i] = p + M i;
Tadeusz A. Kadłubowski
2
Das hängt vom Typ des c ab - wenn es char ** ist, dann ja, wenn es char * ist, ändert sich die Indizierung: element [i] [j] ~ c [i * M + j].
Nikolai Fetissov
1
@ Nikolai N Fetissov, es gibt viele Mallocs im Code, wie kann das alles befreit werden? indem Sie auch for-Schleifen verwenden?
e19293001
2
@ e19293001 ja, eine freefür jede malloc. Sie müssten die char*Variablen durchlaufen , um sie freizugeben, und dann die freigeben char**.
Erickrf
Ich habe dasselbe in einem Buch gesehen, in dem stand: "... die Erinnerung ist nicht garantiert zusammenhängend."
dud3
49

Die typische Form zum dynamischen Zuweisen eines NxM-Arrays vom Typ T ist

Wenn jedes Element des Arrays eine andere Länge hat, ersetzen Sie M durch die entsprechende Länge für dieses Element. zum Beispiel

John Bode
quelle
Wenn ich die Gesamtzahl der Ints habe, die ich haben werde, aber nicht wie viele davon in jedes Array gehen, wie soll ich vorgehen?
Dietbacon
Sehr klare Antwort, danke! Können Sie auch eine Beschreibung hinzufügen, in welcher Reihenfolge freeder zugewiesene Speicher ordnungsgemäß verwendet werden soll?
Kagaratsch
2
@Kagaratsch: Im Allgemeinen kostenlos in der von Ihnen zugewiesenen umgekehrten Reihenfolge - das heißt, zuerst kostenlos a[i], dann kostenlos a.
John Bode
29

Die äquivalente Speicherzuordnung für char a[10][20]wäre wie folgt.

Ich hoffe das sieht einfach zu verstehen aus.

Ramesh
quelle
10

Der andere Ansatz wäre, einen zusammenhängenden Speicherblock zuzuweisen, der einen Headerblock für Zeiger auf Zeilen sowie einen Bodyblock zum Speichern tatsächlicher Daten in Zeilen umfasst. Markieren Sie dann einfach den Speicher, indem Sie den Zeigern im Header pro Zeile Adressen des Speichers im Body zuweisen. Es würde wie folgt aussehen:

Der Vorteil dieses Ansatzes ist die elegante Speicherfreigabe und die Möglichkeit, mithilfe der Array-ähnlichen Notation auf Elemente des resultierenden 2D-Arrays zuzugreifen.

Dmitry Aleks
quelle
2
Zu beachten: Diese Lösung bietet im Allgemeinen eine bessere Leistung in Bezug auf die Cache-Kohärenz, da die einzelnen Zeilen im Gegensatz zu den anderen Ansätzen, bei denen jeweils eine Zeile zugewiesen wird, garantiert zusammenhängend sind und zu einer Matrix führen können, deren Bestandteile verstreut sind in einem stark fragmentierten Haufen.
Max DeLiso
4
Dies hat leider auch den Nebeneffekt, dass die Ausrichtung für Typen ohne Zeigergröße nicht garantiert wird. Beispiel: Ein System mit 32-Bit-Zeigern und 64-Bit-Doubles mit einer ungeraden Anzahl von Zeilen startet die erste Spalte der Double-Zeile an einer nicht ausgerichteten Grenze für double. Es ist sehr wichtig, dass dies berücksichtigt wird, da dies aufgrund einer falschen Datenausrichtung leicht zu einem Busfehler führen kann. Eine allgemeine Lösung sollte sicherstellen, dass die Datenzeilen an einer 8-Byte-Grenze beginnen, zusätzlichen Zuordnungsraum schaffen und entsprechend angepasst werden, wenn dem primären Zeigersegment Zeilenzeiger zugewiesen werden.
WhozCraig
@DmitryAleks: Wo erklärst du columnSizes[]?
user2284570
3

Wenn jedes Element in b unterschiedliche Längen hat, müssen Sie Folgendes tun:

Sockel
quelle
1
Es wird kein Speicher für ein eindimensionales Array von char * -Zeigern zugewiesen.
Tadeusz A. Kadłubowski
2

Ich denke, ein 2-Schritt-Ansatz ist am besten, weil c 2-D-Arrays gerecht sind und ein Array von Arrays. Der erste Schritt besteht darin, ein einzelnes Array zuzuweisen und es dann zu durchlaufen, um Arrays für jede Spalte zuzuweisen. Dieser Artikel enthält gute Details.

zdav
quelle
1

Dynamische Speicherzuordnung für 2-D-Arrays

Sridhar T.
quelle
0

malloc weist keine bestimmten Grenzen zu, daher muss davon ausgegangen werden, dass es einer Bytegrenze zugeordnet ist.

Der zurückgegebene Zeiger kann dann nicht verwendet werden, wenn er in einen anderen Typ konvertiert wird, da der Zugriff auf diesen Zeiger wahrscheinlich zu einer Verletzung des Speicherzugriffs durch die CPU führt und die Anwendung sofort heruntergefahren wird.

Vendicar Decarian
quelle