anfänger hat probleme mit globalen variablen



  • Trantüte schrieb:

    eins.putadresse();
    

    die wahrsagekugel sagt, dass der fehler wahrscheinlich in dieser funktion liegt.
    ohne weiteren code ist weitere hilfe unmöglich.



  • also an alle die sich wegen:

    eins.putadresse(); beschwert haben, dass ich hab ich natürölich mit auskommentiert. 🙂

    zweitens es kommt keine fehlermeldung beim compilieren er compiliert alles ohne warnungen oder errors. nur beim aufruf der exe datei kommt von windows so ein fenster und zwar dreimal nach einander. in dem fenster steht adresse.exe hat ein problem festgestell und mus beendet werden. und das ganze drei mal 🙂

    so hier nochmal der code von allen dzugehörigen dateien:

    haeder datei adresse.h
    
    #ifndef _adresse_
    #define _adresse_
    
    #include <string.h>
    
    class adresse
    {
    private:
    	char stadt[20];
    	char strasse[25];
    	char telefon[15];
    public:
    	adresse(const char *stadt="xxxxxx",const char *strasse="xxxxxx", const char *telefon="000000");
    	~adresse();
    	void setadresse(const char *,const char *,const char *);
    	void putadresse();
    };
    
    inline void strcpy(char *s1,const char *s2,int n)
    {
    	strncpy(s1,s2,n);
    	s1[n]='\0';
    }
    
    #endif
    
    hier die zweite:
    
    #include "adresse.h"
    #include <iostream>
    using namespace std;
    
    int anzahl=0;
    
    adresse::adresse(const char *stadt,const char *strasse,const char *telefon)
    {
    	setadresse(stadt,strasse,telefon);
    	++anzahl;
    
    	cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " erschaffen!\n";
    	cout << "Das war das " << anzahl << ". Objekt!\n";
    }
    
    adresse::~adresse()
    {
    	--anzahl;
    	cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " zerstoert!\n";
    	cout << "Es verbleiben noch " << anzahl << " Objekte!\n";
    }
    
    void adresse::setadresse(const char *city,const char *street,const char *nummer)
    {
    	strcpy(stadt,city,sizeof(stadt)-1);
    	strcpy(strasse,street,sizeof(strasse)-1);
    	strcpy(telefon,nummer,sizeof(telefon)-1);
    }
    
    void adresse::putadresse()
    {
    	cout << "Strasse:\t" << stadt << endl;
    	cout << "Stadt:  \t" << strasse << endl;
    	cout << "Telefon:\t" << telefon << endl;
    
    	cin.get();
    }
    
    und hier die dritte:
    
    #include "adresse.h"
    #include <iostream>
    using namespace std;
    
    void func ();
    
    //adresse eins("Rostock","Rosenweg 12","0170/1964619");
    
    int main ()
    {
    	//eins.putadresse();
    
    	adresse a;
    	a.putadresse();
    	a.setadresse("13055 Berlin","Arendsweg 13","030/9821609");
    	a.putadresse();
    
    	cout << "Es folgt der erste Aufruf der Funktion func()\n\n";
    
    	func();
    
    	cout << "Es folgt der zweite Aufruf der Funktion func()\n\n";
    
    	func();
    
    	return 0;
    }
    
    void func()
    {
    	static adresse spez1("09471 Baerenstein","Rosenweg 12","037347/84973");
    	spez1.putadresse();
    
    	adresse funktion("16792 Zehdenick","Falterstrasse 17","03307/302589");
    	funktion.putadresse();
    
    	cout << "\nVor dem Ende der Funktion!\n\n";
    }
    

    mal sehen ob ihr mir jetzt licht ins dunkel bringen könnt 😉

    mfg david



  • du kopierst immer sizeof(stadt), sizeof(strasse) und sizeof(telefon) viele chars aus den übergebenen strings in die arrays. was ist aber, wenn der string, den du übergibst, nicht so viele chars enthält? dann wird grober unsinn mitkopiert bzw. kann es dir passieren, sachen mitzukopieren, die deinem programm eigentlich gar nicht gehören. das ging vielleicht früher, aber heutzutage lässt das kaum ein betriebssystem mehr zu. was ist übrigens, wenn jemand in Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch wohnt? (eine stadt in wales)
    also, du kannst bei dem design bleiben und mit strlen arbeiten

    strcpy(stadt,city,strlen(city));
    strcpy(strasse,street,strlen(street));
    strcpy(telefon,nummer,strlen(nummer));
    

    btw würde ich die funktion nicht unbedingt strcpy nennen, da es schon ein strcpy gibt.
    oder du könntest natürlich auch auf die c++ strings umsteigen.

    was mir noch auf die schnelle auffällt, ist, dass der header nicht string.h sondern cstring heißt, und dass du die präprozessordirektiven

    #ifndef _adresse_
    #define _adresse_
    

    nicht mit einem underscore beginnen solltest. (diese namen sind nämlich für compilerhersteller reserviert)



  • Du sag mal programmierst du C oder C++? Für mich sieht das mal stark nach C aus...



  • 💡 er verwendet iostream, namespaces und klassen.



  • hmmm bis jetzt hat mir immer noch keiner meine Frage beantwortet 😞

    aber ich hoffe noch.

    mfg david



  • Trantüte schrieb:

    class adresse
    {
    private:
    	char stadt[20];
    	char strasse[25];
    	char telefon[15];
    [...]
    };
    
    adresse::adresse(const char *stadt,const char *strasse,const char *telefon)
    {
    	setadresse(stadt,strasse,telefon);
    	++anzahl;
    
    	cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " erschaffen!\n";
    	cout << "Das war das " << anzahl << ". Objekt!\n";
    }
    

    Btw wie unterscheidet der Compiler jetzt zwischen den Parameterbezeichnern des Konstruktors und den Membervariablenbezeichnern der Klasse adresse? Greift er sich da nicht die Membervariablen der Klasse?

    Hmm, ich schlage dir sowieso vor eine Initialisierungliste zu benutzen, das spart den Aufruf vom Default-Konstruktor. 🙂



  • Trantüte schrieb:

    hmmm bis jetzt hat mir immer noch keiner meine Frage beantwortet 😞

    davie schrieb:

    du kopierst immer sizeof(stadt), sizeof(strasse) und sizeof(telefon) viele chars aus den übergebenen strings in die arrays. was ist aber, wenn der string, den du übergibst, nicht so viele chars enthält? dann wird grober unsinn mitkopiert bzw. kann es dir passieren, sachen mitzukopieren, die deinem programm eigentlich gar nicht gehören. das ging vielleicht früher, aber heutzutage lässt das kaum ein betriebssystem mehr zu.

    kurz gesagt ersetze sizeof(stadt) durch strlen(city) [gegebenenfalls überprüfe, ob strlen(city) kleiner als sizeof(stadt) ist]
    oder besser noch: verwende std::string.

    ... schrieb:

    Btw wie unterscheidet der Compiler jetzt zwischen den Parameterbezeichnern des Konstruktors und den Membervariablenbezeichnern der Klasse adresse? Greift er sich da nicht die Membervariablen der Klasse?

    nein. er greift zu den parametern. auf die member kann man via this-> zugreifen.

    ... schrieb:

    Hmm, ich schlage dir sowieso vor eine Initialisierungliste zu benutzen, das spart den Aufruf vom Default-Konstruktor. 🙂

    vielleicht stehe ich auf der leitung: was meinst du?



  • davie schrieb:

    nein. er greift zu den parametern. auf die member kann man via this-> zugreifen.

    Ich wusste es eben nicht mehr aus dem Kopf, weil der this-Zeiger kann ja auch weggelassen werden um auf eine Membervariable zuzugreifen. Aber ich habe es nochmals ausprobiert, es wird tatsächlich auf die Parameter zugegriffen. Trotzdem würde ich Membervariablen mit dem Präfix m_* benennen, das spart die Verwirrung immens.

    davie schrieb:

    vielleicht stehe ich auf der leitung: was meinst du?

    Mit Initialisierungsliste meine ich das hier:

    class A
    {
    public:
        A(int __a) 
        : a(__a) // Initialisierungsliste
        { }
    private:
        int a;
    };
    


  • HI

    adresse(const char *stadt="xxxxxx",const char *strasse="xxxxxx", const char *telefon="000000");
    

    Zum guten programmier stiel gehört auch dazu das man möglichst wenig default werte nimmt, und in diesem fall sind sie sogar absolut unnötig

    mfg spjoe



  • davie schrieb:

    ... schrieb:

    Btw wie unterscheidet der Compiler jetzt zwischen den Parameterbezeichnern des Konstruktors und den Membervariablenbezeichnern der Klasse adresse? Greift er sich da nicht die Membervariablen der Klasse?

    nein. er greift zu den parametern. auf die member kann man via this-> zugreifen.

    Oder man verwendet eine spezielle Bezeichnung für Member Variablen. Das altbekannte Präfix m_ ist zB eine Möglichkeit, einige Programmierer (zB auch meiner einer) verwenden mittlerweile Postfix _.



  • Jop, das geht natürlich auch. Man kanns auch als Präfix anwenden, aber lesbarer ist es natürlich als Suffix, weil der Name besser hervorgeht. Es gibt auch noch mehr sinnvolle Möglichkeiten, aber egal welche man anwendet, die Lesbarkeit wird dadurch immens gesteigert. 😉



  • @davie

    hmm also mit strlen funktioniert es nicht mal ohne globale objekte. da ich noch anfänger bin mach ich vielleicht auch irgendwas anderes falsch. vielleicht kannst du mir mal die entsprechenden passagen umschreiben und posten :).

    mfg david



  • einmal mit c-strings

    //Nummer 1
    #ifndef Adresse_h  
    #define Adresse_h
    
    //Nummer 2
    /*#include <cstring>*/
    
    class adresse
    {
    private:
        char stadt[20];
        char strasse[25];
        char telefon[15];
    public:
        adresse(const char *stadt="xxxxxx",const char *strasse="xxxxxx", const char *telefon="000000");
        ~adresse();
        void setadresse(const char *,const char *,const char *);
        void putadresse();
    };
    
    #endif
    
    #include "adresse.h"
    #include <iostream>
    //Nummer 3
    #include <cstring>
    using namespace std;
    
    //Nummer 4
    namespace
    {
       int anzahl=0; //oder lieber in die klasse rein?
    }
    
    adresse::adresse(const char *stadt,const char *strasse,const char *telefon)
    {
        setadresse(stadt,strasse,telefon);
        ++anzahl;
    
        cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " erschaffen!\n";
        cout << "Das war das " << anzahl << ". Objekt!\n";
    }
    
    adresse::~adresse()
    {
        --anzahl;
        cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " zerstoert!\n";
        cout << "Es verbleiben noch " << anzahl << " Objekte!\n";
    }
    
    void adresse::setadresse(const char *city,const char *street,const char *nummer)
    {
        strncpy(stadt,city, strlen(city)+1);
        strncpy(strasse,street, strlen(street)+1);
        strncpy(telefon,nummer,strlen(nummer)+1);
    }
    
    void adresse::putadresse()
    {
        cout << "Strasse:\t" << stadt << '\n';
        cout << "Stadt:  \t" << strasse << '\n';
        cout << "Telefon:\t" << telefon << '\n';
    
        cin.get();
    }
    
    #include "adresse.h"
    #include <iostream>
    using namespace std;
    
    void func ();
    
    adresse eins("Rostock","Rosenweg 12","0170/1964619");
    
    int main ()
    {
        eins.putadresse();
    
        adresse a;
        a.putadresse();
        a.setadresse("13055 Berlin","Arendsweg 13","030/9821609");
        a.putadresse();
    
        cout << "Es folgt der erste Aufruf der Funktion func()\n\n";
    
        func();
    
        cout << "Es folgt der zweite Aufruf der Funktion func()\n\n";
    
        func();
    
        //Nummer 5
        //return 0;
    }
    
    void func()
    {
        static adresse spez1("09471 Baerenstein","Rosenweg 12","037347/84973");
        spez1.putadresse();
    
        adresse funktion("16792 Zehdenick","Falterstrasse 17","03307/302589");
        funktion.putadresse();
    
        cout << "\nVor dem Ende der Funktion!\n\n";
    }
    

    vielleicht auch mit

    void adresse::setadresse(const char *city,const char *street,const char *nummer)
    {
        strcpy(stadt,city);
        strcpy(strasse,street);
        strcpy(telefon,nummer);
    }
    

    und mit std::strings

    //Nummer 1
    #ifndef Adresse_h  
    #define Adresse_h
    
    //Nummer 2
    #include <string>
    
    class adresse
    {
    private:
        //Nummer 3
        std::string stadt;
        std::string strasse;
        std::string telefon;
    public:
        //Nummer 4
        adresse(std::string const& stadt="", std::string const& strasse="", std::string const& telefon="");
        ~adresse();
        //Nummer 5
        void setadresse(std::string const&, std::string const&, std::string const&);
        void putadresse();
    };
    
    #endif
    
    #include "adresse.h"
    #include <iostream>
    using namespace std;
    
    //Nummer 6
    namespace {
       int anzahl=0; //oder lieber in die klasse rein?
    }
    
    //Nummer 7
    adresse::adresse(string const& stadt, string const& strasse, string const& telefon)
     : stadt(stadt), strasse(strasse), telefon(telefon)
    {
        ++anzahl;
        cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " erschaffen!\n";
        cout << "Das war das " << anzahl << ". Objekt!\n";
    }
    
    adresse::~adresse()
    {
        --anzahl;
        cout << "\nEs wurde das Objekt fuer die Stadt " << stadt << " zerstoert!\n";
        cout << "Es verbleiben noch " << anzahl << " Objekte!\n";
    }
    
    //Nummer 8
    void adresse::setadresse(string const& city, string const& street, string const& nummer)
    {
       stadt=city;
       strasse=street;
       telefon=nummer;
    }
    
    void adresse::putadresse()
    {
        cout << "Strasse:\t" << stadt << '\n';
        cout << "Stadt:  \t" << strasse << '\n';
        cout << "Telefon:\t" << telefon << '\n';
    
        cin.get();
    }
    
    #include "adresse.h"
    #include <iostream>
    using namespace std;
    
    void func ();
    
    adresse eins("Rostock","Rosenweg 12","0170/1964619");
    
    int main ()
    {
        eins.putadresse();
    
        adresse a;
        a.putadresse();
        a.setadresse("13055 Berlin","Arendsweg 13","030/9821609");
        a.putadresse();
    
        cout << "Es folgt der erste Aufruf der Funktion func()\n\n";
    
        func();
    
        cout << "Es folgt der zweite Aufruf der Funktion func()\n\n";
    
        func();
    
        //Nummer 9
        //return 0;
    }
    
    void func()
    {
        static adresse spez1("09471 Baerenstein","Rosenweg 12","037347/84973");
        spez1.putadresse();
    
        adresse funktion("16792 Zehdenick","Falterstrasse 17","03307/302589");
        funktion.putadresse();
    
        cout << "\nVor dem Ende der Funktion!\n\n";
    }
    

    müsste alles funktionieren, wenn keine tippfehler drin sind.



  • ... schrieb:

    Mit Initialisierungsliste meine ich das hier:

    was eine initialisierungsliste ist, weiß ich. trotzdem fehlt doch irgendwie der bezug?



  • @davie

    erst mal danke für die mühe 🙂 habe beide versionen ausprobiert funktionieren beide genauso wie die ursprüngliche. sobald ich aber das globale objekt eins der klasse adresse initializiere passiert dasselbe drei mal das am anfang beschriebene fenster keine ausführung des programms. compilieren tut ers ohne fehler oder warnungen.

    irgendwas mit globalen objekten klappt nicht. aber was? bei normalen globalen variablen wie anzahl gibt es keine probleme.

    wieso hast du die variable anzahl in namespace verpackt? was ist der efekt oder sinn?

    was ist in <string> definiert?

    das return in der main hast du einfach so auskommentiert gibts da keine probleme oder was ist davon der sinn das mann es nicht schreibt?

    mfg david



  • hmmm weiß keiner eine antwort?

    mfg david



  • hmmm

    es muss doch irgendjemand eine antwort für dieses problem haben?

    oder ist euch der beitrag schon zu lang, dann post ich ihn nochmal neu?

    mfg david



  • Hast du schon mal daran gedacht, den Debugger zu verwenden, um zu sehen wo es Probleme gibt?



  • ich hab leider kein debugger 🤡 aber ich schätze mal das wird nichts bringen weil der compiler es ohne probleme kompiliert.

    nur beim start der exe datei kommt eine fehlermeldung von windows und die muss ich drei mal wegdrücken wie schon mehrmals erwähnt.

    zum thema debugger kannt du mir einen empfehlen un dgibt es sowas eventuell kostnlos?

    mfg david


Anmelden zum Antworten