# Algemeines zu char * und char[]



## lindin (14. September 2004)

Hallo, ich habe eien Farge zu dem Unterschied zwischen char[] und char *!

Ich habe jetzt schon öfter gehört, daß es da keinen unterschied gibt!

Ich denke, der Unterschied ist, daß bei char[] ein fester Speciehr reserviert wird bei der Deklaration!

Aber ich verstehe nicht, wieso es dann nicht bei char * Probleme mit dem Speicher gibt, da, je länger die Variable wird, der Fall wahrscheinlicher wird, daß eine Speicherverletzuing auftritt!

Ich weiß auch, daß es die Möglichkeit mit malloc gibt, um für char * Speicher zu reserviern!
Das muß man aber nicht, man kann char * "einfach so" verwenden! 
Aber wieso


----------



## Endurion (14. September 2004)

lindin hat gesagt.:
			
		

> Hallo, ich habe eien Farge zu dem Unterschied zwischen char[] und char *!
> 
> Ich habe jetzt schon öfter gehört, daß es da keinen unterschied gibt!


Das betrifft eher die Übergabe an Funktionen, da ist dann kein Unterschied.



> Ich denke, der Unterschied ist, daß bei char[] ein fester Speciehr reserviert wird bei der Deklaration!


Richtig. Bei char* wird direkt gar kein Speicher reserviert (bis auf den für den Zeiger natürlich).



> Aber ich verstehe nicht, wieso es dann nicht bei char * Probleme mit dem Speicher gibt, da, je länger die Variable wird, der Fall wahrscheinlicher wird, daß eine Speicherverletzuing auftritt!


Wenn man nicht aufpasst, gerät man bei char* sehr leicht in den Fehlerfall. Ich habe üblicherweise feste Char-Arrays bevorzugt (MAX_PATH oder 260 o.ä.).



> Ich weiß auch, daß es die Möglichkeit mit malloc gibt, um für char * Speicher zu reserviern!
> Das muß man aber nicht, man kann char * "einfach so" verwenden!
> Aber wieso


Das kann nur dann klappen, wenn man einen konstanten Wert benutzt wie:

char*  szHallo = "Hallo Welt!"

Solange von dem Pointer nur dieser String gelesen wird, ist das völlig in Ordnung. Der Compiler belegt in diesem Fall den Speicher für den String und setzt den Zeiger auf die Adresse.
Das geht natürlich ganz schnell in die Hose, wenn man auf den Pointer schreibend zugreift. Mit etwas Glück passiert nichts (kein Speicher-Schreibschutz, innerhalb des belegten Speichers geblieben) oder eben auch ein Absturz direkt beim Aufruf.
Oder, am allerschlimmsten, ein Absturz, wo er absolut nicht vermutet wird, weil man eben doch über den Speicherbereich rausgeschrieben hat.

Ach ja, wer in C++ heute statt std::string noch char* oder char[] benutzt, hat entweder sehr gute Gründe (wüsste auf Anhieb keinen) oder seine Probleme einfach verdient.


----------



## lindin (14. September 2004)

Ahso, std:string ist also besser 

Ich nutze char, da mir früher nur ansi-c eingetrichtert wurde!

Also fahr ich am besten, wenn ich stat char * immer char[] verwende, alles klar!

Streng genommen sollte man also gar nicht char * verwenden, wenn man das nicht in der Form 
char * x="kjsfd" ;

sondern 
char * x;
x="kjsfd";

macht!

Hm hm, also ich verstehe einfach nicht, wieso die Benutzung von char * dann in der Form überhaupt möglich ist, müßte denn dann ein Compiler nicht eine Fehlermeldung ausgeben?


----------



## Beichtpfarrer (14. September 2004)

> *Ahso, std:string ist also besser
> Ich nutze char, da mir früher nur ansi-c eingetrichtert wurde!*


Mach es wie du willst, kann beides Vorteile haben, kommt auf den Anwendungsfall an.



> *
> Streng genommen sollte man also gar nicht char * verwenden, wenn man das nicht in der Form
> char * x="kjsfd" ;
> sondern
> ...


