Fehler bei Zeigern ?!



  • Hi, um mich mit den Zeigern etwas besser auseinanderzusetzen habe ich eine kleine Methode geschrieben die 2 strings vertauscht , mir ist klar das man das auch anders lösen kann.
    Wenn ich das ganze richtig verstanden habe sollte folgendes
    auch ohne probleme laufen...

    bool swap_strings(char * str1, char * str2){
    	int lenstr1 = 0;
    	int lenstr2 = 0;
    	lenstr1 = strlen(str1);
    	lenstr2 = strlen(str2);
    
    	if(lenstr1 != lenstr2)
    	{
    		return false;
    	}
    	char  tmp = '\0';
    	int i;
    	for(i = 0; i < lenstr1; i++ )
    	{
    		tmp = *(str1 + i);
    		cout << tmp << endl;
    //---	//	*(str1 + i) = *(str2 + i);
    //---	//	*(str2 + i) = tmp;
    	}
            //DEBUG
    	cout << "str 1 neu : " << str1 << endl;
    	cout << "str 2 neu : " << str2 << endl;
    	return true;
    
    }
    

    leider erhalte ich eine Exception : Status_Access_Violation
    der fehler liegt bei dem mit //--- // kommentierten code, allerdings verstehe ich nicht wo.

    *(str1 + i) entspricht dem inhalt/wert von str1[i] , es sollte also eigentlich nur eine ganz normale char vertauschung stattfinden oder ?



  • wie rufst du die funktion auf?



  • hab den fehler gefunden,
    hatte als aufruf 2 "strings" mit char * x = "...";
    angelegt und diese übergeben es muss aber wohl per char x[] = "...";
    inizialisiert werden. Wobei mir hier nicht ganz klar ist wo der unterschied liegt ?
    x ist doch auch nur ein zeiger auf x[0] ?



  • char * x = "...";

    "..." ist ein literal und somit konstant. zusätzlich legen die compiler (nicht alle) die daten in einen speicherbereich der nicht änderbar ist und dadurch nur gelesen werden kann.



  • Auch bei Arrays kannst du nicht einfach so die Strings wechseln.

    Was bei Literalen geht, ist den Zeiger zu ändern, aber nicht den Speicherbereich selbst. Dann müsstest du die Zeiger aber als Referenz oder als Zeiger übergeben. Oder direkt std::swap() verwenden. 😉



  • es ging ja darum nichts festes zu verwenden 😉

    und es funktioniert ja so wie es sollte, ich wusste nur nicht das char * x = "..."
    anders angelegt wird als char x[] = "..."

    aber danke nochmals


  • Administrator

    @tallan,
    Deshalb sollte man ein Zeiger auf ein String-Literal immer als konstant definieren, also:

    char const* p = "Hello World!";
    

    Was der Unterschied zwischen diesen zweien ist, ist dir aber nun klar?

    char const* s1 = "Hello";
    char s2[] = "Hello";
    

    (Wenn ich es nicht wüsste, wäre es mir nämlich aus dem, was im Thread geschrieben wurde, nicht klar geworden ;))

    Grüssli



  • ich hoffe das ich es verstanden habe,

    char bla[] = "xxx" alokiert speicher für 3 * char element fortlaufend ab der adresse von bla.
    bei char * bla = "xxx" wird dieser speicher u.u. in einem bereich angelegt der schreibgeschützt ist und somit sind änderungen der "werte" wie bla[i] = 'c'
    nicht möglich sondern allenfalls eine änderung der zeiger !?


  • Administrator

    tallan schrieb:

    char bla[] = "xxx" alokiert speicher für 3 * char element fortlaufend ab der adresse von bla.

    Nicht ganz.
    Grundsätzlich wird hier ein Array allokiert, welches Speicher für 4 char Elemente hat. Das 4. Element wird für die Null-Terminierung verwendet ( '\0' ). Man könnte es auch anders schreiben:

    char bla[] = { 'x', 'x', 'x', '\0' };
    

    Des Weiteren sollte man klarstelle, dass bla keine Adresse ist. bla ist ein Array-Objekt. Ein Array-Objekt lässt sich nicht kopieren, man kann allerdings ein Zeiger oder eine Referenz auf ein Array-Objekt erstellen. Dies geht so:

    char bla[] = "xxx";
    char (*p)[4] = &bla;
    char (&r)[4] = bla;
    

    Das wird dich wahrscheinlich überraschen, vor allem der Zeiger, da du eher an sowas gedacht hättest:

    char* p = bla;
    

    Tatsächlich passiert in diesem Fall eine implizite Konvertierung von dem Array-Objekt zu einem Zeiger auf das erste Element. Es ist also gleichbedeutend mit:

    char* p = &bla[0];
    

    Die implizite Konvertierung funktioniert nur bei 1-dimensionalen Arrays. Bei mehrdimensionalen Arrays empfiehlt es sich über die andere Version vorzugehen. Wenn möglich sollte man sowieso auf mehrdimensionale Arrays verzichten. Die Emulation ist meistens deutlich einfacher.

    char multiDim[4][5];
    char* p1 = multiDim; // FEHLER
    char* p2 = &multiDim[0][0]; // RICHTIG
    
    // Zeiger auf ein multi-dimensionales Array:
    char (*p3)[4][5] = multiDim;
    
    // Emulation:
    char emuMultiDim[20];
    std::size_t const rowSize = 4;
    
    emuMultiDim[rowSize * y + x];
    // Am besten natürlich in eine Klasse gekapselt
    // oder bereits existierende Konstrukte verwenden.
    

    tallan schrieb:

    bei char * bla = "xxx" wird dieser speicher u.u. in einem bereich angelegt der schreibgeschützt ist und somit sind änderungen der "werte" wie bla[i] = 'c' nicht möglich sondern allenfalls eine änderung der zeiger !?

    Was verstehst du unter Änderung der Zeiger? Meinst du das:

    char const* bla = "xxx";
    bla = "yyy";
    

    Dann ja, richtig 🙂

    Grüssli



  • Vielen Dank für die ausführliche Antwort


Log in to reply