Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

10.1.4 Konstante Strings und Stringkonstanten

10.1.4 Konstante Strings und Stringkonstanten

Um noch einen drauf zu setzen, möchte ich Ihnen noch die konstanten Strings zeigen. Sie werden in einem separaten Konstantenspeicher gehalten und vom Compiler verwaltet. Im Stack befindet sich dann nur noch eine Referenz, also ein Pointer auf diese Konstante. Man hat also einen quasi dynamischen String. Als es eben um dynamische Strings ging, habe ich schon kurz gezeigt, dass man einen Pointer auf einen konstanten Wert zeigen lassen kann. Ich habe auch dazu gesagt, dass es möglich ist, diesen Zeiger dann zur Laufzeit auf eine andere Konstante umzubiegen. Wenn man aber bei der Variablendeklaration den Modifikator "const" mit vor den Typ schreibt, ist dies auch nicht mehr möglich. Dies wird in der Regel aber nur in Funktionsköpfen getan, um den Nutzer der Funktion zu garantieren, dass sein String unverändert bleibt.

An folgendem Quelltext möchte ich noch einmal die Unterschiede klar machen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
					
const char*	astrConstString		= "konstant";
char*		pcstrConstString	= "konstant";
char		aStaticString[10]	= "statisch";

char*	pstrDynamicString		= new char[10];
strcpy(pstrDynamicString, "dynamisch");

printf("%s\n", astrConstString);	
printf("%s\n", pcstrConstString);
printf("%s\n", astrStaticString);
printf("%s\n", pstrDynamicString);

aConstString2				= "Konstant";	// Verweis auf neue Konstante
aStaticString[0]			= 'S';		// Zeichen Austauschen
pstrDynamicString[0]			= 'D';		// Zeichen Austauschen

printf("%s\n", aConstString2);
printf("%s\n", aStaticString);
printf("%s\n\n", pstrDynamicString);

delete [] pstrDynamicString;
					

Ausgabe:

konstant
konstant
statisch
dynamisch

Konstant
Statisch
Dynamisch
		

Speicherverwaltung verschiedener Stringtypen vor Änderungen

Hier sind zunächst die drei Speicherbereiche gut ersichtlich. Der Stack ist ja der Speicher, welcher zwar nicht so groß ist, aber auf welchem wir bedenkenlos Daten anlegen können, ohne uns um deren Verwaltung zu kümmern.

Der Const-Speicher ist ein Speicherbereich, welcher vom Compiler bereit gestellt wird und mit jedem Programmstart reserviert wird. Der Zugriff ist ausschließlich lesend und die Verwaltung übernimmt der Compiler. Er ist es auch, welcher für eine automatische Größe sorgt. Versucht man einen String auf eine Konstante zu löschen, geht das zwar im ersten Moment, aber spätestens beim Programmende, wird es einen Fehler geben, weil der Compiler Code eingefügt hat, um dies zu tun (und somit würde es doppelt passieren).

Der Heap ist der größte Bereich des Speichers und auf ihn kann man nur über eine Referenzierung heran kommen. Speicherplatz muss selbst erstellt und freigegeben werden. Wenn man versucht einen Zeiger auf einen solchen String auf eine Konstante biegt, ist das zwar im Moment ok, aber der reservierte Platz kann nicht mehr freigegeben werden, da man nicht mehr weiß, wo der Speicherbereich ist, der freizugeben ist.

In der Grafik ist auch schön zu erkennen, dass sowohl der Zeiger auf die Konstante, als auch der Zeiger auf den dynamischen String, im Stack liegen, aber dann wo anders hin verweisen. Lediglich der statische String wird komplett im Stack gehalten. Schaut man sich aber den Quelltext dazu an, sieht man nicht so schnell den Unterschied.

Gerade der Unterschied zwischen Zeile 2 und 3 ist wichtig. Ich hatte ja mal gesagt, dass man ein Array bei der Definition entweder mit dem Stern am Variablentyp oder mit den eckigen Klammern am Variablenname setzen kann. Der Unterschied bei Strings ist nun, dass die Angabe mit den eckigen Klammern und einer Größenangabe, ein Array im Stack anlegt. Zusätzlich existiert eine Konstante im Const-Speicher, welche dann in das Array kopiert wird. Somit kann man den Inhalt verändern, wie in Zeile 14 gezeigt. Die Angabe mit dem Punk ist lediglich ein Zeiger. Hier kann kein Array im Stack angelegt werden, da ja die Größe nicht explizit angegeben wird. Somit wird ein Verweis auf den Inhalt im Const-Speicher gesetzt. Dieser Verweis kann zwar zur Laufzeit umgebogen werden, wie in Zeile 13 gezeigt, aber man kann den Inhalt nicht ändern, solange der Zeiger auf den Const-Speicher zeigt.

Auch wenn das Verwirrend klingt, aber Sie müssen immer unterscheiden zwischen einem konstanten String und einer Stringkonstante. Ein konstanter String ist ein nicht veränderbarer Pointer auf einen String und dieser kann nicht umgebogen werden. Falls der Zeiger aber auf einen Bereich im Stack oder Heap zeigt, kann man den Inhalt durchaus ändern. Eine Stringkonstante hingegen ist ein Bereich im Const-Speicher. Die Referenz kann umgebogen werden, aber der Inhalt kann nicht manipuliert werden.

Um noch einen drauf zu setzen, gibt es auch konstante Stringkonstanten. Das sieht man in Zeile 1. Hier habe ich einen String definiert, welcher auf eine Stringkonstante zeigt. Dieser Zeiger kann auch später nicht mehr umgebogen werden und der String selbst ist nicht änderbar.

Nach den änderungen ab Zeile 13, sieht der Speicher wie folgt aus.

Speicherverwaltung verschiedener Stringtypen nach Änderungen

Sie sehen hier sehr schön, dass "pcstrConstString" zwar scheinbar geändert wurde, er aber im Grunde nur auf einen anderen Bereich im Const-Speicher verweist. Bei dem statischen und dem dynamischen String hingegen, wurde tatsächlich der Inhalt geändert.

Ich kann gut verstehen, wenn Sie jetzt einen Knoten im Kopf haben sollten. Wenn dem so ist, lesen Sie dieses Kapitel einfach noch einmal in Ruhe durch. Ich muss selber auch zugeben, dass ich jedes Mal aufs Neue nachdenken muss. Jetzt verstehen Sie vielleicht warum man sagt, dass Strings in C das komplizierteste Thema ist.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012