Die beiden Formen machen überhaupt keinen Unterschied. Die meisten (wenn nicht alle) Compiler generieren dafür sogar den gleichen Assembler-Code.
Bei meinem Compiler sieht die Umsetzung folgendermassen aus: Wenn du irgendwo im Quellcode eine Zeichenkette wie "kjsfd" benutzt, wird sie im Datensegment des Prozesses gespeichert. Bei jeder Benutzung wird ein Zeiger auf diese Stelle im Datensegment zurückgegeben, so kann man sogar beliebig oft die gleiche Zeichenkette benutzen, ohne dass dadurch die Exe grösser wird und bei einer Zuweisung eines Zeigers an einen String muss kein Speicher reserviert und nachher wieder freigegeben werden (was auch ziemlich unmöglich wäre). Dafür gibt es unter Umständen Probleme, wenn man in den Buffer schreiben will.

Edit: Mist, falsche Tags benutzt....


----------



## lindin (14. September 2004)

Du meinst, wenn man folgendes macht:

```
char * x ="test";
char * y ="test";
```

Daß dann beide Variablen auf den gleichen Speicherbereich zugreifen, weil es der gleiche String ist? Oder hab ich das jetzt falsch verstanden?

Aber wenn dann jetzt z.B. x geändert wird, wird dann das geänderte x in einen anderen Speicherbereich geschrieben, und y weist noch auf den selben Speicherbereich wie vorher?


----------



## canuzzi (14. September 2004)

*char*

Also bei der Deklaration wuerde ich auch immer  die Vektorversion nehmen, damit mir auch immer klar ist das ich einen string habe und keinen einfachen pointer auf char - aberim weiteren ist die pointerversion sehr schoen kompakt.


----------



## lindin (14. September 2004)

Also ich habe das bisehre immer so gehandhabt, daß ich die Pointerversion genommen ahbe, wenn ich nicht wußte, wie lang der String wird!
Da gibt es ja auch dann Probleme, wenn man über den allokierten Bereich hinausschreibt!
Ich hatte mir zwar schon gedacht, das char[] besser für die Speicherverwaltung ist!
Hab aber auch gedacht, wenn ich immer char * nehme, dann wird die Datei hinterher so klein wie möglich!
Wenn man nämlich nicht weiß, wie lang der String wird, dann müßte man sehr große Arrays deklarieren, und das macht die exe-DAtei dan natürlich immer größer!

Naja, ich denke, ich bin nun überzeugt davon nur noch arrays zu verwenden


----------



## Beichtpfarrer (14. September 2004)

