PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kleine Frage zu Pointern in C++



Ynnus
18.11.2004, 19:46
Hallöchen,

ich befasse mich gerade etwas mit C++, bin gerade bei den Pointern, und da kommen jetzt erste Fragen auf. Ich orientiere mich an diesem Tutorial, habe bisher von vorne bis zu den Pointern durchgemacht (war ja auch noch nicht so viel) und hab dann jetzt folgendes Problem:
Tutorial: http://www.cplusplus.com/doc/tutorial/tut3-3.html | Überschrift: Pointer initialization


As in the case of arrays, the compiler allows the special case that we want to initialize the content at which the pointer points with constants at the same moment as declaring the variable pointer:

char * terry = "hello";

in this case static storage is reserved for containing "hello" and a pointer to the first char of this memory block (that corresponds to 'h') is assigned to terry
(...)
it is important to indicate that terry contains the value 1702 and not 'h' nor "hello", although 1702 points to these characters.(Dazu sei zu sagen, dass in diesem Tutorial der Wert 1702 als Beispieladressierung im Speicher gewählt wurde. Das ist also die Adresse im Speicher, als Beispiel).

So, es geht um den letzten Satz. Der ist besonders wichtig bzw. mir nicht ganz verständlich. Bisher hab ich es so registriert, dass wenn ich einen Pointer erstelle, die so mache:


int variable = 9; //erstmal die Variable
int * pointer = &variable; //pointer auf Speicheradresse von Variable setzen
So, wenn ich mir nun per "cout"-Funktion "pointer" ausgeben lasse, erhalte ich die darin gespeicherte Adresse zu "Variable". Lasse ich mir "*pointer" anzeigen, so gibt er mir den Wert der Variable, also 9 aus. Soweit so gut. Nun macht mir das Tutorial-Beispiel oben mit dem String aber Probleme.

So sieht mein Programmchen aus:

#include <iostream.h>

int a (0);
char * terry = "hello";

int main()
{

cout <<"Pointer: " <<*terry;
cout <<"\n"<<"Value: " <<terry;
cout <<"\n"<<"Adresse: " <<&terry;

cin >> a;

return 0;
}

Wer sich das ausgeben lässt, erkennt, dass nun der Inhalt des Pointers terry jetzt nicht die Speicheradresse des ersten Characters von "Hello" enthält sondern den kompletten String "Hello". Dahingegen ist der Wert des Pointers, also mit *terry jetzt nur das "h", also der erste charakter. Die Speicheradresse von terry, also per &terry liefert mir dann erst den gewünschten Speicherwert von "hello".
Wie soll ich diese Unstimmigkeiten nun verstehen? Warum kann "terry" hier nicht wieder die Speicheradresse enthalten und *Terry dann eben das "Hello" oder das "H"?

it is important to indicate that terry contains the value 1702Darum geht's, wieso zeigt er mir dennoch "Hello" an, anstelle des Speicherswertes 1702 (welcher hier als Beispiel genommen ist)?

Im Tutorial wird erwähnt, dass diesmal der Pointer einen Speicherbereich (also Buffer) reserviert, von 6 Byte. Kann ich jetzt darauf schließen, dass wenn man nicht explizit per "&-Operator" die Speicheradresse in den Pointer schreibt, sondern eben die Zeichenkette "Hello", dass dann der Pointer nicht die Adresse sondern diesen Speicherbereich als eine Art Buffer sich anlegt und wiedergibt? Wie kann man das anständig Unterscheiden, wann was durch ein simples "cout<<pointer"; zurückgegeben wird und wann dann * und & nötig ist?
Ich hoffe hier gibt's jemanden der mir das anschaulich vermitteln kann, ist etwas verwirrend. ;)

mfg.

Sunny

Bluebird
18.11.2004, 23:04
In C++ werden Arrays und Pointer ähnlich behandelt. Wenn du z. B. ein Array anlegst und im Programm nur den Namen des Arrays benutzt (ohne die eckigen Klammern), dann behandelt der Compiler das wie einen Pointer; umgekehrt gehts auch (Pointer mit eckigen Klammern). Wenn du dem cout-Objekt einen char-Pointer übergibst, wäre das also so, als ob du ihm ein char-Array übergibst und er signalisiert das als String, also gibt er es auch als String aus. D. h. dass wenn das cout-Objekt einen Pointer auf ein char übergeben bekommt, dass es dann das als String ausgibt. Was ich hier rede muss nicht alles stimmen, aber ich bin mir sicher, dass es so ist *g*.

