Anfänger Problem - Zeiger



  • MSDN schrieb:

    nullptr is only valid when compiling with /clr (Common Language Runtime Compilation).

    Ich behaupte mal jetzt nicht NULL ist 0, dafür bekomme ich bestimmt
    einen auf den deckel.

    Aber ich vermute mal, dass es mir eigentlich völlig schnuppe sein kann,...
    ..gerade weil alle zeiger auf dem gleichen system die gleiche breite haben....

    //bei der gleichen addressbreite wird beides gleich behandelt
    #define NULL 0
    __int64 *pi64=NULL;
    __int32 *pi32=NULL;
    
    __int64 *pi64_2=0;
    __int32 *pi32_2=0;
    
    //hier dann nicht mehr, aber die interpretation von null über den 
    //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt
    __int64 i64=NULL;
    __int32 i32=NULL;
    
    __int64 i64_2=0;
    __int32 i32_2=0;
    

    das kann man hier schon sehen:

    //bei der gleichen addressbreite wird beides gleich behandelt
    #define NULL 0
    __int64 *pi64=NULL;
    0041158D  mov         dword ptr [ebp-14h],0 
    __int32 *pi32=NULL;
    00411594  mov         dword ptr [ebp-20h],0 
    
    __int64 *pi64_2=0;
    0041159B  mov         dword ptr [ebp-2Ch],0 
    __int32 *pi32_2=0;
    004115A2  mov         dword ptr [ebp-38h],0 
    
    //hier dann nicht mehr, aber die interpretation von null über den 
    //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt
    __int64 i64=NULL;
    004115A9  mov         dword ptr [ebp-48h],0 
    004115B0  mov         dword ptr [ebp-44h],0 
    __int32 i32=NULL;
    004115B7  mov         dword ptr [ebp-54h],0 
    
    __int64 i64_2=0;
    004115BE  mov         dword ptr [ebp-64h],0 
    004115C5  mov         dword ptr [ebp-60h],0 
    __int32 i32_2=0;
    004115CC  mov         dword ptr [ebp-70h],0
    

    grüüüße



    1. nullptr ist ein Schlüsselwort in C++0x und hat genau den Zweck, kann aber keinem int, char, etc zugewiesen werden, ist also nicht castbar nach nicht-pointer Typen.
      Beispiel:
    void f(int);
    void f(int*);
    
    int main()
    {
    	f(nullptr); // OK
    	f(0);       // Welche Funktion aufrufen?
    	f(NULL);    // - || -
    }
    
    1. NULL ist unleserlich.


  • Hi Pi E+014,

    A) nutzt man einen MSVC Compiler, so ist nullptr nur mit dem flag /clr verfügbar
    (Ich progge nativ...)

    😎 0 wird in deinem beispiel als ein int interpretiert, und nicht als 0 zeiger

    C)
    nullptr heißt " null pointer" , also "nullptr indicates that an object handle,
    interior pointer, or native pointer type does not point to an object"
    und damit wird foo(int)* aufgerufen, ein äquivalent zu foo((int)0)*.

    Dadurch wird n bisschen was erleichtert und nullptr ist ja denn auch gehighlighted.
    Da gebe ich Dir recht.

    D) naja,.. das NULL unleserlich ist... 🙄

    grüüüße



  • zeusosc schrieb:

    😎 0 wird in deinem beispiel als ein int interpretiert, und nicht als 0 zeiger

    Das Beispiel war falsch, sorry.
    Richtig:

    void f(long);
    void f(int*);
    
    ...
    
    f(NULL);
    f(0);
    f(nullptr);
    

    zeusosc schrieb:

    C)
    nullptr heißt " null pointer" , also "nullptr indicates that an object handle,
    interior pointer, or native pointer type does not point to an object"
    und damit wird foo(int)* aufgerufen, ein äquivalent zu foo((int)0)*.

    Habe nie was anderes behauptet.

    zeusosc schrieb:

    D) naja,.. das NULL unleserlich ist... 🙄

    Wie ich schon irgendwo geschrieben hab, NULL ist aus C und bleibt am besten dort.



  • 314159265358979 schrieb:

    Das Beispiel war falsch, sorry.
    Richtig:

    void f(long);
    void f(int*);
    
    ...
    
    f(NULL);
    f(0);
    f(nullptr);
    

    Jo gutes beispiel.

    grüüüüße 😃



  • 314159265358979 schrieb:

    1. NULL ist unleserlich.

    So ein Quatsch. NULL ist für Zeiger natürlich leserlicher als 0.


  • Mod

    _matze schrieb:

    314159265358979 schrieb:

    1. NULL ist unleserlich.

    So ein Quatsch. NULL ist für Zeiger natürlich leserlicher als 0.

    NULL muss vor allem nicht 0 sein und das ist in C++ ein wichtiger Unterschied. Deshalb sollte man 0 nehmen, wenn man 0 meint.



  • shwN schrieb:

    Hey...
    ich bin noch ein Anfänger und hoffe ihr könnt mir helfen.
    Ich habe eine einfache Kundenklasse. Der Vor und Nachname müssen leider Chararrays sein (Aufgabe) und dann noch eine Kundennummer.
    ...

    // KUNDE.CPP
    Kunde::Kunde(char *vname, char *nname, int knr)
    {
    	setVorname(vname);
    	setNachname(nname);
    	setKundennummer(knr);
    }
    
    Kunde::Kunde(const Kunde &k)
    {
    	kundennummer = k.kundennummer;
    	setVorname(k.vorname);
    	setNachname(k.nachname);
    }
    
    Kunde::~Kunde()
    {
    	cout << "Destruktor -- Kunde wird entfernt." << endl;
    	delete [] vorname;
    	vorname = NULL;
    	delete [] nachname;
    	nachname = NULL;
    	nachname = 0;
    	kundennummer = 0;
    }
    
    void Kunde::setKundennummer(int knr)
    {
    	kundennummer = knr;
    }
    
    void Kunde::setVorname(char *vname)
    {
    	if( vname != NULL )
    	{
    		if( vorname != NULL )
    		{
    			delete [] vorname;
    			vorname = NULL;
    		}
    		vorname = new char[strlen(vname)+1];
    		strcpy(vorname, vname);
    	}
    }
    
    void Kunde::setNachname(char *nname)
    {
    	if( nname != NULL )
    	{
    		if( nachname != NULL )
    		{
    			delete [] nachname;
    			nachname = NULL;
    		}
    		nachname = new char[strlen(nname)+1];
    		strcpy(nachname, nname);
    	}
    }
    
    void Kunde::print()
    {
    	if( vorname != NULL  &&  nachname != NULL )
    	{
    		cout << "Kundeninformationen: " << endl;
    		cout << "Vorname: " << vorname << endl;
    		cout << "Nachname: " << nachname << endl;
    		cout << "Kundennummer: " << kundennummer << endl;
    	}
    	else
    	{
    		cout << "Kundendaten ungueltig!" << endl;
    	}
    }
    
    // KUNDE.H
    class Kunde
    {
    
    	public:
    		Kunde() : kundennummer(0), vorname(NULL), nachname(NULL) {};
    		Kunde(char *vname, char *nname, int knr);
    		Kunde(const Kunde &k);
    		~Kunde();
    		void setKundennummer(int knr);
    		void setVorname(char *vname);
    		void setNachname(char *nname);
    
    		void print();
    
    	private:
    		unsigned int kundennummer;
    		char *vorname;
    		char *nachname;
    
    };
    

    Bist Du Dir sicher, dass die Klasse so aussehen soll? Ich kann's nämlich nicht ganz glauben. Die einzige Erklärung, es so zu machen, wäre höchstens zu Lehrzwecken als Negativbeispiel ... mit dem Ziel der Wertschätzung von std::string. Wenn nämlich char* sich nicht so verhält, wie Du es gerne hättest, dann macht es mehr Sinn einen eigenen Typen für diese Datenelemente zu konstruieren (std::string) statt die Kopiersemantik in der Klasse Kunde anzupassen.

    Steht in der Aufgabenstellung nur "char Array" oder auch was davon, dass Du Zeiger speichern sollst und den Speicher dynamisch allozieren sollst? Alternativ könnte man nämlich Arrays mit fixer Länge als Datenelemente verwenden. Das ist zumindest ein populärer Ansatz; denn so (mit char*) musst Du Deiner Klasse entsprechende Operationen selbst definieren (den Zuweisungsoperator hast Du übrigens vergessen).

    kk



  • zeusosc schrieb:

    ..gerade weil alle zeiger auf dem gleichen system die gleiche breite haben....

    Eine solche Garantie macht der C++ Standard nicht, auch nicht, wenn man sich auf "Objekt-Zeiger" beschränkt und Member-Pointer sowie Funktionszeiger außen vor lässt. Es soll Maschinen geben, bei denen 1=sizeof(int*)<sizeof(char*) gilt.

    zeusosc schrieb:

    //bei der gleichen addressbreite wird beides gleich behandelt
    #define NULL 0
    __int64 *pi64=NULL;
    __int32 *pi32=NULL;
    
    __int64 *pi64_2=0;
    __int32 *pi32_2=0;
    
    //hier dann nicht mehr, aber die interpretation von null über den 
    //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt
    __int64 i64=NULL;
    __int32 i32=NULL;
    
    __int64 i64_2=0;
    __int32 i32_2=0;
    

    🙄
    btw: Hier gibt es keine Zuweisungen. Das sind Initialisierungen. Der Unterschied: Bei einer Zuweisung gibt es das Ziel-Objekt schon vorher.

    zeusosc schrieb:

    das kann man hier schon sehen:

    ...
    

    Ich verstehe nicht Deine Obsession bzgl Implementierungsdetails des Compilers von Microsoft.

    kk



  • Ok,... heute ist Samstag,.. heute ist Senftag 😃

    krümelkacker schrieb:

    zeusosc schrieb:

    ..gerade weil alle zeiger auf dem gleichen system die gleiche breite haben....

    Eine solche Garantie macht der C++ Standard nicht, auch nicht, wenn man sich
    auf "Objekt-Zeiger" beschränkt und Member-Pointer sowie Funktionszeiger außen
    vor lässt. Es soll Maschinen geben, bei denen 1=sizeof(int*)<sizeof(char*) gilt.

    Echt? Das garantiert mir vlt. nicht die ISO, aber es garantiert mir die
    architektur die ich mit meinen source versorge.
    Auf einem 32bit system der x86 architektur ist die addresse immer 32bit breit,
    wohingegen 8bit systeme der RISC architektur auch 16bit breite addressen
    unterstützen (müssen) da der stack oft größer als 256 Byte Ram ist,
    aber selbst dort ist jeder 16bit offset ptr als low und high fragment nur
    jeweils 8bit groß.

    krümelkacker schrieb:

    btw: Hier gibt es keine Zuweisungen. Das sind Initialisierungen. Der Unterschied: Bei einer Zuweisung gibt es das Ziel-Objekt schon vorher.

    Ja, das object existiert ja auch schon vorher.

    double a(1.0f);
    double b=1.0f;
    double c;
    c=1.0f;
    

    sind 100% äquivalent.

    Das liegt an der interpretation der objekt construction.
    Für den Compiler sind das alles Copy-Ctor's, erst Object initialisieren,
    dann zuweisen! Und bei der zuweisung interpretiert, wie oben gesagt,
    der Compiler den RVALUE als zieltypen.
    (Insofern eine passende zuweisungsregel vorliegt).

    (willste den asm ausdruck sehen???? Das macht gcc und msvc so)

    --------------------------

    krümelkacker schrieb:

    Ich verstehe nicht Deine Obsession bzgl Implementierungsdetails des Compilers von Microsoft.

    Hehe, jeder hat doch seine macken, nicht? 🙂

    Nein mal ehrlich: Wenn ich weiß, wie der Compiler, in meinem fall ist es halt
    MSVC (Mit gcc habe ich aber auch schon gearbeitet, für µC's jedenfalls),
    meine routinen, zuweisungen, callconventions, implementiert, weiß ich
    was ich wie verwenden darf, damit das gemacht wird was ich will.

    Also den umgang mit ptr's, egal ob es ein offset für eine function /member ist,
    ob es ein offset für einen weiteren ptr ist usw, habe ich nicht in TP,VB,C/C++
    gelernt, sondern in asm.

    Also bitte ich um verständniss und um rücksicht wenn ich mir (und vlt auch euch)
    klar machen will, was der compiler vor dem assembler eigentlich macht.
    ------------------

    Seid alle gegrüßt und nicht ärgern lassen 🙂


Anmelden zum Antworten