> *Du meinst, wenn man folgendes macht:
> *
> 
> ```
> ...


Genau so mein ich das.


> *
> Aber wenn dann jetzt z.B. x geändert wird, wird dann das geänderte x in einen anderen Speicherbereich geschrieben, und y weist noch auf den selben Speicherbereich wie vorher? *


Wenn x so geändert wird:

```
char * x ="test";
char * y ="test";
x = "was anderes";
```
dann zeigt x danach natürlich auf einen anderen Speicherbereich, als y.
folgendes:

```
char * x ="test";
*x = 'a';
```
führt bei mir zum Programmabsturz.
Besser wäre:

```
char x[] = "test";
//oder:
char* g = new char[256];
strcpy(g,"test");
```
Beide Fälle stellen sicher, dass kein anderer Zeiger/kein anderes Array den gleichen Speicherberreich nutzt.

edit: Schon wieder Tags verwechselt...


----------



## C Coder (14. September 2004)

@lindin:
Also soweit ich weiß wird durch große Array benutzung wie:

```
char ganzganzgroßesArray[512000]; //500 Kbyte
```
nicht die exe-datei größer. Nur wenn das Programm ausgeführt wird natürlich mehr Platz im Stack beansprucht.


----------



## randomize (14. September 2004)

> _Original geschrieben von C Coder _
> *@lindin:
> Also soweit ich weiß wird durch große Array benutzung wie:
> *
> ...



Yo, denke ich auch. Platz für Variablen wird schließlich selten in die EXE reincompiliert, AFAIK...


----------



## lindin (15. September 2004)

Ach so, das wäre natürlich schön, denn wieviel Platz hinterher beansprucht wird, ist mir erstmal egal, hauptsache, die exe bleibt so klein wie möglich!

Jetzt habt iht mich auf noch eine Frage gebracht:


> Besser wäre:
> 
> Code:
> --------------------------------------------------------------------------------
> ...



Hier zeigt ja g dann auf ein array!
und ich kann dafür strcpy benutzen, was ich für einen sonstigen char-Zeiger nicht verwenden kann!

kann ich denn für g jetzt auch Fnktionen verwenden, die ich sonst nur für char-Zeiger verwenden kann?

z.B habe ich oft Probleme, wenn ich einem char-Array eine char-Zeiger-Variable zuordne:

```
char t[255];
char *s="test";
t=s;
```

Ich kann nur entweder mit strcpy ein char-Array in eina nderes kopieren, oder mit strdup eine char-Zeiger-Variable in eine andere kopieren!

Wenn ich jetzt wie oben

```
char * g=new char[255];
```

verwende, dann könnte ich die Variable wie eine Zeigervaribale verwenden, müßte aber nicht Angst haben, daß ich eine Speicherverletzung provoziere (vorausgesetzt die Variable wird nicht länger als 255)!

Also meine Frage, wie ist diese Variable dann zu behandeln, wie ein Array oder wie ein Zeiger?


----------



## Beichtpfarrer (15. September 2004)

Ich glaube, du hast noch nicht so genau verstanden, was ein Zeiger und was ein Array ist.

Zeiger: ist 4 Byte gross und beeinhaltet eine Addresse deines Arbeitsspeichers. (muss zwar nicht unbedingt wirklich im Arbeitsspeicher sein, aber für dich macht es keinen Unterschied).
Er zeigt also auf einen Buffer/Speicherbereich.
Der Typ char* gibt nur an, dass das, was an diesem Speicherbereich liegt, als char zu behandeln ist.

char* x = new char[256];
reserviert einen Speicherbereich von sizeof(char)*256 Byte und liefert dessen Speicheraddresse zurück, die anschliessend der Variable zugewiesen wird.
da aber x nicht konstant ist (das wäre char*const x), kann es auch im späteren Programmverlauf auf andere Stellen des Speichers verweisen.

Ein Array dagegen ist selbst ein Speicherbereich.
char f[256]; hat die Grösse sizeof(char)*256 Byte und nicht 4 Byte, wie ein Zeiger es immer hat.
Nur der Name "f" kann im Übrigen wie ein konstanter Zeiger verwendet werden, der auf eben den Speicherbereich zeigt, in dem dieses Array liegt, daher kann nicht f selbst neu zugewiesen werden, sondern nur das verändert, worauf es zeigt.

Also -> Arrays können nur bei Initialisierung String zugeordnet bekommen (die werden dann einfach reinkopiert). Nach der Initialisierung kann man sie nur noch per strcpy usw beschreiben.

Wenn du was nicht verstanden hast (ich glaub, ich kann nicht gut erklärn), schau lieber nochmal in einem C++-Tutorial nach. Zb auf http://www.c-plusplus.de/index.php


----------



## lindin (16. September 2004)

Danke für den kleinen Kurs, habs glaub ich verstanden, nur noch eine Frage!



> char* x = new char[256];
> reserviert einen Speicherbereich von sizeof(char)*256 Byte und liefert dessen Speicheraddresse zurück, die anschliessend der Variable zugewiesen wird.
> da aber x nicht konstant ist (das wäre char*const x), kann es auch im späteren Programmverlauf auf andere Stellen des Speichers verweisen.



Wieso macht man das dann, wenn x hinterher auf einen anderen Speicher zeigen kann?
Und in welchem FAll zeigt x auf einen anderen Speicherbereich?

wenn ich jetzt immer x einen String zuweise: x="string"; dann müßte string immer in dem reservierten Speciherbereich stehen, da x die Adresse beinhaltet!

Wenn ich jetzt x eine andere char-zeiger variable zuordne, dann zeigt x auf den Speicherbereich der andren Variablen, richtig?


----------



## Beichtpfarrer (16. September 2004)

Stell dir die Arbeitsweise deines Prozesses mal etwas technischer an:
Jedes Byte in deinem Speicher ist addressierbar.
Speicherplatz 1 ist das 1. Byte, 2 das 2. usw.

Nehmen wir mal an, deine Exe ist 1kb gross und wird gleich in die ersten 1000 Bytes Speicher geschrieben.

Bis sagen wir zu Byte 400 stehen irgendwelche Header.
Dann folgen globale Variablen, Strings, alles einfach direkt hintereinander.
der String "hallo" ist zB an Byte 450 angelegt, und reicht, da er nicht Unicode ist, bis einschlieslich Byte 455 (5Zeichen + '\0')

Nehmen wir an, du hast einen globalen Zeiger char*x deklariert. Er belegt nun die Bytes 500 bis 503, da er 4 Byte gross ist.
Dann ist erstmal undefiniert, an welche Stelle er zeigt, da du ihn nicht initialisiert hast, is ja logisch. Der Versuch ihn zu dereferenziern würde sehr wahrscheinlich zum Programmabsturz wegen nicht authorisiertem Speicherzugriff führen.
machst du jetzt x="hallo", werden diese 4 Bytes einfach mit der Addresse 450 beschrieben, da dort der String "hallo" liegt. Schreibst du im späteren Programmverlauf noch irgendwo x="anderer string"; nehmen die 4Bytes die Addresse des ersten Bytes von "anderer string" ein, dabei geschieht aber nichts mit dem Speicher an Byte 450.
Das ist ja der Sinn von Zeigern -> Sie verweisen auf andere Variablen, so können zur Laufzeit Variablen verwendet werden, die zur Kompilationszeit noch nicht mal bekannt sein müssen.

Ich glaube, eins deiner Probleme ist auch, dass du annimmst, ein char* ist gleichbedeutend mit einem String.
Es ist in erster Linie mal so: Ein char* zeigt auf einen char, beeinhaltet also die Speicheraddresse einer char-Variable.
Jetzt können bestimmte Funktionen natürlich vorraussetzen, dass hinter dieser ersten Char-Variable mehr ist.
Ein Beispiel dafür sind Strings: es ist verlangt, dass aller Speicher hinter der ersten char-Variable zugreifbar ist, bis ein 0-Zeichen kommt.

Also mehr kann ich jetzt echt nicht erklärn.......


----------



## lindin (16. September 2004)

Also tut mir leid, wenn ich Dich nerve!

Also wenn einmal an stelle 450 einen String geschrieben hat, dann bleibt der da die ganze Zeit stehen?

Das heißt, wenn man im Verlauf eines Programms immer andere Strings verwendet, wird immer mehr Speicher gebraucht, weil der Speicher der andreen Strings nicht überschrieben wird?

Also wenn man einem Zeiger einen String zuweißt wird der ganze Speicherbereich durchsucht, und geguckt, ob irgenwo der String steht? Und wenn nicht, wird er neu in den Speicher geschrieben?

Könnte ich denn z.B. den Speicher an dem ein String steht frei machen, damit ich weniger Speicherverbrauch habe, wenn ich den String nicht mehr brauche?

Und wenn man wirklich an die Stelle schreiben will, wo der Zeiger hinzeigt, dann muß man &Zeiger nehmen?


----------



## RedWing (16. September 2004)

Bingo!

Beispiel:

```
char *name = new char[7];
  name[0] = 'l'; name[1] = 'i':name[2] = 'n'; name[3] = 'd'; name[4] = 'i'; name[5] = 'n';
  name[6] = '\0';
  ....

  //ab jetzt brauchst du deinen name nicht mehr und willst den Speicher wieder freigeben
  delete[] name;
  //ab jetzt kannst du dich umbennen
  name = new char[10];
  name[1] = 'A';
  ... //usw
```

Gruß

RedWing


----------



## lindin (16. September 2004)

Aha, das kannte ich nicht, danke!


----------

