auf strukturelemente zugreifen



  • Hallo,
    kann mir jemand sagen, wann man -> nimmt und wann nur einen . um auf eine klassen oder struktur information zuzugreifen?
    ich dachte es wäre so

    struct hans {
    int groesse;
    }
    hans peter;
    
    peter.groesse = 10; 
    
    std::cout << "Peter ist ein Hans mit der Größe" << peter.groesse << "\n";
    

    jetzt sehe ich aber in einem beispiel in einem tutorial

    time_t ZeitDatum;
    struct tm *AktuellesDatum;
    
       ZeitDatum = time(NULL);				// Systemaufruf
       AktuellesDatum = localtime(&ZeitDatum);	// Systemaufruf
       Monat = AktuellesDatum->tm_mon + 1;
       Tag = AktuellesDatum->tm_mday;
       Jahr = AktuellesDatum->tm_year + 1900;
       Format = 1;
    

    es wird ein zeiger auf eine tm struktur deklariert.
    damit ich es verstehe müsste localtime(&ZeitDatum) einen zeiger zurückgeben sodass der zeiger Aktuelles Datum vom Typ tm auf die Systemzeit(auch vom typ tm?) zeigt.

    ich würde jetzt eigentlich denkene, dass man um auf den inhalt der struktur zugreifen zu können, Aktuelles Datum erst dereferenzieren muss also so z.B.:

    Monat = *AktuellesDatum.tm_mon;
    

    (ist das + 1 nach tm_mon da, weil die Monate im System von 0 bis 11 gezählt werden?

    Viele Grüße,
    FLo



  • Hi,

    *a.b geht nicht, da . stärker bindet als * und der Ausdruck daher äquivalent zu *(a.b) ist, was ein Syntaxfehler ist.

    Also muss man (*a).b schreiben. Da es aber nervt, Klammern zu setzen, hat man -> eingeführt mit: (*a).b <=> a->b

    Ein weiterer Vorteil ist, dass man -> überladen darf, sodass auch bei Objekten, die nicht direkt dereferenzierbar sind, eine "so wie Zeiger"-Verwendung gebastelt werden kann. Bestes Beispiel sind Iteratoren (Thema der Woche, scheint es :p).

    damit ich es verstehe müsste localtime(&ZeitDatum) einen zeiger zurückgeben sodass der zeiger Aktuelles Datum vom Typ tm auf die Systemzeit(auch vom typ tm?) zeigt.

    Ja. Und wenn man Polymorphie und seltene Reinterpretationen vernachlässigt sollte ein Zeiger eines Typs T auch immer auf eine Variable des Typs T verweisen.

    (ist das + 1 nach tm_mon da, weil die Monate im System von 0 bis 11 gezählt werden?

    Mir fällt kein anderer sinnvoller Grund dafür ein. 😉



  • ja deshalb ist das +1 da.
    steht auch in der API, dass die monate von 0 bis 11 gehen, genau wie die minuten und sekunden (oder so)

    ist halt das typische programmierer zählen: von 0 bis n-1



  • Cool, jetzt weiß ichs ! 🙂

    noch eine sache ( will dafür nicht extra noch ein thema machen)

    static char *MonatsName[13] = {" ", "Jan", "Feb", "Mar", "Apr",
    						  "Mai", "Jun", "Jul", "Aug",
    						  "Sep", "Okt", "Nov", "Dez"};
    
    	// Gib Jan Feb Mar Apr etc. zurück
    char *Datum::HoleMonatsName(void)
    {
       return MonatsName[Monat];
    }
    
    	// Gib eine ASCII-Z Zeichenfolge mit dem gespeicherten Fromat zurück
    	//   Format = 1	Aug 29, 1991
    	//   Format = 2	29.8.91
    	//   Format = 3	29.8.1991
    	//   Format = 4	29 Aug 1991       Militärsiche Zeit
    	//   Format = ?	Alles andere wird als Format 1 interpretiert
    char *Datum::HoleFormatiertesDatum(void)
    {
       switch (Format)
       {				// Diese Ausgabe nimmt an, dass das Jahr
    				// zwischen 1970 und 2069 liegt
    	case 2  : sprintf(AusStrom, "%02d.%02d.%02d",
    							  Tag, Monat, Jahr - 1970);
    		    break;
    
    	case 3  : sprintf(AusStrom, "%02d.%02d.%04d",
    								   Tag, Monat, Jahr);
    		    break;
    
    	case 4  : sprintf(AusStrom, "%d %s %04d",
    						   Tag, MonatsName[Monat], Jahr);
    		    break;
    
    	case 1  : // Weiter zu default
    	default : sprintf(AusStrom, "%s %d, %04d",
    						   MonatsName[Monat], Tag, Jahr);
    		    break;
       }
       return AusStrom;
    }
    

    Kann mir einer hier die verwendung der zeiger erklären und dazu noch, wieso überhaupt zeiger und nicht normale variablen?



  • Meinst Du die **char ***?
    Ein char kann nur ein Zeichen halten.
    Du willst aber eine Kette von Zeichen verarbeiten. Also nimmt man einen Zeiger auf das erste Zeichen. Das Kettenende wird durch ein Nullbyte gekennzeichnet (bei verwendung von "" implizit).



  • die zeiger sind doch aber in erster linie auf funktionen gerichtet, heißt das, dass hier nur der ausgabetyp der funktion der grund für die verwendung von zeigern ist?



  • Die Frage verstehe ich nicht.
    Und welche Funktion meinst Du?



  • Er mein z. Bsp. HoleMonatsName welche ein char* zurückgibt. Wenn diese Funktionen statt dessen std:.string zurückgeben würden bräuchte man keine Zeiger.



  • @Braunstein: Danke.
    @Flub:
    Es gibt verschiedene Gründe für die Verwendung von Zeigern.
    In dem von Dir gebrachten Beispiel verwendest Du C-Strings (alias char-Arrays), die kannst Du nur via Zeigern referenzieren.
    Wenn Du, wie Braunstein erwähnte, stattdessen std::String verwendetest könntest Du ohne Zeiger auskommen. Aber nur, weil std::string das intern für dich übernimmt.



  • genau, ich meinte z.B. in zeile 6.
    Ich habe irrtümlicherweise Funktion statt Methode geschrieben, also dort wird die methode HoleMonatsName implementiert, das Sternchen ist allerdings vor dem Namen der Methode, weshalb ich an Funktionszeiger gedacht habe.

    Kann man also immer wenn eine Methode eine Zeichenkette als Rückgabewert liefert

    char *methode(...
    

    im prototyp und in der implementation schreiben?

    EDIT:wir waren gleichzeitig am schreiben...

    Woher weiß der compiler, dass es überhaupt eine Zeichenkette (char-array ist) wenn es laut char *methode, genauso ein zeiger auf einen char sein könnte?



  • Flub schrieb:

    Kann man also immer wenn eine Methode eine Zeichenkette als Rückgabewert liefert

    char *methode(...
    

    im prototyp und in der implementation schreiben?

    Wenn's ein C-String sein soll, kannst Du nicht, Du mußt.

    Flub schrieb:

    Woher weiß der compiler, das es überhaupt eine Zeichenkette (char-array ist) wenn es laut char *methode, genauso ein zeiger auf einen char sein könnte?

    Die Frage ist falsch.
    Es ist ein Zeiger auf einen char - Punkt. Du entscheidest, wie Du ihn verwendest.



  • Eine Funktion, die einen char* ausgeben soll etc. handelt damit eben ganz besonders:

    Sie geht auf das Element, auf welches char* zeigt (also den char), und gibt diesen aus. Jetzt geht die Funktion davon aus, dass an der Speicheradresse direkt nach dem Zeiger wieder ein auszugebendes Zeichen ist und gibt das auch aus. Solange bis \0 kommt.
    Man könnte das auch so schreiben:

    void output(const char* str)
    {    
        if(*str != '\0')
        { 
            do
            {
                std::cout << *str;
            }while(*(++str) != '\0')
        }
    }
    


  • Man muß hier lediglich beachten, dass char* kein normaler Zeiger ist, sondern dass es hier diverse Sonderbehandlungen (siehe Streams) gibt. Hierbei wird char* im Allgemeinen als Zeichenkette interpretiert und auch so verwendet. Deswegen setzt man char* häufig mit einer Zeichenkette gleich. Siehe auch alle Funktionen aus cstring. Dies ist natürlich eine Altlast aus C.



  • Eisflamme schrieb:

    Man könnte das auch so schreiben:

    void output(const char* str)
    {    
        if(*str != '\0')
        { 
            do
            {
                std::cout << *str;
            }while(*(++str) != '\0')
        }
    }
    

    Auch bekannt als das komplizierte if/do-Konstrukt.

    void output(const char* str)
    {    
        while(*str != '\0')
        { 
            std::cout << *str;
            ++str;
        }
    }
    


  • Man sehe es mir nach, ich war noch halb am schlafen. ^^



  • Spricht eigentlich irgendetwas gegen

    std::cout << *str++;
    

    ?



  • hm...



  • Caligulaminus schrieb:

    Spricht eigentlich irgendetwas gegen

    std::cout << *str++;
    

    ?

    Ich verwende eigentlich nie sowas, wenn ich das Auslesen und das Inkrementieren auch auf zwei Zeilen packen kann.
    Früher schrieb ich auch mit Spaß Sachen wie

    while(!++*d++);//Vaxerzragvreg rvar Ynatmnuy zvg avrqrejregvtfgrz HVag mhrefg.
    

    , viel schlimmer noch, ich konnte nicht anders.



  • volkard schrieb:

    while(!++*d++);//Vaxerzragvreg rvar Ynatmnuy zvg avrqrejregvtfgrz HVag mhrefg.
    

    , viel schlimmer noch, ich konnte nicht anders.

    LOL - und da weisst du nach nem halben Jahr noch was es tut? Übrigens hast du vergessen das rot13 zu salzen *eg*



  • Argh!

    Dann ist hier d ein int(32)* das auf die untere Hälfte eines int(64) zeigt um hinterher nach inkrementierung dieser auf die obere zu zeigen?

    Habe ich das richtig verstanden?

    ~P.S.: Wird man für sowas eigentlich gefeuert, oder ist das eine effektive Jobsicherung?~


Log in to reply