Zeiger und Vektoren



  • Genau...allerdings wird wenn ich cptr mit cout ausgebe trotzdem das komplette Wort ausgegeben.
    Wenn ich einen normalen Zeiger vom Typ int mit einer Integer-Variablen intialisieren und dann ohne Anwendung
    des Derenferenzierungsoperators (*) mit cout ausgebe (so wie in meinen Code-Beispiel) wird mir die
    Adresse ausgegeben. Warum da die Adresse und bei Vektoren das ganze Objekt?



  • Weil std::cout für verschiedene Typen verschiedene Dinge tut. Ganz einfach. Wenn du eine Variable vom Typ char* übergibst, dann weiß cout (bzw. operator<< weiß), dass du einen nullterminierten String ausgeben willst. Bei anderen Pointer-Typen gibt es keine solche Spezialbehandlung und dann kommt eben die Adresse raus.

    Im Prinzip liegt es also daran, dass der operator<< vom ostream für char* überladen ist. Siehe hier: https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2

    Man hat also einen Spezialfall, der sehr nützlich ist, eingebaut.

    Edit: Bitte sprich lieber von einem Array, wenn du Arrays meinst. In C++ versteht man unter "Vector" eigentlich immer std::vector.



  • Alles klar...dann weis ich Becheid. Vielen Dank!
    Im Kapitel Zeiger und Arrays habe ich allerdings eine weitere Funktion vor mir, bei mir ich nicht
    verstehe was da gemacht wurde/wie das möglich ist:

    int strlen(char * str)
    {
    char * p = str;
    for (p=str; *p != '\0'; ++p)
    ;
    return (p -str)
    }

    Warum wurde hier str ohne Verwendung des Adressoperators & den Zeiger p zugewiesen. Wären nicht
    die beiden Varianten char* p = &str bzw. char *p = *str nur möglich?
    Was drückt dann der Ausruck p=str bzw. ++p aus? Müsste nicht eigentlich der Verweisoperator * angewendet werden
    wenn dort Werte zugewiesen werden bzw. in dem String weitergesprungen wird?



  • @C-Sepp hmm, steht in deinem Buch wirklich

    int strlen(char * str)
    

    ?
    Falls ja, würde ich das Lehrmaterial wechseln.

    size_t strlen(const char *str)
    {
    	const char *p;
    	for (p = str; *p; ++p)
    		;
    	return (p - str);
    }
    


  • Innerhalb von strlen ist str eine lokale Zeiger-Variable.
    Ebenso wie p

    Bei &str bekommst du die Adresse, wo str selber liegt. dies wäre auch vom Typ char** (Ein Zeiger auf einen Zeiger auf char).
    Mit *str bekommst du den Wert an der Stelle str. das wäre ein char.

    Beide Typen passen nicht zu p (was ja ein char* ist)

    @C-Sepp sagte in Zeiger und Vektoren:

    Was drückt dann der Ausruck p=str

    Eine Zuweisung: p bekommt den Inhalt von str. Also die Adresse die in str abgelegt ist.
    (ist hier überflüssig, da dies in der Zeile davor (Definition von *p mit Initialisierung) schon gemacht wird.

    bzw. ++p aus?

    Das ist Pointer-Arithmetik. der Inhalt von p wird erhöht. p Zeigt jetzt auf das nächste Element.
    Dabei wird die Größe von *ptr (hier char) berücksichtigt.

    p-str liefert die Differenz (Abstand) der Adressen.
    Da p auf das Ende com String zeigt, bekommt man somit die Länge.



  • @DirkB sagte in Zeiger und Vektoren:

    p-str liefert die Differenz (Abstand) der Adressen.

    Um das noch zu präzisieren: es ist der Abstand in Einheiten der Größe des Typen, auf den man zeigt. Wenn du z.B. einen Pointer auf einen 32-bit Integer hast (und char 8 Bit hat), dann gehst du mit int_pointer + 1 gleich 4 Bytes weiter, weil eben der Integer 4 Bytes groß ist. Würdest du den Pointer vorher nach char* casten und dann 1 addieren, würdest du noch "in der Mitte" des integers landen. Das heißt, die Differenz hängt von der Pointee-Größe ab. Oder anders: wenn der Typ korrekt ist, bekommst du mit *(pointer+1) immer das nächstfolgende Element im Array.



  • Okay...das habe ich soweit verstanden.
    Müsste im Programmbeispiel:

    double *pv, v[5] = {5.5,4.4,3.3,2.2,1.1}
    for (pv = v+4; pv >=v; --p)
    *pv *=2;

    Warum wird dann der Schleifenrumpf 5 mal durchlaufen?
    Müsste es nicht nur viermal sein, dass heißvon 1.1 zu 2.2, 2.2 -> 3.3, 3.3 -> 4.4, 4.4 -> 5.5?



  • @C-Sepp sagte in Zeiger und Vektoren:

    Warum wird dann der Schleifenrumpf 5 mal durchlaufen?

    Weil bei pv == v (pv zeigt auf den Anfang vom Array) die Bedingung pv >=v noch wahr ist. Die Schleife wird dann nochmal ausgeführt.



  • @C-Sepp sagte in Zeiger und Vektoren:

    double *pv, v[5] = {5.5,4.4,3.3,2.2,1.1}
    for (pv = v+4; pv >=v; --p)
    *pv *=2;
    Warum wird dann der Schleifenrumpf 5 mal durchlaufen?

    Der Code funktionier gar nicht. Oder woher kommt "p"? Wenn du mit p pv meintest, dann verstehe ich dir Frage.

    Müsste es nicht nur viermal sein, dass heißvon 1.1 zu 2.2, 2.2 -> 3.3, 3.3 -> 4.4, 4.4 -> 5.5?

    Aber ich komme auf 5:

    • v + 4
    • v + 4 - 1
    • v + 4 - 2
    • v + 4 - 3
    • v + 4 - 4

    Ich weiß nicht so recht, was du mit "von 1.1 zu 2.2" etc. meinst. Es läuft der Pointer pv (=v + 4) herunter, solange der Wert >= v ist.



  • Ja genau mit p meinte ich pv. Sorry! Okay!!



  • Arbeite gerade die Thematik zu Zeiger und Arrays durch. Darin steht, dass der ++-Operator einen
    höheren Vorrang als der Verweisoperator * hat, weshalb *pv++ mit *(pv++) äquivalent ist.
    In dem Codebeispiel steht wiederrum:

    float v[6] = {0.0F, 0.1F, 0.2F, 0.3F, 0.F, 0.5F}, *pv, x;
    pv= v+4;
    pv -=2;
    ++pv;
    x= *pv++; //v[3] an x zuweisen, dann pv ein Element weiter

    als Kommentar "v[3] an x zuweisen, dann pv ein Element weiter". Müsste es nach der oben aufgeführten Regel
    nicht genau andersrum sein....sprich pv ein Element weiter, dann v[4] an x zuweisen? Vielen Dank!



  • @C-Sepp sagte in Zeiger und Vektoren:

    Darin steht, dass der ++-Operator einen
    höheren Vorrang als der Verweisoperator * hat, weshalb *pv++ mit *(pv++) äquivalent ist.

    Das bedeutet, dass du den Pointer nach dem Zugriff auf *p erhöhst.

    (*pv)++ inkrementiert den Wert, auf den p zeigt. Du bekommst aber noch den Wert vor dem inkrement.



  • Okay...ich hätte erwartet, dass die Operation, welche einen höheren Vorrang hat, in Klammern gesetzt wird und
    auch zuwerst ausgeführt wird. Irgendwie ein bisschen unlogisch



  • @C-Sepp sagte in Zeiger und Vektoren:

    und
    auch zuwerst ausgeführt wird.

    Du bekommst trotzdem den Pointer von vor dem Inkrement. Du denkst an *(++p)



  • Hallo Leute,

    ich habe ein weiteres interssantes Codebeispiel gefunden , in dem sich eine Frage ergeben hat:

    char arr[] = "open sea";

    char* p = arr, * q = arr + 4;
    
    cout << q - p << endl;
    cout << *q << endl;
    
    p = ++q;
    while (p < q + 3)
        cout << *p++ << endl;
    
    cout << *q << endl;
    cout << *arr << endl;
    cout << *(q - 2) << endl;
    cout << *q << endl; 
    

    Ausgabe:
    4

    s
    e
    s
    o
    n
    s

    Ich verstehen was das Programm gemacht hat, um auf dieses Ergebnis zu kommen. Jedoch verstehe
    ich nicht, warum der Zeiger *q ab der While-Schleife auf das "s" im Array zeigt. Müsste er nicht auf
    das Leerzeichen zwischen open und sea zeigen? Der zweite Ausgabewert ist ja ein Leerziechen.
    Nochmals vielen Dank!



  • Entschuldige die Ausgabe ist:

    4

    s
    e
    a
    s
    o
    n
    s


  • Mod

    Bei p = ++q wird q nebenher um 1 erhöht. Vorher stand q auf dem Leerzeichen, wie du mit der zweiten Ausgabe gesehen hast, danach eben eins weiter auf dem 's'.



  • Ahh okay...also wird mit p=++q auch q gleichzeitig um 1 erhöht. Vielen Dank!



  • Es wird zuerst q erhöht, und dieses Resultat, nach der Erhöhung, wird dann p zugewiesen.
    Anders wäre es bei:

    p = q++;
    

    Hier bekommt p den Wert von q, danach wird q inkrementiert.
    Nach:

    p = ++q;
    

    haben also p und q denselben Wert, nach:

    p = q++;
    

    nicht.



  • ++q heißt Preinkrement, weil q erst erhöht wird und dann mit dem Wert gearbeitet wird.

    q++ heißt Postinkrement, weil der Wert zuerst von q genommen wird und danach der Wert erhöht wird.

    Das passiert aber auch nicht unbedingt unmittelbar nachdem der Wert genommen wurde.

    p = q++ + q++; ist z.B. undefiniertes Verhalten.


Anmelden zum Antworten