Dingsi
18.11.2004, 23:11
*short posting am abend*.
Bluebird hat recht. Der operator<< von cout erkennt dass du ihm ein char-Pointer übergibst und kann vollkommen selbstständig den Rest des Strings auslesen... schlaues Bürschli. Jo, Jo.

Versuch mal einem void-Pointer (void* bla) den Wert von terry zu zuweisen und dann diesen mit cout auszugeben. Dann solltest du die Addresse von dem ersten Zeichen erhalten, denke ich. Ganz sicher bin ich mir aber nicht.. Kann cout<< void*s handlen?
char* terry = "Hallo";
void* test = terry;
cout << "terry: " << terry << endl; //: Hallo
cout << "test-terry: " << test << endl; //: 12345624 oder so.

Zu dem Speicherbelegen usw: Das macht der Compiler automatisch wenn du irgendwo einen String benutzt. Also wenn du schreibst "Hallo" reserviert der Compiler an der Stelle automatisch Speicher für eben den String und gibt den Pointer zum ersten Zeichen zurück.

Ynnus
19.11.2004, 00:11
Ich hab das jetzt mal so geschrieben:

#include <iostream.h>

int a (0);
char * terry = "hello";
void * test = terry;

int main()
{

cout <<"Pointer: " <<terry;
cout <<"\n"<<"Value: " <<test;

cin >> a;

return 0;
}


Nur, wie kann ich jetzt prüfen, ob der ausgegebene Speicherwert von "test" wirklich der gleiche ist wie er in terry steht? Also wenn ich "*test" ändere müsste sich ja auch der Wert in *terry ändern. Allerdings gibt mir der Compiler eine Fehlermeldung aus, kann wohl keine Werte ändern solange der pointer "test" noch void ist.
Kann man das irgendwie anders prüfen? Etwa den typ casten vielleicht? Nur dann darf es diesmal kein Char sein sonst handhabt er es irgendwie sicher wieder wie ein String oder sowas. Wie könnte man das jetzt testen ob die Speicheradressen stimmen?

Dingsi
19.11.2004, 15:50
Hast du das nicht selbst in deinem ersten Post beantwortet? Du kannst ja &terry abfragen.
Zum ändern: Du kannst ja versuchen test = (void*)"Test-String"; zu machen. Ich überleg grad nur was der Compiler dann mit den alten Daten macht... mh. Obwohl .. sollte iegentlich gehen. Normale char*-Strings kann man ja auch einfach wieder mit = "Bla" überschreiben.

Ynnus
19.11.2004, 20:31
Der Pointerwert von test und *terry sind aber nicht identisch. :(
Naja, jetzt hab ich das mal so aufgefasst, wenn das Cout-Objekt einen String erkennt, wird dieser so ausgegebene, ist es ein Pointer der einen String erhält, wird dieser anstelle der Speicheradresse ausgegeben. Hoffe das ist so jetzt korrekt.

=============================

Andere Frage noch zu C++:
In dem einglischen Tutorial von oben hieß es, dass es keinen Typen für Strings gibt, demnach nutzt man da Arrays oder Pointer welche die Zahlenketten speichern, so wie oben, der Pointer. So stehts im englischen Tutorial:

In C++ there is no specific elemental variable type to store strings of characters. In order to fulfill this feature we can use arrays of type char, which are successions of char elements. Remember that this data type (char) is the one used to store a single character, for that reason arrays of them are generally used to make strings of single characters.

In diesem deutschen Tutorial heißt es jetzt, es gibt einen Typ "String" welchen man da nimmt:

Um einem char einen Buchstaben zuzuweisen darf man nicht char c="a"; schreiben, sondern man muss 'a' schreiben. Denn "a" ist ein String (Zeichenkette) und 'a' ein zeichen :)
Warum das so ist, behandeln wir später. Wichtig für uns ist: wenn wir einen String (Zeichenkette) verwenden wollen, dann verwenden wir string als Variablentyp:
Tutorial: http://tutorial.schornboeck.net/variablen.htm

Das ist der Code welcher als Beispiel für Strings gepostet wird:

#include<string> //für string
#include<iostream>
using namespace std;

int main()
{
string str="Hallo Welt";
cout<<str<<"\n";
}

