for(year=0,total=0;year<YEARS;year++){// for each year, sum rainfall for each month
12
for(month=0,subtot=0;month<MONTHS;month++)
13
subtot+=rain[year][month];
14
printf("%5d %15.1f\n",2000+year,subtot);
15
total+=subtot;// total for all years
16
}
Es soll die Zeile "subtot += rain[year][month]" durch Pointer ersetzt
werden.
Ich habe folgende Lösung die nicht funktioniert:
subtot += *(rain + ((year * MONTHS) + month) ) ;
Wie bin ich auf diese Lösung gekommen?
Dies steht im Buch:
*(dates + 2) /* value of the 3rd element of dates */
Hallo!
Das Beispiel mit dates aus Deinem Buch war fuer ein
1D Array. In Deinem Fall musst Du das Prinzip zweimal
anwenden:
*(rain + year) ergibt das 1D Array mit den monatlichen Regenfaellen
fuer ein gegebens Jahr (year).
*(*(rain + year) + month) ergibt dann das entsprechende Element
aus diesem Array fuer einen gegebenen Monat (month).
Du benoetigst also:
subtot += *(*(rain + year) + month);
Das sollte das Buch aber eigentlich erlaeutern, falls es etwas taugt.
Das dazugehörige Basiswissen ist, dass in C die Schreibweise Array[]
äquivalent ist zu *(Array + Index). Sprich: setzt du einen Pointer ptr
auf das erste Arrayelemente, kannst du mit einem Inkrement des Pointers
zum nächsten springen. In deinem Fall sind es zwei verschachtelte
Arrays. Bringt dich das weiter?
Kellernerd schrieb:> subtot += *(*(rain + year) + month);
Diese Antwort ist richtig.
Leider verstehe ich es nicht. Ich glaube ich hab mir die Sache einfach
falsch vorgestellt. Ich dachte die Elemente stehen hintereinander im
Speicher und ich muss abzählen.
Auf diese Lösung wäre ich in 100 Jahren nicht gekommen.
rain ist ein Array von einem Array von const float.
rain[0] gibt die Adresse vom ersten Jahr und ist vom Typ "Zeiger auf
const float"
rain[1] gibt die Adresse vom zweiten Jahr
rain gibt die Adresse vom ersten Array und ist vom Typ "Zeiger auf Array
12 von const float"
Da Array[index] und *(Array+index) identisch sind, hast du für
rain[year][month] dann *(rain[year]+month)) und schließlich
*(*(rain+year)+month))
Anmerkungen:
Da Array[index] und *(Array+index) identisch sind, und für die Addition
das Kommutativgesetz gilt, kann man auch *(index+Array) schreiben.
Darum ist auch index[Array] in C erlaubt
rain und rain[0] ergeben dieselbe Adresse, sind aber von
unterschiedlichem Typ.
rain+1 zeigt auf das zweite Jahr, während rain[0]+1 auf den zweiten
Monat im ersten Jahr zeigt (wie &rain[0][1] )
Michael schrieb:> Die Reihenfolge ist ne andere.
Nein, ist sie nicht.
Bei dir sind die Adressen aufsteigend.
Im Beispiel von Kaj G. ist das nicht anders.
Er hat nur ein char arr[x][2];
Nach dem C-Standard wir der ganz rechte Index am schnellsten gewechselt.
Michael schrieb:> [...]> falsch vorgestellt. Ich dachte die Elemente stehen hintereinander im> Speicher und ich muss abzählen.
Die Elemente stehen, wie von Dir vermutet und von anderen Kommentatoren
bereits erlaeutert, tatsaechlich hintereinander im Speicher. Die von Dir
angenommene Auswahl mittels
Gesamtindexberechnung gilt allerdings nur in eindimensionalen Arrays.
Du koenntest also ein 1D Array erzeugen und dort alle Niederschlagswerte
hintereinander hineinschreiben (= recht unuebersichtlich) oder aber auch
Deine Adresse eines zweidimensionalen Arrays (rain) als Adresse eines
eindimensionalen Arrays uminterpretieren (casten), um den von Dir
angenommen Zugriff zu realisieren:
1
subtot+=*((constfloat*)rain+year*MONTHS+month);
Hier musst Du jedoch Vorwissen haben, wie die Werte eines
zweidimensionalen Arrays bei der Sprache C im Speicher abgelegt werden
(reihenweise oder spaltenweise) und ausserdem diese haessliche
Multiplikation mit einer Konstanten hinzufuegen. Schlimmer wird es
noch bei hoeheren Dimensionen (wenn Du z.B. noch Tag und Stunde
haettest).
Das mehrdimensionale Array ist hier eleganter und leichter
lesbar/verstaendlich.
Das Umschreiben in einen Zugriff mittels Zeiger soll dem Leser des
Buches wohl die Zusammenhaenge erlaeutern, denn es resultiert in
schlechterer Lesbarkeit und mehr Tipparbeit. Falls dies wirklich das
erste Beispiel zu Zeigern ist, ist der Buchautor etwas fies.
Ich wuerde Dir (bei Interesse) empfehlen, mehrere minimale
Beispielprogramme mit unterschiedlichen Arraydimensionen und
Zugriffsarten auszuprobieren und diese genau mittels Debugger auf ihr
Speicherlayout hin zu untersuchen.
Eeine spannende Erweiterung waere
z.B. ein Cast/Zugriff mittels (void *), so dass keine Kenntnis
mehr ueber die Groesse der Elemente im Array besteht und Du dann
entsprechend Zeigerarithmetik mit Bytes machen musst:
1
subtot+=*((constvoid*)rain/* + ??? */);
.
Mit der Printf-Direktive %p kannst Du Dir Adressen ausgeben lassen.
Das ist fuer Experimente bei der Adressberechnung sehr hilfreich.
Z.B die Adresse Deines Arrays (rain) oder die eines Arrayelementes:
1
printf("%p\n%p\n%p\n",rain,&rain,&rain[2][2]);
Wenn Du begruenden kannst, warum rain und &rain den
gleichen Wert liefern, hast Du den Themenkomplex recht gut verstanden.
Viel Spass beim Experimentieren und lass Dich nicht von der
Adressrandomisierung verwirren, bzw. schalte sie fuer Deine
Beispiele ab, da ansonsten Dein Array bei jedem Programmstart an einer
anderen Anfangsadresse liegt (dies ist eigentlich ein Schutz, damit
Angreifer die Adressen nicht so leicht erfahren und im Fall von
Programmierfehlern ausnutzen koennen).
Kellernerd schrieb:> subtot += *(const float *)((const void *) rain /* + ??? */);
Naja, man muss dabei sagen, dass Michaels Aufgabenstellung sinnlos ist
und wohl nur der Erforschung der Anordnung dient. Die Originalzeile ist
ja lesbar und gut:
Michael schrieb:> Es soll die Zeile "subtot += rain[year][month]" durch Pointer ersetzt> werden.