Programmanalyse < C/C++ < Programmiersprachen < Praxis < Informatik < Vorhilfe
|
Status: |
(Frage) beantwortet | Datum: | 18:51 Di 02.09.2008 | Autor: | tynia |
Ich habe hier folgenden Quellcode und soll jetzt geeignete Kommentare dazu abgeben. Ich habe das jetzt gemacht, verstehe aber so ein paar sachen nicht.
Erstmal der Quellcode mit Bildschirmausgabe:
[Dateianhang nicht öffentlich]
Und jetzt meine Fragen:
1.
Wenn ich das Array mit int a [3][2] deklariere, dann erstellt mir der pc das programm ohne Probleme.
Wenn ich es aber mit int a [2][1] deklariere, gibt er mir eine Fehlermeldung aus, aber gibt trotzdem irgendwelche Werte aus.
Ich habe gedacht, ich müsste a mit a [2][1] deklarieren, weil die höchste Position in der Matrix mit dem Wert 6 bei a [2][1] besetzt wurde.
2.
Warum gibt der Pc hier:
cout << [mm] "\n*a[0]:\t" [/mm] << *a[0]; // Feld (Array) existiert nicht, da wir uns im 2-dim. befinden
trotzdem einen Wert aus, nämlich die 1.
Ich verstehe halt nicht, warum der Pc was ausgibt, obwohl das Array eigentlich gar nicht existiert, da wir uns ja im 2-dimensinalen befinden.
Überall wo ich ich als Kommentar: Zugriffsverweigerung oder Feld existiert nicht dran geschrieben habe, gibt er trotzdem Werte aus.
Ich habe deshalb auch die Bildschirmausgabe mit eingefügt, damit man das mal sehen kann.
Ich hoffe es kann mir jemand helfen. Danke schonmal im voraus.
Dateianhänge: Anhang Nr. 1 (Typ: png) [nicht öffentlich]
|
|
|
|
> Ich habe hier folgenden Quellcode und soll jetzt geeignete
> Kommentare dazu abgeben. Ich habe das jetzt gemacht,
> verstehe aber so ein paar sachen nicht.
>
> Erstmal der Quellcode mit Bildschirmausgabe:
[Dateianhang nicht öffentlich]
> Und jetzt meine Fragen:
> 1.
> Wenn ich das Array mit int a [3][2] deklariere, dann
> erstellt mir der pc das programm ohne Probleme.
>
> Wenn ich es aber mit int a [2][1] deklariere, gibt er mir
> eine Fehlermeldung aus, aber gibt trotzdem irgendwelche
> Werte aus.
Wahrscheinlich eine Zugriffsverletzung (access violation): weil bei der Anweisung a[2][0]=5 auf eine Zelle ausserhalb des deklarierten Bereichs zugegriffen wird.
> Ich habe gedacht, ich müsste a mit a [2][1] deklarieren,
> weil die höchste Position in der Matrix mit dem Wert 6 bei
> a [2][1] besetzt wurde.
Nein, dies ist ein kleines Missverständnis. In C++ beginnt die Arrayindexierung bei 0. In der Deklaration musst Du aber die Länge des Indexbereiches angeben. Ein mittels a[m][n] deklarierter Array darf daher in der Form a[i][k] nur mit Indexwerten [mm] $i\in \{0,\ldots m-1\}$ [/mm] und [mm] $k\in \{0,\ldots, n-1\}$ [/mm] adressiert werden.
>
> 2.
> Warum gibt der Pc hier:
> cout << [mm]"\n*a[0]:\t"[/mm] << *a[0]; // Feld (Array) existiert
> nicht, da wir uns im 2-dim. befinden
> trotzdem einen Wert aus, nämlich die 1.
a[0] ist die Adresse des ersten Elementes des Subarrays der Elemente a[0][0], a[0][1]. Durch "Dereferenzieren" * wird auf den Wert, der in diesem ersten Element gespeichert ist, zugegriffen. *a[0] liefert also denselben Wert, wie a[0][0].
Analog würde *a[1] denselben Wert liefern, wie a[1][0]
>
> Ich verstehe halt nicht, warum der Pc was ausgibt, obwohl
> das Array eigentlich gar nicht existiert, da wir uns ja im
> 2-dimensinalen befinden.
Diese Bemerkung verstehe ich nun überhaupt nicht. Am Anfang des Programmes wird ja der Array deklariert und sogar alloziert. Zudem werden allen allozierten Elementen des 2-dimensionalen Arrays a auch Werte zugewiesen. Wo also siehst Du ein Problem?
>
> Überall wo ich ich als Kommentar: Zugriffsverweigerung oder
> Feld existiert nicht dran geschrieben habe, gibt er
> trotzdem Werte aus.
Dein Problem scheint zu sein, dass Du die Syntax von C++ im Zusammenhang mit Arrays nicht genügend genau verstehst (Dich mit solchen Verständnisproblemen zu konfrontieren, war sicher auch die Absicht des Aufgabenstellers). Wie gesagt: deklarierst Du int a[m][n], dann bedeutet a[i] die Adresse eines int-Arrays der Länge $n$. Deshalb wurde bei der Anweisung cout << "\na[0]+1:\t"<< a[0]+1; der Wert 0032FB24 ausgegeben. Diese Schreibweise (achtstellige Hexadezimalzahl) sollte Dir schon sagen: hier wird der Wert einer Adresse ausgegeben. Die Adresse a[0] muss 0x0032FB24-sizeof(int) gewesen sein, denn sizeof(int) wird zu einem Zeiger auf einen int-Array dazuaddiert, wenn man ihm ein +1 anhängt.
Dateianhänge: Anhang Nr. 1 (Typ: png) [nicht öffentlich]
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 19:26 Di 02.09.2008 | Autor: | tynia |
Also sind demnach meine Kommentare, in denen ich schreibe, dass das Feld gar nicht existiert, falsch? Ist den der Rest richtig?
Kannst du mir vielleicht auch noch sagen, warum ich eine Fehlermeldung erhalte, wenn ich folgendes eingebe:
cout << "*a[0][1]" << *a[0][1];
Du hast recht, ich habe von Informatik nicht soviel Ahnung, muss aber trotzdem bald eine Klausur schreiben. Zum Glück gibt es sowas wie Matheraum.de, sonst wäre ich ein bißchen aufgeschmissen.
|
|
|
|
|
> Also sind demnach meine Kommentare, in denen ich schreibe,
> dass das Feld gar nicht existiert, falsch? Ist den der Rest
> richtig?
>
> Kannst du mir vielleicht auch noch sagen, warum ich eine
> Fehlermeldung erhalte, wenn ich folgendes eingebe:
>
> cout << "*a[0][1]" << *a[0][1];
Die Deklaration des Arrays war ja int a[3][2]. Zudem wurde die Anweisung a[0][1]=2; ausgeführt. Demzufolge ist a[0][1] nichts anderes als die Zahl 2. Da aber zudem bei *a[0][1] noch mit * versucht wird, diese Zahl 2 als Adresse zu dereferenzieren (man verlangt also gewissermassen, dass *2 ausgeführt wird), kommt es zur besagten Fehlermeldung.
>
> Du hast recht, ich habe von Informatik nicht soviel Ahnung,
> muss aber trotzdem bald eine Klausur schreiben.
Nein, es geht hier nicht wirklich um Informatik sondern bloss um die zweifellos etwas verwirrliche Syntax von C++. Vielleicht findest Du auf dem Netz noch die eine oder andere nützliche Erklärung. Auf Anhieb bin ich mit der Google-Suche nach "c++ pointerarithmetik" auf diese Seite gestossen. Vermutlich hat es auch noch wesentlich bessere Erklärungen auf dem Netz, aber diese Seite ist doch schon gar nicht mal so schlecht.
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 19:42 Di 02.09.2008 | Autor: | tynia |
Eine Frage noch. Ich will mal wissen ob ich das verstanden habe.
a[1] ist die Adresse des ersten Elementes des Subarrays der Elemente a[1][0], a[1][1]. Kann ich denn auch auf das zweite Element zugreifen?
|
|
|
|
|
> Eine Frage noch. Ich will mal wissen ob ich das verstanden
> habe.
>
> a[1] ist die Adresse des ersten Elementes des Subarrays der
> Elemente a[1][0], a[1][1].
Richtig.
> Kann ich denn auch auf das zweite Element zugreifen?
Ja, indem Du einfach noch [1] an a[1] dranhängst. Aber dies weisst Du schon, weil es nichts anderes bedeutet als a[1][1]. Immerhin kann man dies auch als (a[1])[1] schreiben.
Eine weitere Alternative zu a[1][1] wäre *(a[1]+1), weil durch den Zusatz +1 zur Adresse a[1] des ersten Elementes des fraglichen Subarrays die Grösse einer int-Speicherzelle dazuaddiert wird (also sizeof(int)), so dass die Adresse a[1]+1 nun auf das zweite Element des Subarrays zeigt und somit mittels Dereferenzieren *, auf dessen Wert zugegriffen werden kann.
Des weiteren kann man a[1] auch zuerst einem Pointer auf int zuweisen. Und zwar so: int *pa1 = a[1]; und schliesslich mit pa1[1] oder mit *(pa1+1) auf denselben Wert zugreifen wie mit a[1][1].
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 20:00 Di 02.09.2008 | Autor: | tynia |
Ok. Danke erstmal. Hast mir echt geholfen
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 20:06 Di 02.09.2008 | Autor: | tynia |
Noch eine Frage:
Ich würde das nochmal mit den Kommentaren machen, habe nur heute keine Zeit mehr dafür. Würde das morgen machen. Könntest du dir das dann nochmal angucken und gegebenenfalls korrigieren?
|
|
|
|
|
> Noch eine Frage:
>
> Ich würde das nochmal mit den Kommentaren machen, habe nur
> heute keine Zeit mehr dafür. Würde das morgen machen.
> Könntest du dir das dann nochmal angucken und
> gegebenenfalls korrigieren?
Ich würde dies gerne machen. Aber eine Bitte habe ich dazu: kopiere den Code in Deine Frage hinein und zwar, indem Du den ganzen Code zwischen [code][/code]-Tags einfügst. Denn wenn Du einen zwar hübschen aber leider nicht editierbaren Screendump lieferst, muss ich alles nochmals von Grund auf eintippen...
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 20:14 Di 02.09.2008 | Autor: | tynia |
ok. habe doch noch eine frage.
cout << "a+1: " << a+1;
cout << "a[0]+1: " << a[0]+1;
warum gibt er hier eine Adresse aus?
|
|
|
|
|
> ok. habe doch noch eine frage.
>
> cout << "a+1: " << a+1;
Aufgrund der Deklaration int a[3][2]; ist $a$ ein Poiner auf einen 2-dimensionale Array von int Werten, und zwar auf einen Array der deklarierten Grösse [3][2]. Mit dem Zusatz +1 kommt wieder Pointerarithmetik zum Zug. Zur Adresse a wird die Grösse (in bytes, also sizeof(a)) dazuaddiert. Du solltest aber nicht versuchen, diesen Pointer a+1 mit [i] oder * zu dereferenzieren, denn a+1 zeigt auf einen bloss hypothetischen Array, der gar nicht alloziert wurde.
> cout << "a[0]+1: " << a[0]+1;
>
> warum gibt er hier eine Adresse aus?
a[0] ist die Adresse des ersten Elementes a[0][0] des aus den Elementen a[0][0] und a[0][1] bestehenden Subarrays. Es handelt sich daher um einen Pointer auf int (d.h. um eine Adresse einer Integer). Der Zusatz +1 bedeutet, dass zu dieser Adresse a[0] die Grösse sizeof(*a[0]) der Objekte, auf die a[0] "zeigt" dazuaddiert wird (die Idee ist, dass die resultierende Adresse, a[0]+1 auf das nächste Element derselben Grösse zeigen soll). Auf meinem System ist sizeof(int) dasselbe wie sizeof(*a[0]) und zwar gleich 4. sizeof(a[0]) ist jedoch gleich $8$, was nicht erstaunt, denn der Subarray, auf den a[0] zeigt, hat ja 2 int-Elemente und daher eine Grösse 2*sizeof(int), also [mm] $2\cdot [/mm] 4=8$.
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 20:42 Di 02.09.2008 | Autor: | tynia |
ich dachte pointer werden mit *a[] deklariert und Adressen mit & a[]? das verstehe ich nicht.
muss jetzt leider danach weg.kann also nicht mehr antworten
|
|
|
|
|
> ich dachte pointer werden mit *a[] deklariert und Adressen
> mit & a[]? das verstehe ich nicht.
>
> muss jetzt leider danach weg.kann also nicht mehr antworten
Die Adresse der Speicherzelle, in der sich a[2][0] befindet, ist &a[2][0]. Ampersand & ist in diesem Sinne also der "address of"-Operator: &a[2][0] ist die Adresse, auf der der Wert a[2][0] gespeichert ist.
&a[2][0] ist die Adresse einer Integer (d.h. int). Daher kann ein Pointer auf diese Zelle mitels int *p; deklariert, mittels p=&a[2][0] oder p=a[2] initialisiert und schliesslich mittels *p oder p[0] derefrenziert werden.
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 15:57 Mi 03.09.2008 | Autor: | uecki |
Hallo, ich bin eine Kommilitonin von tynia und habe noch eine Frage zu dem ganzen hier.
Und zwar an der Stelle:
cout << "a[0]+2" << (*a[0]+2)-1
Nach "a[0]+2" müsste der PC mir hier die Adresse des Feldes a[0][0]+2 ausgeben.
Aber nach (*a[0]+2)-1 gibt der PC mir doch den Wert des Feldes a[0][0]+1=2 aus. Ist das dann ein logischer Fehler?
Danke für deine Geduld
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 16:03 Mi 03.09.2008 | Autor: | uecki |
Mir fällt gerade auf, dasselbe würde doch dann nach meinem Verständnis auch für die Programmzeile:
cout << "a[1][0]" << &a[1][0]
gelten.
Hier würde es ja nach "a[1][0]" heißen,dass mir der Wert von a[1][0] nämlich 3 ausgegeben werden würde.
Aber natürlich gibt mir der PC nach &a[1][0] die Adresse der Variablen aus.
Wäre doch dann wieder ein logischer Fehler? oder????
|
|
|
|
|
> Mir fällt gerade auf, dasselbe würde doch dann nach meinem
> Verständnis auch für die Programmzeile:
> cout << "a[1][0]" << &a[1][0];
Auch hier ist der Ausdruck a[1][0], den Du als Text auf cout ausgeben lässt, nicht identisch mit dem Ausdruck &a[1][0], dessen Wert Du effektiv dann ausdrucken lässt. a[1][0] ist eine Zahl - und zwar, aufgrund der Initialisierung des Arrays a müsste dies die Zahl 3 sein.
&a[1][0], andererseits, ist die Adresse, auf der der Wert von a[1][0] gespeichert wird. Daher nennt man & auch den "address of"-Operator.
> gelten.
> Hier würde es ja nach "a[1][0]" heißen,dass mir der Wert
> von a[1][0] nämlich 3 ausgegeben werden würde.
> Aber natürlich gibt mir der PC nach &a[1][0] die Adresse
> der Variablen aus.
Stimmt: also sind wir uns in dieser Frage einig.
> Wäre doch dann wieder ein logischer Fehler? oder????
Ich sehe nicht, wo Du einen Widerspruch siehst: ausser zwischen der blossen Zeichenkette "a[1][0]" und der effektiv ausgegebenen Adresse &a[1][0], die übrigens mit a[1] übereinstimmen sollte.
Du kannst ja auch gleich solchen Müll wie
cout << "\ngugus, gaga:\t" << &a[1][0];
schreiben und Dich dann bitter beklagen, dass &a[1][0] nicht den gewünschten Wert "gugus, gaga" geliefert hätte...
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 18:02 Mi 03.09.2008 | Autor: | uecki |
Ja genau das meinte ich mit Fehler, also den Widerspruch zwischen Text und wirklicher Ausgabe. Dachte das würde logischer Fehler heißen.
Ok, danke! Hat uns sehr weitergeholfen!
Aber nun die letzte Frage die wir noch haben
Bei der Zeile:
cout << "a+2" << a+2;
steht.
Gibt mir der PC da die Adresse des gesamt gespeicherten Arrays um zwei "Plätze" erhöht aus?
|
|
|
|
|
> Ja genau das meinte ich mit Fehler, also den Widerspruch
> zwischen Text und wirklicher Ausgabe. Dachte das würde
> logischer Fehler heißen.
> Ok, danke! Hat uns sehr weitergeholfen!
> Aber nun die letzte Frage die wir noch haben
> Bei der Zeile:
> cout << "a+2" << a+2;
> steht.
> Gibt mir der PC da die Adresse des gesamt gespeicherten
> Arrays um zwei "Plätze" erhöht aus?
Bei der Pointerarithmetik kommt es darauf an, auf welche Art von Objekt der Pointer effektiv zeigt. Die Grösse des Objektes (in Bytes), auf das der Pointer a zeigt, erhältst Du von sizeof(*a), oder, was auf das selbe hinausläuft, von sizeof(a[0]).
Wenn Du etwa folgende drei Anweisungen
cout << "\na:\t" << a;
cout << "\nsizeof(*a):\t" << sizeof(*a);
cout << "\na+2:\t" << a+2;
nach der Initialisierung anfügst, dann erhältst Du als Ausgabe etwas in der folgenden Art:
a: 001BF224
sizeof(*a): 8
a+2: 001BF234
Du siehst, dass die für a+2 ausgegebene Adresse gleich der Adresse a+2*sizeof(*a) ist (wobei hier a nur für den Zahlenwert 001BF224 steht und somit a+2*sizeof(*a), im Unterschied zum Ausdruck a+2, nicht als C++ Ausdruck zu interpretieren ist!). Dies gilt allgemein: ist p ein Pointer, dann ist p+k die Adresse p+k*sizeof(*p) (wobei in diesem letzteren Ausdruck p nur für den uninterpretierten hexadezimalen Zahlenwert der Adresse p steht).
Und weshalb ist sizeof(*a) gleich 8? - Weil a, als Pointer, auf den ersten Subarray von a, bestehend aus den Elementen a[0][0] und a[0][1] zeigt: a ist also ein Pointer auf einen Integerarray der Länge 2. Da sizeof(int) gleich 4 ist (jedenfalls auf meiner Maschine), folgt, dass die Gesamtlänge des Subarrays (in Bytes), auf den a zeigt, gleich 2*4=8 ist. Deshalb ist sizeof(*a) also gleich 8.
|
|
|
|
|
> Ja genau das meinte ich mit Fehler, also den Widerspruch
> zwischen Text und wirklicher Ausgabe. Dachte das würde
> logischer Fehler heißen.
> Ok, danke! Hat uns sehr weitergeholfen!
> Aber nun die letzte Frage die wir noch haben
> Bei der Zeile:
> cout << "a+2" << a+2;
> steht.
> Gibt mir der PC da die Adresse des gesamt gespeicherten
> Arrays um zwei "Plätze" erhöht aus?
Vielleicht hätte ich noch schreiben sollen, dass a+2 dieselbe Adresse liefert, wie a[2]. Dies ist hier aber nur deshalb so, weil a als mehrdimensionaler Array deklariert wurde. Wäre die Deklaration von a z.B. gleich int a[3]; gewesen, so wäre zwar a+2 noch immer eine Adresse, und zwar die Adresse, auf der a[2] gespeichert wird. a[2], andererseits, wäre der dort gespeicherte Integerwert, also keine Adresse.
Nachtrag (1. Revision): Hier noch ein Bildchen, das zeigen soll, wie die Pointer a bzw. a[0] durch Addieren von 1, 2, 3 in unterschiedlich grossen Schritten verschoben werden: einfach weil diese Pointer auf Objekte unterschiedlicher Grösse zeigen. a zeigt auf int-Arrays der Länge 2, a[0] zeigt jedoch auf int Werte:
[Dateianhang nicht öffentlich]
Dateianhänge: Anhang Nr. 1 (Typ: png) [nicht öffentlich]
|
|
|
|
|
> Hallo, ich bin eine Kommilitonin von tynia und habe noch
> eine Frage zu dem ganzen hier.
> Und zwar an der Stelle:
> cout << "a[0]+2" << (*a[0]+2)-1;
Was hier steht ist schon mal ganz fragwürdig, denn die Idee ist doch, dass der auf cout ausgegebene Text "a[0]+2" mit dem Ausdruck übereinstimmt, dessen Wert danach ausgegeben wird. Dies ist hier aber nicht der Fall: a[0]+2 ist etwas ganz anderes als (*a[0]+2)-1. Entweder musst Du
cout << "\na[0]+2:\t" << a[0]+2
oder
cout << "\n(*a[0]+2)-1:\t" << (*a[0]+2)-1;
schreiben: aber nicht eine widersprüchliche Mischung dieser beiden Anweisungen.
> Nach "a[0]+2" müsste der PC mir hier die Adresse des Feldes
> a[0][0]+2 ausgeben.
Nein, a[0] ist die Startadresse des Subarrays von a, der aus den Elementen a[0][0] und a[0][1] besteht. Diese Adresse, aufgefasst als Pointer, zeigt auf den erste Eintrag eines int-Arrays der Länge 2 (im Sinne von 2 Integerwerte: denn so war der Bereich für den zweiten Index von a deklariert worden). Somit ist a[0]+2 das selbe wie &a[0][2] (die Adresse, auf der die Integer a[0][2] gespeichert wird). Du kannst dies selbst prüfen, indem Du die Ausgaben von
cout << "\na[0]+2:\t" << a[0]+2;
und
cout << "\n&a[0][2]:\t" << &a[0][2];
vergleichst: es sollte in beiden Fällen dieselbe (hexadezimale) Adresse ausgegeben werden.
Der Code (*a[0]+2)-1, dessen Wert Du effektiv auf cout augibst, macht nochmal was anderes. Ich erklär's schrittweise: a[0] ist die Startadresse des Subarrays von a, der aus den Elementen a[0][0] und a[0][1] besteht. Als nächstes wird diese Adresse a[0], die auch gerade auf das erste Element a[0][0] dieses Subarrays zeigt, dereferenziert: *a[0]. Dies liefert den Wert, auf den a[0] "zeigt", und ist daher gleich dem Wert a[0][0]. Aufgrund der Initialisierung des Arrays a ist *a[0] daher die ganze Zahl (Integer) 1 (also insbesondere keine Adresse mehr). Zu dieser Zahl 1 wird mit *a[0]+2 noch 2 dazugezählt, ergibt 3 und schliesslich wird mit (*a[0]+2)-1 noch 1 subtrahiert: ergibt insgesamt den ganzzahligen Wert 2.
> Aber nach (*a[0]+2)-1 gibt der PC mir doch den Wert des
> Feldes a[0][0]+1=2 aus. Ist das dann ein logischer Fehler?
Nein, siehe oben.
|
|
|
|