Array of Chars #2

Teil 1

In Teil 1 habe ich das Szenario einer Tabelle mit zwei Spalten und drei Zeilen geschildert, deren Daten dann in einem zweidimensionalen Array gespeichert wurden.
Nun werden aber meistens nicht nur reine Zahlen gespeichert, sondern oft sollen auch Strings, also Zeichenketten, verarbeitet werden.
Ein String ist ja nichts anderes als eine Zeichenkette, welche ein Array aus chars, Zeichen ist.

char a[] = "string";


































a[INDEX] Inhalt
0 s
1 t
2 r
3 i
4 n
5 g
6 NUL

Der NUL-Terminator am Ende kann Probleme bereiten, wenn er vergessen wird. Er ist dazu da, um das Ende der Zeichenkette anzuzeigen, z.B. bei Ausgabe mit printf. Fehlt dieser, hat der String kein Ende mehr - das Programm wird, wenn nicht sofort, dann später, ganz sicher abstürzen.
Darüber hinaus geben manche Funktionen die Zeichenkette mit NUL-Terminator zurück, manche nicht. Einige geben als Länge nur die Länge des Strings ohne NUL-Terminator zurück, andere mit. Deshalb nebenbei immer die Funktionsreferenz offen lassen.

Nehmen wir also auch diesmal an, ich möchte eine Tabelle mit folgenden Werten ausgeben:













Spalte0Spalte1
Spalte0Zeile0Spalte0Zeile0
Spalte0Zeile1Spalte0Zeile2
Spalte0Zeile2Spalte0Zeile2

Das sieht doch jetzt exakt so aus wie letztes Mal, nur mit anderen Werten in den Feldern, oder?
Erstaunlicherweise funktioniert die statische allokation des Arrays auf dem Stack genau gleich:
Quelltext Grundlage für alle weiteren Code-Ausschnitte *klick*.
    
char * auf_dem_stack[2][3] = {
     {"Spalte0Zeile0", "Spalte0Zeile1", "Spalte0Zeile2"}, // Spalte 0
     {"Spalte1Zeile0", "Spalte1Zeile1", "Spalte1Zeile2"} // Spalte 1
    };

Die Ausgabe ist auch identisch, bis auf die anderen Werte:

auf_dem_stack, 2x3 Array, Wert   28FF24, Zeiger   28FF24.
auf_dem_stack[0]--- (Adresse: 28FF24) = d @
auf_dem_stack[0][0] (Adresse: 28FF24) = Spalte0Zeile0
auf_dem_stack[0][1] (Adresse: 28FF28) = Spalte0Zeile1
auf_dem_stack[0][2] (Adresse: 28FF2C) = Spalte0Zeile2
auf_dem_stack[1]--- (Adresse: 28FF30) = Ž @
auf_dem_stack[1][0] (Adresse: 28FF30) = Spalte1Zeile0
auf_dem_stack[1][1] (Adresse: 28FF34) = Spalte1Zeile1
auf_dem_stack[1][2] (Adresse: 28FF38) = Spalte1Zeile2


Kann es wirklich so einfach sein?

Gewiss nicht.
Der Unterschied ist erst im Speicher zu sehen:
Bei der Tabelle mit den Zahlenwerten von Teil 1

stehen die Werte auch dort, wo sie laut Ausgabe der Adresse im Konsolenfenster auch stehen sollen.

Mit Zeichenketten als Inhalt

ist allerdings keine Spur mehr von den Werten an den angegebenen Adressen zu finden.

Was wir hier nicht sehen ist, dass wir kein zweidimensionales Array haben, sondern ein dreidimensionales.
An den angegebenen Speicheradressen stehen wieder nur 4 Byte große Zeiger, printf's %s ließt netterweise direkt von der Zeigeradresse bis zum NUL-Terminator. Man bekommt also auch hier als Programmierer nichts davon mit, solange alles statisch bleibt, auf dem Stack.

So sieht die Tabelle im Computer aus:
auf_dem_stack sei hier gekürzt a.
Die Zahlen in den ersten Zeilen geben a[SPALTE][][] wieder,
die Zahlen in den zweiten Zeilen a[][][INDEX],
die Zahlen in der erste Spalte, sowie die Spalte in der Mitte der drittletzten Zeilen geben a[][ZEILE][] wieder.
Diese sind extra hervorgehoben.






















000000000000000 111111111111111
 012345678910111213  012345678910111213
0Spalte0Zeile0NUL 0Spalte1Zeile0NUL
1Spalte0Zeile1NUL 1Spalte1Zeile1NUL
2Spalte0Zeile2NUL 2Spalte1Zeile2NUL

Das Array dynamisch auf dem Heap anzulegen folgt dem gleichen Schema wie in Teil 1 das int Array, nur eben mit einem * mehr.

C ist schlechthin die maschinennahe Programmiersprache (Assembler ist näher dran, ok), in Sachen Geschwindigkeit kommen da andere Sprachen (C#, Java, etc) nicht nach.
Das bedeutet aber auch, dass alles auf einem sehr niedrigen Level stattfindet, es gibt keinen String Datentyp.

Prekär wird es, wenn die Daten dreidimensional vorliegen, wie etwa bei Koordinatensystemen:
int koordinaten[x][y][z];
Mit integer leicht verdaulich, mit char wird es eine Dimension mehr, folglich vierdimensional.
Und das ist schwer vorstellbar. Dafür gibt es Zeiger, die * "Sternchen".