1. Zeile: Einfach nur einen neuen Zeiger der auf "Auto" zeigt, d.h. es gilt
src[0] = 'A',
src[1] = 'u',
src[2] = 't',
src[3] = 'o'. Verstehst du, wieso das gilt? Ein Array in C ist nichts anderes als ein Zeiger auf das erste Element des Arrays, und die anderen Elemente des Arrays liegen im Speicher direkt dahinter. Deswegen kannst du ein Array genau so behandeln wie ein Zeiger, und ein Zeiger genau so wie ein Array.
2. Zeile:
len bekommt die Länge von
src, also den Wert
4.
3. Zeile: Hier wird neuer Speicher reserviert.
malloc nutzt du, um Speicher auf dem Heap zu reservieren. Dazu etwas: Du hast im Grunde zwei Speicherbereiche: Stack und Heap.
Wenn du innerhalb einer Funktion eine Variable anlegst, dann wird sie auf dem Stack gespeichert. Sobald die Funktion zu Ende ist, werden alle Variablen, die in ihr angelegt wurden, gelöscht. Genauer: Stell dir den Stack wie ein langes Band vor, auf das Werte gelegt werden können. Dazu gibt es einen Zeiger der auf das nächste freie Feld zeigt. Wird ein Wert darauf abgelegt, dann kommt der Wert also auf das Feld, auf den der Zeiger momentan zeigt, und er bewegt sich anschließend ein Feld nach vorne.
Wenn nun eine Funktion betreten wird, dann merkt sich dein Programm wo sich der Zeiger momentan befindet. Wird die Funktion beendet, dann wird der Zeiger einfach auf die gemerkte Position zurück gesetzt, sodass alle Werte, die während der Funktion aufs Band gelegt wurden, sich nun wieder im freien Bereich befinden.
Praktisch heißt das also: Legst du in einer Funktion eine lokale Variable an, und die Funktion ist vorbei, war es das auch mit der lokalen Variable. Deswegen funktioniert in C zum Beispiel folgendes auch nicht:
Code:
char *get_string(void) {
char string[80];
strcpy(string, "Hello world!");
return string;
}
int main(int argc, char **argv) {
printf("%s\n", get_string());
return 0;
}
Denn:
char string[80]; ist eine lokale Variable, also auf dem Band.
get_string() liefert nun zwar den Zeiger auf den Anfang von unserem Text zurück, aber wir nutzen diesen Zeiger erst, nachdem die Funktion zu Ende ist. Der Zeiger zeigt also in den freien Bereich vom Stack-Band, und damit gibt es keine Garantie mehr, dass dort tatsächlich noch das liegt, was wir gerne haben wollen.
Weil manche Werte nun aber behalten möchte, wenn eine Funktion vorbei ist, gibt es den Heap, also ein zweites Band. Hier ist es völlig egal, wann wir uns dort Speicher holen, wann eine Funktion beginnt oder zu Ende ist. Wir reservieren manuell mit
malloc() dort Speicher und geben ihn mit
free() wieder frei. Von dort holt sich Jeoni in seinem Beispiel den Speicher, und zwar
len + 1 Bytes, also fünf Bytes. Genau so viel brauchen wir, um das Ergebnis zu Speichern:
o, t, u, A, \0
Dabei soll \0 das Byte "0" sein und nicht das Zeichen "0". Das hängt an jedem String hinten dran, damit das Programm weiß, wann der String zu Ende ist. Deswegen benötigt ein String der Länge
n auch immer
n + 1 Bytes. Beachte, dass
strlen() wirklich die Länge des Strings liefert, also nicht die Anzahl der Bytes, die du brauchst, um ihn zu speichern.
4. Zeile: Klar. Vielleicht nur:
size_t ist oft ein Alias für
unsigned int, der immer genutzt wird, man die Größe von einem Array speichern möchte.
5. Zeile: Das letzte Byte wird auf "0" gesetzt, um also zu zeigen, dass der String dort zu Ende ist.
Rest:
i wird auf
len - 1 = 3 und ebenso
len auf
len - 1 = 3 gesetzt. In der Schleife werden die einzelnen Bytes rüber kopiert, konkret so:
Code:
dst[0] = src[3] (len = 3, i = 3)
dst[1] = src[2] (len = 3, i = 2)
dst[2] = src[1] (len = 3, i = 1)
dst[3] = src[0] (len = 3, i = 0, Schleife terminiert)
Die Schleife terminiert, wenn
i = 0 gilt, denn
i ist die Bedingung: Jeder Zahlenwert ungleich Null entspricht in C wahr und nur der Zahlenwert Null entspricht falsch. Deswegen terminiert die Schleife also, wenn
i Null ist. Wie du an den konkreten Werten nachvollziehen kannst, wird der String also in umgekehrter Reihenfolge nach
dst kopiert.