Zeiger und Vektoren



  • 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.



  • Okay....wieder was dazugelernt.
    Mit den Wissen der letzten Beiträge habe ich mir jetzt eine Funktion geschrieben, die aus 2 übergebenen Arrays
    gleicher Länge n ein drittes Array erstellen/mischen soll. Der Mischvorgang läuft so ab, dass die Werte
    beider Arrays an gleicher Position miteinander verglichen werden, und immer der kleinste Wert in das dritte neu erstellte Array geschrieben wird:

    int merge(int arr1[], int arr2[], int n, int arr3[])
    {
        int* ptr1 = &arr1[0];   //bzw. int *ptr1= arr1;
        int* ptr2 = &arr2[0]; 
        int i=0;
        int i1 = 0;
        
    
        for (ptr1=arr1, ptr2=arr2; ptr1<arr1+n ; ptr1++, ptr2++)
        {       
            if (*ptr1<*ptr2)
                arr3[i1] = *ptr1;
            else
                arr3[i1] = *ptr2;
            i1 = i1 + 1;
            cout << i1 << endl;
            cout << *ptr1 << endl;
            cout << *ptr2 << endl;
        }   
    
        i= sizeof(arr3) / sizeof(int);
    
        return i;
    }
    
    int main()
    {
        int arr1[5] = { 27, 33, 39, 45, 51 };
        int arr2[5] = { 22, 30, 42, 48, 54 };   
    
        merge(arr1, arr1, 5, arr3);
    }
    
    

    Das Durchiterieren funktioniert, allerdings steht in beiden Zeiger bei jeden Durchlauf immer der gleiche Wert, d.h 27, 33,
    39 usw. Komischerweise enthält dass Array auch nur ein Element obwohl i bis zur 5 hochgezählt wird. Was mache ich
    verkehrt? Vielen Dank!


Anmelden zum Antworten