Zeiger und Vektoren



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



  • @C-Sepp sagte in Zeiger und Vektoren:

    int* ptr1 = &arr1[0];   //bzw. int *ptr1= arr1;
    int* ptr2 = &arr2[0];
    

    arr1, arr2, arr3 sind Zeiger, da sie als Parameter der Funktion definiert sind.
    Egal ob du das mit [] oder * schreibst.

    Darum kannst du innerhalb der Funktion die Größe des übergebenen Arrays auch nicht mehr herleiten.

    Warum sollte i einen anderen Wert als n haben?

    Wo kommt in der main arr3 her?
    Du musst schon ein ausreichend großes Array übergeben.
    Das wird nicht so einfach dynamisch erzeugt oder erwitert,

    Noch was:
    Der Compiler wandelt selber erstmal a[i] in *(a+i) um. Da ist kein Unterschied in der Behandlung.

    In C steht das Rückgabearray i.A. an erster Stelle optisch der Paramter.
    Damt soll sowas wie arr3 = merge(arr1,arr2) optisch erzeugt werden.



  • Okay...habe in der Main jetzt mal ein 5-Elemente großes Array an die Funktion übergeben. Trotzdem enthält das
    Array arr3 nach den 5 Durchläufen nur 1 Element??
    i sollte selbstverständlich gleich n sein, weshalb das sizeof rausgenommen werden kann.
    Warum die beiden Zeigen ptr1 und ptr2 immer den gleichen Wert haben ist mir nach wie vor nicht klar. Es werden die Anfangsadressen des jeweiligen Arrays zugewiesen und dann schrittweise durchiteriert. Arr1, arr2 und arr3 sind Zeiger wie
    du schon gesagt hast, aber nicht weil sie als Parameter der Funktion definiert sind!



  • @C-Sepp sagte in Zeiger und Vektoren:

    Warum die beiden Zeigen ptr1 und ptr2 immer den gleichen Wert haben ist mir nach wie vor nicht klar.

    Dann schau dir mal deinen Aufruf von merge in der main ganz genau an.
    Zeichen für Zeichen

    @C-Sepp sagte in Zeiger und Vektoren:

    Arr1, arr2 und arr3 sind Zeiger wie
    du schon gesagt hast, aber nicht weil sie als Parameter der Funktion definiert sind!

    Wir reden hier schon von arr1 bis arr3 in merge?



  • Stimmt, da ist noch ein Fehler. Der Aufruf enthielt nur arr1. Damit hat es funktioniert. Allerdings wurde das dritte Array
    in der Funktion nach wie vor nur mit einen Element befüllt.
    Ja die drei Arrays meinte ich. Jeder Parameter ist ja nicht automatisch ein Zeiger.



  • @C-Sepp sagte in Zeiger und Vektoren:

    Allerdings wurde das dritte Array
    in der Funktion nach wie vor nur mit einen Element befüllt.

    Woran erkennst du das?
    Ändert sich die Ausgabe von i1 in der Funktion.

    Ja die drei Arrays meinte ich. Jeder Parameter ist ja nicht automatisch ein Zeiger.

    Das nicht, aber ich hatte die Aussage noch eingeschränkt.



  • @C-Sepp sagte in Zeiger und Vektoren:

    Allerdings wurde das dritte Array in der Funktion nach wie vor nur mit einen Element befüllt.

    Wie hast du denn arr3 (für den Aufruf in main) definiert?

    PS: sizeof(arr3) / sizeof(int) innerhalb der Funktion merge ergibt immer einen konstanten Wert (denn arr3 wird hier, da als Zeiger übergeben, immer als int* ausgewertet, z.B. also bei 32bit-Zeiger: 4 / 4 = 1 oder bei 64bit-Zeiger: 8 / 4 = 2 - bei üblichen 32bit int).

    Edited...



  • @Th69 sagte in Zeiger und Vektoren:

    8 / 4 = 1

    Hm... Wenn 4 / 4 = 1 ist, dann ist 8 / 4 = ?
    Die Grundschulmathematik wollen wir doch nochmal üben 😉



  • @wob sagte in Zeiger und Vektoren:

    Hm... Wenn 4 / 4 = 1 ist, dann ist 8 / 4 = ?

    1 Rest 4 ??



  • Die Ausgabe von i ändert sich. Ich habe das Array3 vor Übergabe an die Funktion mit: int arr3[5]; definiert.
    Damit hat es funktioniert, wie ich bei einer weiteren Ausgabe des Arrays3 in Merge gesehen habe. Bin die Funktion
    zuvor immer im Schrittbetrieb durchgegangen und habe den Mauszeiger auf array3 in Merge gehalten. So habe
    ich komischerweise immer nur einen Eintrag des Arrays3 gesehen. Hätte erwartet, dass auch im Einzelschrittbetrieb mir
    alle Einträge eines Arrays angezeigt werden.



  • Du hättest das Array mit int arr3[5] = {0}; gleich initialisieren können (da werden auch nicht aufgeführte Elemente auf 0 gesetzt)
    Und in main nochmal eine Schleife mit Ausgabe zur Kontrolle.



  • Ich habe inzwischen die Übersicht verloren. Wie ist dein vollständiger Code? Wo ändert sich die Ausgabe von i? (Schrittbetrieb & Mauszeiger halten sind Dinge deiner Entwicklungsumgebung - da ists schwierig darüber zu sprechen)

    Warum machst du nicht etwas in der folgenden Art:

    int min(int a, int b) {
        if (a < b) return a;
        return b;
    }
    
    int merge(int arr1[], int arr2[], size_t n, int arr3[])
    {
        for (size_t i = 0; i < n; ++i) {
            arr3[i] = min(arr1[i], arr2[i]);
        }
    }
    


  • So geht es natürlich auch. Interessanter vom Lerneffekt fand ich trotzdem die Zeiger. Vielen Dank!



  • @C-Sepp Dann schreib statt Zeile 9
    *arr3++ = min(*arr1++, *arr2++);



  • Ich bin noch ein weiteres Codesbeispiel durchgegangen. Bei diesen wird ein string s mittels der Funktion strtok() in
    Teilzeichenfolgen zerlegt, welche durch Zeichen aus dem String delim begrenzt werden. Die Funktion lautet:
    char* strtok(char* s, const char* delim)

    Zum Lernen habe ich mir diese Funktion so in etwa mal nachprogrammiert, wobei wieder ein paar
    Fragen entstanden sind, welche wahrscheinlich trivial sind:

    char** test(char* s1, const char* s2)
    {
        s1 = "ein anderer Test"; //Fehlerconst char [17]" kann nicht in "char *" konvertiert werden
        s2 = "Test1";
        s2 = "Test2"; 
        return &delim;
    }
    
    int main()
    { 
        char s1[] = "Das ist ein Test";
        char s2[] = "Das ist ein anderer Test";
    
        test(s1,"Das ist ein anderer Test");
    }
    

    Warum kann ich den Read-Only-Zeiger s2 in der Funktion eigentlich beliebige Werte zuweisen? (Wäre dies
    ein Zeiger auf Integer wäre dies nicht möglich.)
    Warum kann ich s1 hingegen keinen Wert zuweisen? Nochmals vielen Dank!



  • Die Fehlermeldung kommt, weil ein String-Literal in C++ (also sowas in "doppelten Quotes") ein konstanter String ist. Diesen kannst du nicht verändern. (das ist auch ein Unterschied von C++ zu C, wo es auch ohne const ginge)

    Die Zuweisung an s2 funktioniert, weil bei s2 eben const dransteht. Du musst unterscheiden: ist der Zeiger konstant oder ist das, auf das der Zeiger zeigt, konstant? Mit const char * hast du einen (veränderbaren) Zeiger auf einen konstanten char. Verwechsle das nicht mit char * const (const hinter dem *) - dann wäre der Zeiger konstant, aber nicht das, auf das der Zeiger zeigt. Und mit const char * const wäre sowohl der Zeiger als auch das, auf das der Zeiger zeigt, konstant. Du kannst auch char const * bzw. char const * const schreiben, also das const und char vertauschen, was in letzter Zeit populärer geworden ist (nennt sich east const / west const).

    Du kannst hier "C Gibberish" nach Englisch übersetzen: https://cdecl.org/?q=const+char+*c

    Abgesehen davon folgendes:

    • delim ist nicht bekannt (Zeile 6)
    • wozu übergibst du überhaupt s1 und s2 als Parameter, wenn du mit s1 = ... und s2 = ... deren Werte als allererstes versuchst zu überschreiben?




  • Super...wieder etwas dazugelernt. Gut zu wissen auch, dass der Schreibschutz eines konstanten Zeigers im Gegensatz zu strings nicht unterlaufen werden kann. Sprich ich kann einen konstanten Zeiger keinen nicht konstanten Zeiger zuweisen:

    unsigned int strlen(const char *s)
    {
        ...
        char* temp = s; // Fehler
    }
    
    const string s1 ="Ein Stringstest";
    string s2 = s1;
    

    Dass der Aufruf der oben definierten Funktion test auch mit test(s1, s2) in der Main funktioniert, hängt dann wahrscheinlich konkret damit zusammen, dass s2 nach Zuweisung des Strings "Das ist ein anderer..." ein konstanter String ist?


Anmelden zum Antworten