Pointer, Enum, Linksschieben und paar andere Noob Fragen



  • Bald hab ich meine Programmierung Klausur und jetzt habe ich die letzte Klausur mal zur Probe gemacht, und dabei hängt es bei paar Aufgaben.

    Ich bin mir sicher das es die ganz logisch sind aber wir kommen zum verrecken einfach nicht darauf wie die drauf kommen.

    1.)

    Int pa=1, *pb=&pa;
    pa = pa + 2;
    *pb = *pb +3;
    Cout << pa << endl; (=6)
    Cout << *pb << endl; (=6)

    Verstehe das überhaupt nicht mit den Zeigern, kann mir das jemand bitte erklären?

    2.)
    Int b[]= {1,2,3,4}, *pc=b;
    Cout << *++pc << endl;

    Wie oben, hab ich gar kein Ansatz, und da soll 2 raus kommen. Wie? Keine Ahnung.

    3.)
    Int h=0;
    enum {richtig, falsch};
    If (richtig)
    h+=3;
    If(falsch)
    h+=7;
    Cout << h << endl;

    Da soll 7 raus kommen, ok! Aber warum wird der if(falsch) ausgeführt? Es wurde ja auch nicht deklariert das z.B. h=0 = falsch ist. Ich mein man könnte es statt "richtig und falsch" ja auch anders nennen, die Namen haben ja in diesem Fall nix zu sagen.

    4.)
    { int d = 1<< 10;}
    Cout << d << endl; (=42)
    Cout << 1 << 10 << endl; (=110)

    Muss man hier die 1 und 10 in Binär schreiben? Linksschieben? Rechtsschieben? Aber wie geht es dann weiter und warum kommen da 2 Unterschiedliche Ergebnisse? Es sind doch beides die gleichen Aufgaben. 😕

    5.)
    int m=0, n=1;
    if (m=n)
    m+=2;
    else
    m+=4;
    cout << m << endl; (=3)

    In diesem Fall wird meiner Meinung nach der else ausgeführt und dadurch wird m=4 aber das Ergebniss ist m=3 ?? Echt ratlos.

    6.)
    int w=0;
    w = w? w-8 : 8-w;
    cout << w << endl; (=8)

    If w=w then w-8 else 8-w, ich hätte gedacht das w-8 richtig wäre sprich w=w-8= -8, meine Antworg wäre in diesem Fall "-8", das richtige Ergebnis ist aber 8, warum bitte? 😮

    Ich hoffe ihr könnt mir helfen, ich wäre euch unendlich dankbar, hab schon den halben Sonntag verbracht Antworten zu finden aber nix gefunden, weder im Skript noch im Internet.



  • Aufgabe 4 ist falsch:

    4.) 
    int d = 1 << 10;
    cout << d << endl; (=1024) 
    cout << 1 << 10 << endl; (=110)
    

    Ich finde die Aufgaben gut, bin aber gerade zu faul und zu müde um 2 Seiten verständlichen Text zu produzieren der das erklärt. Das ginge auch deutlich einfacher wenn man etwas malen könnte.



  • nwp3 schrieb:

    Aufgabe 4 ist falsch:

    4.) 
    int d = 1 << 10;
    cout << d << endl; (=1024) 
    cout << 1 << 10 << endl; (=110)
    

    Ich finde die Aufgaben gut, bin aber gerade zu faul und zu müde um 2 Seiten verständlichen Text zu produzieren der das erklärt. Das ginge auch deutlich einfacher wenn man etwas malen könnte.

    Ok das kann sein das da ein Fehler war in der Lösung, warum ist der andere Wert dann aber =110?



  • Welcher Wert ist denn 110? Da wird eine 1 und eine 10 ausgegeben.



  • schwarztee schrieb:

    1.)

    int pa=1, *pb=&pa;
    pa = pa + 2;
    *pb = *pb +3;
    cout << pa << endl;         (=6)
    cout << *pb << endl;        (=6)
    

    Verstehe das überhaupt nicht mit den Zeigern, kann mir das jemand bitte erklären?

    pa ist 1 und pb ist ein Zeiger, der auf pa zeigt.
    Danach wird pa um zwei erhöht.
    pb zeigt immernoch auf pa und *pb greift auf den Wert zu, auf den gezeigt wird. Dieser Wert (der gleichzeitig immernoch pa ist) wird um drei erhöht.
    Daher sind auch beide Ausgaben gleich sechs.

    schwarztee schrieb:

    2.)

    int b[]= {1,2,3,4}, *pc=b;
    cout << *++pc << endl;
    

    Wie oben, hab ich gar kein Ansatz, und da soll 2 raus kommen. Wie? Keine Ahnung.

    pc zeigt auf b bzw das erste Element von b .
    ++pc ändert die Adresse, auf die gezeigt wird. Es zeigt jetzt nichtmehr auf das erste, sondern auf das zweite Element.
    Mit dem * wird wieder auf den Wert zugeriffen, auf den gezeigt wird, also auf die zwei.

    schwarztee schrieb:

    3.)

    int h=0;
    enum {richtig, falsch};
    if (richtig)
        h+=3;
    if(falsch)
        h+=7;
    cout << h << endl;
    

    Da soll 7 raus kommen, ok! Aber warum wird der if(falsch) ausgeführt? Es wurde ja auch nicht deklariert das z.B. h=0 = falsch ist. Ich mein man könnte es statt "richtig und falsch" ja auch anders nennen, die Namen haben ja in diesem Fall nix zu sagen.

    Wenn nichts angegeben ist, bekommt bei einem enum das erste Element den Wert null, das zweite den Wert eins usw.
    Null ist falsch/false, nicht null ist wahr/true.
    Die Bezeichner sind (wie du schon richtig angemerkt hast) beliebig zu wählen und hier zur Verwirrung gedacht.

    schwarztee schrieb:

    4.)

    int d=42;
    { int d = 1<< 10;}
    cout << d << endl;        (=42)
    cout << 1 << 10 << endl;  (=110)
    

    Muss man hier die 1 und 10 in Binär schreiben? Linksschieben? Rechtsschieben? Aber wie geht es dann weiter und warum kommen da 2 Unterschiedliche Ergebnisse? Es sind doch beides die gleichen Aufgaben. 😕

    Ich denke das int d=42; hat gefehlt. Hier wird ausgenutzt, dass das d = 1<<10; nur in seinem lokalen Gültigkeitsbereich (die geschweiften Klammern) gültig ist.

    Bei dem zweiten cout werden, wie schon geschrieben, einfach zwei Zahlen ausgegeben.
    Bei cout << (1 << 10) << endl; würde die 1024 ausgegeben werden.

    schwarztee schrieb:

    5.)

    int m=0, n=1;
    if (m=n)
        m+=2;
    else
        m+=4;
    cout << m << endl; (=3)
    

    In diesem Fall wird meiner Meinung nach der else ausgeführt und dadurch wird m=4 aber das Ergebniss ist m=3 ?? Echt ratlos.

    m=n ist eine Zuweisung, der Wert von m und n ist danach eins. Das if wertet den Wert eins als wahr aus.

    schwarztee schrieb:

    6.)

    int w=0;
    w = w? w-8 : 8-w;
    cout << w << endl; (=8)
    

    If w=w then w-8 else 8-w, ich hätte gedacht das w-8 richtig wäre sprich w=w-8= -8, meine Antworg wäre in diesem Fall "-8", das richtige Ergebnis ist aber 8, warum bitte? 😮

    w ist null, was als falsch gewertet wird.
    w = ( (w) ? (w-8) : (8-w) ) , ein w = w wird hier nicht ausgewertet.



  • schwarztee schrieb:

    5.)
    int m=0, n=1;
    if (m=n)
    m+=2;
    else
    m+=4;
    cout << m << endl; (=3)

    In diesem Fall wird meiner Meinung nach der else ausgeführt und dadurch wird m=4 aber das Ergebniss ist m=3 ?? Echt ratlos.

    Hier fehlt in der Bedingung ein '=': if(m == n).
    So wie es jetzt da steht, wird so ich es denn richtig verstanden habe auf m geprüft, also sozusagen if(m), nur dass m noch der Wert von n zugewiesen wird.

    Edit: too late 🙂



  • Ok dankeschön ihr habt mir echt weiter geholfen vorallem lagalopex.

    Dennoch muss ich sagen das ich die 3.) nicht verstehe, alle anderen habe ich jetzt zu 100% drauf, aber bei dem enum stehe ich da immer noch mit einem Fragezeichen da. 😃

    ps: Das mit dem d=42 stand echt ganz am Anfang der Aufgabe, habe nur paar Teile davon kopiert die ich nicht verstanden habe, habe es übersehen und die 110 oh mein Gott, mit was für Tricks hier gearbeitet wird (haha). Freu mich schon auf die Prüfung. -.-

    Um vielleicht noch eine Aufgabe reinzuwerfen, die war auch Teil der Klausur. Ich dachte die wäre mir klar wenn ich die anderen Zeiger Aufageben verstehe, aber dem ist leider nicht so.

    Aufgabe:

    void funktion1
    (int aa, int *bb, int *cc, int &dd)
    { 
    aa++; *bb++; (*cc)++; dd++;
    }
    
    int aa=0, bb=0, cc=0, dd=0;
    funktion1 (aa, &bb, &cc, dd);
    cout << aa << endl; // =0
    cout << bb << endl; // =0
    cout << cc << endl; // =1
    cout << dd << endl; // =1
    

    Immer diese blöden Zeiger 😞



  • Nochmal zum enum:

    enum {richtig, falsch};
    

    Ist dasselbe wie

    enum {richtig = 0, falsch = 1};
    

    Bei if(falsch) wird falsch zum Wert konvertiert, also 1. Und 1 ist true.

    aa wird auf 0 gesetzt und by-Value an die Funktion übergeben. In der Funktion wird nur eine Kopie erhöht, deshalb bleibt a 0.
    bb wird by-Reference (genau genommen via Pointer) an die Funktion übergeben.
    In der Funktion wird *bb++ ausgeführt. Aufgrund der Operator Rangfolge wird zuerst bb++ ausgefüht und auf das Ergebnis davon das *. D.h. bb wird um eine Speicheradresse erhöht (genau genommen UB, da die Speicheradresse nicht offziel belegt ist), und auf die alte Speicheradresse (ist ja Postinkrement) wird der Wert geholt und direkt wieder verworfen.
    Bei cc wird richtig der Wert erhöht, indem Klammern gesetzt werden und cc wird klassich by-Reference übergeben und erhöht.



  • Ok, dank dir, enum ist jetzt klar, war echt verwirrennd wegen den Namen.

    Aber beim anderen verstehe ich nur Bahnhof, habe die Begriffe nie gehört, auch das Skript vom Prof. durchsucht und nix gefunden.
    Im Internet dann das gefunden http://de.m.wikibooks.org/wiki/C++-Programmierung/_Weitere_Grundelemente/_Prozeduren_und_Funktionen aber wirklich verstehen tu ich es nicht.

    Falls irgendjemand noch ein Rat hat, bitte her damit. 👍

    Müsste die Zeile 7 nicht alle Werte auf 0 setzen?
    Und was genau macht eigentlich die Zeile 8?



  • schwarztee schrieb:

    Und was genau macht eigentlich die Zeile 8?

    Keines deiner Beispiele hat 8 Zeilen.



  • nwp3 schrieb:

    schwarztee schrieb:

    Und was genau macht eigentlich die Zeile 8?

    Keines deiner Beispiele hat 8 Zeilen.

    Meine das hier:

    void funktion1
    (int aa, int *bb, int *cc, int &dd)
    { 
    aa++; *bb++; (*cc)++; dd++;
    }
    
    int aa=0, bb=0, cc=0, dd=0;
    funktion1 (aa, &bb, &cc, dd);
    cout << aa << endl; // =0
    cout << bb << endl; // =0
    cout << cc << endl; // =1
    cout << dd << endl; // =1
    

    Hab bis jetzt alles verstanden ausser diese by-Values und by-Reference usw.



  • schwarztee schrieb:

    void funktion1
    (int aa, int *bb, int *cc, int &dd)
    { 
    aa++; *bb++; (*cc)++; dd++;
    }
    
    int aa=0, bb=0, cc=0, dd=0;
    funktion1 (aa, &bb, &cc, dd);
    cout << aa << endl; // =0
    cout << bb << endl; // =0
    cout << cc << endl; // =1
    cout << dd << endl; // =1
    

    In Zeile 8 wird die Funktion funktion1 aufgerufen. Die Paramter sind aa , die Adresse von bb und cc , sowie dd .

    In der Funktion gibt es nun ein neues aa welches nur den Wert vom ursprünglichen aa hat. Dann zwei Zeiger bb und cc die auf das ursprüngliche bb bzw cc zeigen. Sowie dd welches praktisch identisch ist mit dem anderen dd .

    In der Funktion wird aa geändert, da es aber nur eine Kopie ist, die geändert wird, ändert sich das ursprüngliche aa nicht. (Es bleibt null.)
    Der Zeiger bb wird um eins erhöht, es würde also auf einen Integer hinter dem ursprünglichen bb zeigen. Dieser Wert wird geholt (was dabei rauskommt ist nicht definiert) aber der Wert wird eh verworfen. (Auch das zweite bleibt null.)
    Mit (*cc)++ wird nun der Wert, auf den cc zeigt geholt und um eins erhöht. Dies ist gerade das ursprüngliche cc . (Es wird eins ausgegeben.)
    Das dd ist nun eine Referenz auf das ursprüngliche dd und verhält sich genauso. Die Änderung beeinflusst also direkt das ursprüngliche dd . (Es wird wieder eine eins ausgegeben.)

    By-Value meint, dass das Objekt kopiert wird und nur der Wert übergeben wird.
    By-Referenz hingegen übergibt das Original, so das es in der Funktion geändert werden kann.
    Die Zeiger sind so ein zwischending, es wird der Wert (die Adresse) by-Value übergeben, aber über die Adresse kann das Original geändert werden.



  • Tur mir Leid aber ich verstehe es einfach nicht, hab jetzt alles mögliche darüber gelesen aber ich verlier einfach den Überblick.

    void funktion1
    (int aa, int *bb, int *cc, int &dd)
    { 
    aa++; *bb++; (*cc)++; dd++;
    }
    
    int aa=0, bb=0, cc=0, dd=0;
    funktion1 (aa, &bb, &cc, dd);
    cout << aa << endl; // =0
    cout << bb << endl; // =0
    cout << cc << endl; // =1
    cout << dd << endl; // =1
    

    Also ich beschreibe mal wie weit ich mit komme, evtl. wissen wir dann wo bei mir im Gehirn es einfach stoppt.

    Zeile 1: Die Funktion "funktion1" wird deklariert.
    Zeile 2: Integer aa wird deklariert, Zeiger von bb und cc wird deklariert, Referenz von dd wird deklariert.
    Zeile 4: Anweisungen aa++, *bb++, (*cc)++, dd++ werden definiert.
    Zeile 7: Weiß ich nicht so genau was die macht. Ist die überhaupt relevant? (?)
    Zeile 8: Da hackt es richtig, ich weiß nicht genau was das mir sagen soll, warum macht man das? Was nützt das?

    Ich kapier es nicht, wird jetzt (Zeile 😎 alles neu deklariert?

    Und wo ist der Unterschied zwischen *bb++ und (*cc)++, was bringt die Klammer? (Zeile 4)

    Werden hier die Werte um 1 erhöht, postinkrement. Wie das wenn man nicht weiß welche Werte aa, bb, cc und dd haben. (Zeile 4)



  • schwarztee schrieb:

    Zeile 1: Die Funktion "funktion1" wird deklariert.

    Nein, das ist der Beginn einer Definition. Eine Funktionsdeklaration sieht so aus:

    void funktion(int aa, int *bb); // z.B.
    

    Zeile 2: Integer aa wird deklariert, Zeiger von bb und cc wird deklariert, Referenz von dd wird deklariert.

    Ja, aber ganz wichtig: Als Parameter der Funktion. Diese Variablen werden beim Aufruf der Funktion mit Werten versehen und sind nur innerhalb des Funktionskörpers gültig.

    Zeile 4: Anweisungen aa++, *bb++, (*cc)++, dd++ werden definiert.

    Ja. Wobei das komisch klingt. Die Zeile besteht aus den Anweisungen selbst, nicht aus "Definitionen" dieser Anweisungen.

    Zeile 7: Weiß ich nicht so genau was die macht. Ist die überhaupt relevant? (?)

    Das sind die Deklarationen der Variablen aa bis dd. Ohne das gibts die nicht. Das sind völlig andere Variablen als die Funktionsparameter oben, auch wenn sie gleich heißen mögen. Wenn dich das verwirrt, benenne sie (oder die Parameter) temporär anders.

    Zeile 8: Da hackt es richtig, ich weiß nicht genau was das mir sagen soll, warum macht man das? Was nützt das?

    Das ist der Aufruf der Funktion. Die Parameter werden mit den übergebenen Argumenten initialisiert, dann wird der Körper der Funktion ausgeführt, dann geht es nach der Aufrufstelle weiter.

    Ich kapier es nicht, wird jetzt (Zeile 😎 alles neu deklariert?

    Nein, das ist keine Deklaration.

    Und wo ist der Unterschied zwischen *bb++ und (*cc)++, was bringt die Klammer? (Zeile 4)

    Der nachgestellte ++-Operator hat eine höhere Priorität, d.h. *bb++ wird wie *(b++) interpretiert.

    Werden hier die Werte um 1 erhöht, postinkrement. Wie das wenn man nicht weiß welche Werte aa, bb, cc und dd haben. (Zeile 4)

    Weiß man doch, steht doch alles da.



  • Zeile 7 sagt "Es gibt vom Typ int eine Variable aa mit Startwert 0, eine Variable bb mit Startwert 0, ..."
    Die Variablen von Zeile 7 haben mit den Parameternamen in Zeile 2 garnichts zu tun.

    Zeile 8 ruft die Funktion funktion1 auf. funktion1 benötigt für den Aufruf ein int, ein int *, noch ein int * und ein int & wie in Zeile 2 definiert.
    Ein int ist eine Zahl. Ein int * ist ein Zeiger auf eine Zahl. Ein int & ist ein anderer Name für ein int.
    Um nun funktion1 aufzurufen brauchen wir zuerst ein int. Kein Problem, aa ist ein int, steht in Zeile 7. Dann brauchen wir einen Zeiger auf ein int. bb ist ein int und kein Zeiger auf ein int. Mit &bb bekommst du die Adresse von bb. Mit der Adresse der Variablen bb (ein int) kann man den Parameter bb (ein int 😉 initialisieren. Parameter bb zeigt jetzt auf Variable bb.
    Parameter dd ist jetzt ein anderer Name für die Variable dd. Das ist sinnvoll, weil funktion1 nicht direkt auf Variable dd zugreifen kann, weil zur Zeit der Definition die Variable dd noch gar nicht deklariert ist.
    Dann Zeile 4: aa++ erhöht den Parameter aa. Die Variable aa ist nicht betroffen, nur der Parameter aa, deswegen gibt das Programm zuerst eine 0 aus. Dann kommt der Ausdruck *bb++. bb ist ein Zeiger auf einen int. *bb dereferenziert Parameter bb, sodass du zu dem int kommst auf das Parameter bb zeigt (zufälligerweise Variable bb). Die Vorrangregeln in C++ sagen, dass zuerst bb++ und danach die Dereferenzierung ausgeführt werden. bb++ erhöht den Zeiger bb um 1, sodass es jetzt auf Blödsinn zeigt. Der Ausdruck bb++ hat als Rückgabewert bb, vor der Inkrementierung. Danach wird bb dereferenziert und man landet bei Variable bb. Und damit wird nichts gemacht. Also ist Variable bb am Ende immernoch 0, weil es nicht geändert wurde.
    (*cc)++ ändert mit den Klammern die Reihenfolge. Zuerst wird cc dereferenziert und wir landen bei Variable cc. Dann wird diese Variable um 1 erhöht.
    Zuletzt wird Parameter dd erhöht. Parameter dd ist nur ein anderer Name für Variable dd, also haben wir Variable dd um 1 erhöht.

    Wichtig zu merken: Variablennamen und Parameternamen sind unabhängig und werden unabhängig voneinander verändert. Zeiger muss man dereferenzieren wenn man an das rankommen will, worauf sie zeigen.



  • Ich hab jetzt mal eine Nacht drüber geschlafen, und natürlich wieder meine typischen C++ Albträume gehabt. 😃

    Und mit klarem Kopf wird einiges klarer, ich verstehe nicht alles zu 100% aber so viel das es eigentlich reichen müsste, ich hoffe so eine Art von Aufgabe wird nicht nächste Woche in der Klausur dran kommen, wenn nicht muss ich mich halt an der jetzigen Aufgabe orientieren.

    Ich danke euch allen sehr vom Herzen, falls man sich mal im Real Life sieht geb ich auch ein Bier aus. 😉

    Schönen Tag euch allen noch.
    schwarztee. 👍


Log in to reply