Da jetzt meine Frage, was ist die gängige oder korrekte Methode, oder überhaupt erstmal, wer hat Recht? Gibt es diesen Typ "String" wirklich als Typus oder was ist das? Ich hab früher mal gehört, dass alle Strings in C++ Pointer sind (ein Array ist ja auch ein Pointer) und es somit keinen Typ "String" gibt. Jetzt taucht der hier plötzlich auf. Kann mir da jamand genauer erklären was es damit auf sich hat?

Was ich mir dazu denke:
In PureBasic beispielsweise gibt es einen Typ "String", dieser ist allerdings nur ein fiktiver Typ. Denn bei Benutzung des Typs "String" wird ein Pointer erstellt der auf den Inhalt, also auf die Zeichenkette im Speicher weißt. Dadurch wird also ein Pointer erstellt welchen man aber nicht wie einen Pointer handhabt sondern wie eine Variable welche direkt den String enthält.
Jetzt noch die Frage dazu, könnte das so in C++ mit dem obigen Typ "String" genauso sein? Dass da auch intern ein Pointer erstellt wird und nicht eine Variable vom Typ "String"?
Ich hoffe hier findet sich jemand der da Ahnung von hat, ein wenig widersprüchig sind die Sachen in den Tutorials leider manchmal schon.

mfg.

Sunny

Dingsi
19.11.2004, 20:50
In C gibt es keine Strings. In C können nur char-Arrays benutzt werden.
Durch die tollen Neuerungen von C++ wurde aber mit C++ selber der neue Typ string erstellt. Das ist eine Klasse aus der Standard-C++-Bibliothek. Die hat intern zwar immernoch ein char-Array, aber das ganz lässt sich von außen ganz einfach handhaben. Mit allen möglichen Operatoren, Zuweisungen, etc. Wenn du also C++ codest kannst du ruhig std::string aus der STL nehmen. Für nähere Infos ist diese (http://www.sgi.com/tech/stl/basic_string.html) Seite sehr gut geeignet.

regnad
19.11.2004, 21:03
Es gibt keinen "eingebauten" Typ string , sonder string ist eine Klasse aus der STL (Standard Template Library)

Zu dem deutschen Tut:

Wenn er meint "a" wäre ein string, dann meint er eigentlich die sog. c-strings, da eine Zeichenkette in C immer mit '\0' endet (besser: enden sollte, denn C-Strings ohne abschließende Nullterminierung sind eine üble Fehlerquelle, trotzdem wird der Fehler oft gemacht). Tja, und nichts anderes machen die Double Quotation Marks, sie hängen der Zeichenkette "a" ein '\0' an, z.B.:


#include <assert.h>

int main( void )
{
char str[] = "abc";

assert( sizeof( str ) == 4 );

assert( str[3] == '\0' );

return 0;
}

Ynnus
22.11.2004, 00:57
Ok, dank euch schonmal, ich werds mir mal ansehen, was es da so zu Strings und co gibt. ;)

Dann hätt' ich allerdings noch eine kleine Frage, da ich diesen Thread schon habe, belasse ich es hier drinnen.
Gibt es einen Unterschied zwischen den Konstanten welche ich per #define und per "const" deklariere? Bei Define gebe ich ja auch keinen Typ an, den die Konstante haben soll.
Also praktisch:

#define constante 100
Verglichen mit:
const short constante = 100;

Kennt hier jemand den Unterschied oder gibt es da garkeinen? (Ist ja in C++ öfters mal so, dass man 2/3 Dinge unterschiedlich schreiben kann und sie dennoch den selben Effekt haben)

Dingsi
22.11.2004, 12:53
Mit #define legst du etwas für den Compiler fest. Das ist nur ein Alias. Der Compiler _ersetzt_ die Konstante.
#define BLUBB 5
mach_etwas_mit_der_zahl(BLUBB);
// ist für den Compiler wie
mach_etwas_mit_der_zahl(5);
BLUBB = 5; // Ergäbe
5 = 5; // Fehler denke ichconst typ bla dagegen erzeugt mehr oder weniger wirklich die Variable bla mit dem Wert 5, bloß das der Wert nirgens mehr verändert werden kann..
const int BLUBB = 5;
mach_etwas_mit_der_zahl(BLUBB);
// ist für den Compiler wie
mach_etwas_mit_der_zahl(BLUBB);
BLUBB = 5; // Ergäbe wirklich BLUBB = 5, würde aber einen Fehler verursachen, da du versuchst eine Konstante zu beschreiben.