Forum: PC-Programmierung Keine änderung im Memory Dump bei Array füllung.Weshalb?


von Joe M. (jumper)


Angehängte Dateien:

Lesenswert?

Hallo,
weshalb ändert sich im Memory Dump nichts wenn ich ein Array fülle(und 
während ich fülle debugge)?
Ich hätte eine Änderung an der Adresse 0x22ff38 bzw. den darauf 
folgenden Adressen erwartet!

Mein Quelltext:
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
5
int main()
6
7
{
8
    int zahlen[5];
9
    int i;
10
11
    for (i=0; i<6; i++)
12
    {
13
        printf("Zahl %d:", i+1);
14
        scanf("%d", &zahlen[i]);
15
16
    }
17
}
Grüße Joe

von DirkB (Gast)


Lesenswert?

Was hast du denn eingegeben?

von Rolf Magnus (Gast)


Lesenswert?

Ist zwar nicht die Antwort, aber du solltest vermeiden, in ein 5 
Elemente großes Array 6 Werte zu schreiben.

von Vn N. (wefwef_s)


Lesenswert?

Hättest du mal ein vernünftiges C-Buch in der Hand gehabt, wüsstest du, 
dass &zahlen nicht auf das Array im Speicher zeigt, sondern auf den 
Zeiger, der auf das Array zeigt. Du willst dir aber den Speicher an der 
Stelle ansehen, die in "zahlen" steht.

Rolf Magnus schrieb:
> Ist zwar nicht die Antwort, aber du solltest vermeiden, in ein 5
> Elemente großes Array 6 Werte zu schreiben.

Richtig, das mit dem Buch gilt auch hier.

von DirkB (Gast)


Lesenswert?

vn nn schrieb:
> ... sondern auf den
> Zeiger, der auf das Array zeigt.
Diesen Zeiger gibt es bei Arrays gar nicht.

Das ist ja einer der Unterschiede zwischen Arrays und Zeigern.

Im Watches-Fenster kann man auch die Werte über dem i = 1 sehen.
Die passen zu dem Hexdump im Memory-Fenster.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

vn nn schrieb:
> Hättest du mal ein vernünftiges C-Buch in der Hand gehabt, wüsstest du,
> dass &zahlen nicht auf das Array im Speicher zeigt, sondern auf den
> Zeiger, der auf das Array zeigt.

Den aber gibt es hier nicht. In was für einem vernünftigen C-Buch meinst 
Du diese Information gefunden zu haben?

von Joe M. (jumper)


Lesenswert?

Was den nun?
zeigt &zeiger nun auf einen Zeiger, der auf das Array zeigt?

Die Werte im HEX DUMP stimmen mit denen im Watches-Fenster überein wenn 
ich noch nichts in das Array geschrieben hab. Wenn ich jedoch jetzt 
zahlen in das Array schreibe Z.B
           1  2  3  4  5
index:     0  1  2  3  4

ämdert sich im HEX DUMP nichts! weshalb?

von DirkB (Gast)


Lesenswert?

Joe M. schrieb:
> zeigt &zeiger nun auf einen Zeiger, der auf das Array zeigt?

Nein! Nein! Nein!
Ein Array ist kein Zeiger.

Hast du denn auch mal wieder auf Go geklickt?

von Joe M. (jumper)


Lesenswert?

@ DirkB
Danke dir!
funktioniert jetzt! Keine Ahnung weshalb davor nicht ging!

von Uhu U. (uhu)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Den aber gibt es hier nicht.

Den gibt es wohl, nur ist er eine Konstante...

von DirkB (Gast)


Lesenswert?

Es gibt eine Adresse vom Array, aber keinen Ort, wo diese abgelegt ist.
Also gibt es auch keinen Zeiger.

von Uhu U. (uhu)


Lesenswert?

DirkB schrieb:
> Also gibt es auch keinen Zeiger.

Sieh dir die Array-Syntax genau an, dann wirst du sehen, daß man mit dem 
Namen eines Arrays dasselbe machen kann, wie mit einem Zeiger auf ein 
Array.

Der Grund ist, daß ein Array-Name eine Zeigerkonstante ist, wie 5 eine 
Integer-Konstante ist.

Diese Array-Pointer-Konstanten werden - wie andere Konstanten auch - 
üblicherweise als Immediate-Operanden direkt im Maschinencode 
gespeichert.

Das ist ein Stück der Eleganz von C.

von Rolf Magnus (Gast)


Lesenswert?

Uhu Uhuhu schrieb:
> Der Grund ist, daß ein Array-Name eine Zeigerkonstante ist, wie 5 eine
> Integer-Konstante ist.

Nein. Dann würde sizeof(Array) nämlich die Größe eines Zeigers 
zurückgeben, was es aber nicht tut. Außerdem ist &Array eben wie schon 
gesagt wurde nicht die Adresse eines Zeigers und auch nicht vom Typ 
"Zeiger auf Zeiger".
Es ist eher so, daß der Array-Name bei den meisten (aber eben nicht 
allen) Operationen, die man damit machen kann, implizit in einen Zeiger 
konvertiert wird, also eher so, wie man 5 auch einer double-Variable 
zuweisen kann und der Compiler dann automatisch eine 5.0 draus macht. 
Deshalb ist in der 5 aber nicht automatisch eine 5.0 enthalten, und 
genausowenig gibt's beim Array einen Zeiger.

> Diese Array-Pointer-Konstanten werden - wie andere Konstanten auch -
> üblicherweise als Immediate-Operanden direkt im Maschinencode
> gespeichert.

Das stelle ich mir bei einem lokalen Array etwas schwierig vor. Da ist 
die Adresse nämlich erst zur Laufzeit bekannt.

> Das ist ein Stück der Eleganz von C.

Auch wenn es wohl die Intention dahinter war, ist es meiner Meinung nach 
nicht besonders elegant. Das erkennt man auch daran, daß Arrays und 
Zeiger für Anfänger eines der am schwierigsten zu verstehenden Themen 
beim Erlernen der Sprache sind.

von Uhu U. (uhu)


Lesenswert?

Rolf Magnus schrieb:
> Dann würde sizeof(Array) nämlich die Größe eines Zeigers
> zurückgeben, was es aber nicht tut.

Das ist eine der wenigen Stellen, an denen die Vereinheitlichung nicht 
ganz klappt.

> Außerdem ist &Array eben wie schon gesagt wurde nicht die Adresse eines
> Zeigers

&konstante ist nicht definiert; es gibt sie nicht, weil Konstanten 
sozusagen allgegenwärtig sind.

> Das stelle ich mir bei einem lokalen Array etwas schwierig vor. Da ist
> die Adresse nämlich erst zur Laufzeit bekannt.

In dem Fall ist es ein konstanter Offset auf ein Indexregister, häufig 
dem Stackpointer - also kein wesentlicher Unterschied.

>> Das ist ein Stück der Eleganz von C.
>
> Auch wenn es wohl die Intention dahinter war, ist es meiner Meinung nach
> nicht besonders elegant. Das erkennt man auch daran, daß Arrays und
> Zeiger für Anfänger eines der am schwierigsten zu verstehenden Themen
> beim Erlernen der Sprache sind.

Andersrum wird ein Schuh draus: Das Konzept Variablenname ist relativ 
schwer verständlich und weil den Anfängern die Gemeinsamkeiten von 
Pointern und Array-Namen nicht frühzeitig durchsichtig gemacht werden, 
bleibt ein Array-Name undurchsichtig.

Zudem sollte man Fragen der Didaktik nicht mit Fragen Semantik 
vermengen.


Aus eigener Erfahrung kann ich nur sagen, daß mir das 
Array-/Pointer-Konzept auf Anhieb klar war, als ich die Beschreibung vor 
Urzeiten bei Kerninghan/Ritchie gelesen hatte. Reichlich ASM-Hintergrund 
war dazu natürlich überaus hilfreich.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Im Quelltext des Threadstarters wird

  &array

nicht verwendet. Sondern --und das ist ein essentieller Unterschied--

  &array[index]

Und damit ist die Diskussion ziemlich am Thema vorbei.

von Uhu U. (uhu)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Im Quelltext des Threadstarters wird
>
>   &array
>
> nicht verwendet. Sondern --und das ist ein essentieller Unterschied--
>
>   &array[index]
>
> Und damit ist die Diskussion ziemlich am Thema vorbei.

Das Unverständnis für Arrays und Pointer ist das Kernthema und das zu 
beseitigen, kann kaum am Thema vorbei sein...

von DirkB (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Im Quelltext des Threadstarters wird
>
>   &array
>
> nicht verwendet.

Aber im Memory-Fenster vom Debugger ;-)

von Rolf Magnus (Gast)


Lesenswert?

Uhu Uhuhu schrieb:
>> Außerdem ist &Array eben wie schon gesagt wurde nicht die Adresse eines
>> Zeigers
>
> &konstante ist nicht definiert; es gibt sie nicht, weil Konstanten
> sozusagen allgegenwärtig sind.

&Array gibt es aber. Und es ergibt wie bei jeder anderen Variable auch 
deren Adresse.

>> Das stelle ich mir bei einem lokalen Array etwas schwierig vor. Da ist
>> die Adresse nämlich erst zur Laufzeit bekannt.
>
> In dem Fall ist es ein konstanter Offset auf ein Indexregister, häufig
> dem Stackpointer - also kein wesentlicher Unterschied.

Wo unterscheiden sich denn hier Arrays von irgendwelchen anderen 
Variablen?  Bei denen spreche ich doch auch nicht davon, daß es da immer 
eine dazugehörige Pointerkonstante oder sowas gibt.
Mindestens seit C99 gibt's aber auch Beispiele, wo auch das mit dem 
konstanten Offset nicht klappt.
1
void func(int i, int j)
2
{
3
    int a[i];
4
    int b[j];
5
}

Hier ist auch der Offset zum Stackpointer erst zur Laufzeit bekannt.

>>> Das ist ein Stück der Eleganz von C.
>>
>> Auch wenn es wohl die Intention dahinter war, ist es meiner Meinung nach
>> nicht besonders elegant. Das erkennt man auch daran, daß Arrays und
>> Zeiger für Anfänger eines der am schwierigsten zu verstehenden Themen
>> beim Erlernen der Sprache sind.
>
> Andersrum wird ein Schuh draus: Das Konzept Variablenname ist relativ
> schwer verständlich und weil den Anfängern die Gemeinsamkeiten von
> Pointern und Array-Namen nicht frühzeitig durchsichtig gemacht werden,
> bleibt ein Array-Name undurchsichtig.

Was soll an Variablennamen denn schwer verständlich sein?
Was ich dagegen z.B. als für einen Anfänger schwer zu durchschauen 
empfinde, ist, warum bei:
1
#include <stdio.h>
2
void func(int array[10])
3
{
4
    printf("%d\n", sizeof array);
5
}
6
7
int main()
8
{
9
    int array[10];
10
    func(array);
11
}

nicht 10 ausgegeben wird. Und das liegt eben daran, daß heimlich aus dem 
Array ein Zeiger gemacht wird. Dazu kommt hier noch der "geniale" 
Schachzug bei, daß bei Funktionsparametern (aber nur dort) auf einmal 
die Array-Syntax verwendet wird, um einen Zeiger zu definieren und nicht 
etwa ein Array und daß die 10 in den eckigen Klammern einfach komplett 
ignoriert wird.

> Zudem sollte man Fragen der Didaktik nicht mit Fragen Semantik
> vermengen.

Genauso wie die Definition der Sprache und die darunterliegende 
Impelementation. In C ist definiert, daß das Array in einen Zeiger auf 
das erste Element konvertiert wird. Die Konstante mit der Adresse drin 
ist die Art, wie es meist implementiert wird. Solche 
Implementationsdetails sind aber für jemanden, der die Sprache lernt, 
erstmal irelevant.

> Aus eigener Erfahrung kann ich nur sagen, daß mir das Array-/Pointer-
> Konzept auf Anhieb klar war, als ich die Beschreibung vor Urzeiten bei
> Kerninghan/Ritchie gelesen hatte. Reichlich ASM-Hintergrund war dazu
> natürlich überaus hilfreich.

Ich weiß ehrlich gesagt gar nicht mehr, wie das bei mir war. Aber ich 
sehe in Foren und Newsgroups bei C-Einsteigern sehr viele Fragen, die 
erkennen lassen, daß Zeiger und Arrays nicht richtig verstanden wurden. 
Ich würde  schätzen, daß es mit Abstand der Teil ist, bei dem am 
häufigsten Verständisprobleme auftreten.

von Uhu U. (uhu)


Lesenswert?

C hat angefangen als eine Art Super-Assembler und für 
Assemblerprogrammierer ist ein Pointer wirklich nichts aufregendes.

Was K&R mit dieser Vereinheitlichung von Arrays und Pointern erreicht 
haben, ist uniforme Behandlung von Arrays, gleichgültig, ob sie über 
Pointer adressiert werden, oder nicht.
1
int a[5];
2
int *pa = a;

Mit der Zuweisung an pa geht die Längeniformation, die der Compiler zu a 
mitführt verloren, das paßte aber durchaus zur alten C-Philosophie, daß 
sich der Compiler um Feldgrenzen sowieso nicht kümmert.

Gewonnen wird mit dem Kniff, daß Arrays und Pointer (void * gab es in 
den frühen C-Versionen sowieso noch nicht) mit derselben Syntax 
bearbeitet werden können:
1
pa[5] == a[5]
2
*(pa + 5) == a[5]
3
*(pa + 5) == *(a + 5)

Die Array-Schreibweise wird damit auf die Pointer-Arithmetik 
zurückgeführt und für den Anfänger ist das m.A. eine unverzichtbare 
Einsicht, die den Umgang mit Pointern sehr erleichtert.

> Was ich dagegen z.B. als für einen Anfänger schwer zu durchschauen
> empfinde, ist, warum bei:
> ...
> nicht 10 ausgegeben wird.

Der Compiler speichert zu Arrays als Zusatzinformation die Länge in 
Elementen des Grundtyps - das muß er auf jeden Fall tun, denn anders 
kann er das Speicherlayout nicht brechnen.

Wenn die Array-Adresse einem Pointer zugewiesen wird, dann geht diese 
Zusatzinformation verloren, weil über Pointer eben nur der Grundtyp und 
irgendwelche Modifier gespeichert werden. Werte-Tracking ist zumindest 
sehr aufwendig, wenn nicht unmöglich und der C-Compiler sollte auf einer 
PDP-8 laufen mit 4096 Worten zu je 12 Bit, nicht auf einem heutigen 
Rechner mit Gigabytes RAM und Taktraten, von denen damals keiner zu 
träumen wagte.

> Solche Implementationsdetails sind aber für jemanden, der die Sprache
> lernt, erstmal irelevant.

Es macht zwar Mathematikern und Informatikern einen Höllenspaß, 
irgendwelche verzwickten Konstrukte völlig unvermittelt auf Anfänger 
herunterregnen zu lassen, aber didaktisch ist das - zumindest für meine 
Begriffe - grober Unfug.

Wie eigentlich immer, schadet ein Blick in die Geschichte auch hier 
nicht und liefert aufeinander aufbauende und leicht nachzuvollziehende 
Einsichten und wer so tut, als seien die Axiome schon immer da gewesen, 
der zieht tendenziell nur geschichtslose Trottel heran.

> Ich weiß ehrlich gesagt gar nicht mehr, wie das bei mir war. Aber ich
> sehe in Foren und Newsgroups bei C-Einsteigern sehr viele Fragen, die
> erkennen lassen, daß Zeiger und Arrays nicht richtig verstanden wurden.
> Ich würde  schätzen, daß es mit Abstand der Teil ist, bei dem am
> häufigsten Verständisprobleme auftreten.

Dem kann m.A. leicht abgeholfen werden, wenn man etwas Zeit in die 
Vermittlung der Hintergründe investiert.

von DirkB (Gast)


Lesenswert?

Trotzdem ergibt bei deinem Beispiel
&a etwas anderes als &pa

a = pa ist nicht erlaubt,
Und daraus folgt auch:
pa++ ist möglich, im Gegensatz zu a++

Denn es gibt keine Speicherstelle für die Adresse von a, auf die du von 
C aus zugreifen kannst.

von Uhu U. (uhu)


Lesenswert?

DirkB schrieb:
> Trotzdem ergibt bei deinem Beispiel
> &a etwas anderes als &pa

Ist das jetzt etwa völlig unerwartet?

> a = pa ist nicht erlaubt,

Hab ich das behauptet?

> pa++ ist möglich, im Gegensatz zu a++

Konstanten sind nun eben mal unveränderlich...

> Denn es gibt keine Speicherstelle für die Adresse von a, auf die du von
> C aus zugreifen kannst.

Habe ich das behauptet?

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Uhu Uhuhu schrieb:
> C hat angefangen als eine Art Super-Assembler und für
> Assemblerprogrammierer ist ein Pointer wirklich nichts aufregendes.
>
> Was K&R mit dieser Vereinheitlichung von Arrays und Pointern erreicht
> haben, ist uniforme Behandlung von Arrays, gleichgültig, ob sie über
> Pointer adressiert werden, oder nicht.
> int a[5];
> int *pa = a;

Ja, allerdings schafft das eine Inkonsistenz zu anderen Typen, wo es 
sowas nicht gibt. Der Grund dafür, das hinzunehmen, war vermutlich 
folgender:
1
int a[5];
2
int (*pa)[5] = &a;
3
(*pa)[2] = 10;

So ist die Behandlung des Arrays exakt gleich wie die von 
nicht-Array-Tpen. Es gibt nur einen Nachteil: Im Zeigertyp steht die 
Arraygröße drin, und ich kann ihn daher ausschließlich für Arrays der 
Größe 5 benuten. sizeof *pa ergibt 5*sizeof(int).
Also mußte man sich was einfallen lassen, wie man einen Zeiger bekommt, 
über den man auf Arrays zugreifen kann, ohne bei der Definition des 
Zeigers schon die Array-Größe festlegen zu müssen. So kam die Idee mit 
dem Zeiger auf das erste Element, und man hat dann in Konsequenz den 
Zugriff über den Zeiger noch gleich machen müssen wie über das Array, 
was aber leider auch nicht überall durchgezogen werden konnte. So 
ergeben sich noch mehr Inkonsistenzen. Ich sehe das ganze daher nicht 
als Genialität, sondern eher als notwendiges Übel.

Uhu Uhuhu schrieb:
> Die Array-Schreibweise wird damit auf die Pointer-Arithmetik
> zurückgeführt und für den Anfänger ist das m.A. eine unverzichtbare
> Einsicht, die den Umgang mit Pointern sehr erleichtert.

Meiner Ansicht nach ist es genau das Gegenteil. Es ist eine Hürde für 
das Verständnis von Arrays und Pointern.

Uhu Uhuhu schrieb:
> Wenn die Array-Adresse einem Pointer zugewiesen wird,

Du meinst die Adresse des ersten Elements. Die Array-Adresse hat zwar 
den selben Wert, aber einen anderen Typ.

> dann geht diese Zusatzinformation verloren, weil über Pointer eben nur
> der Grundtyp und irgendwelche Modifier gespeichert werden. Werte-Tracking
> ist zumindest sehr aufwendig, wenn nicht unmöglich

Bei Funktionsparametern ist es unmöglich, denn die Funktion kann ja 
jedesmal mit einer anderen Array-Größe aufgerufen werden.

Uhu Uhuhu schrieb:
>> Solche Implementationsdetails sind aber für jemanden, der die Sprache
>> lernt, erstmal irelevant.
>
> Es macht zwar Mathematikern und Informatikern einen Höllenspaß,
> irgendwelche verzwickten Konstrukte völlig unvermittelt auf Anfänger
> herunterregnen zu lassen, aber didaktisch ist das - zumindest für meine
> Begriffe - grober Unfug.

Ja, eben genau deshalb sollte man sich ja nicht darin verlieren, dem 
Lernenden alle Details zu erklären, wie die Sprache üblicherweise von 
einem Compiler implementiert wird, sondern erstmal auf Sprachebene 
bleiben. Man fängt ja auch nicht damit an, Funktionen über irgendwelche 
Stackframes und Registerzuordnungen zu erklären. Die sind (deutlich) 
später für ein tiefergehendes Verständnis durchaus hilfreich, aber nicht 
für den Anfänger. Programmiersprachen schaffen eine Abstraktionsebene, 
die ja gerade deshalb da ist, damit man sich mit diesen Details nicht 
beschäftigen muß.

>> Ich weiß ehrlich gesagt gar nicht mehr, wie das bei mir war. Aber ich
>> sehe in Foren und Newsgroups bei C-Einsteigern sehr viele Fragen, die
>> erkennen lassen, daß Zeiger und Arrays nicht richtig verstanden wurden.
>> Ich würde  schätzen, daß es mit Abstand der Teil ist, bei dem am
>> häufigsten Verständisprobleme auftreten.
>
> Dem kann m.A. leicht abgeholfen werden, wenn man etwas Zeit in die
> Vermittlung der Hintergründe investiert.

Wenn das für das Erlernen der Sprache notwendig ist, zeigt das aber, daß 
es sich um ein schwer veständliches Thema handelt.

von Uhu U. (uhu)


Lesenswert?

Rolf Magnus schrieb:
> Programmiersprachen schaffen eine Abstraktionsebene,
> die ja gerade deshalb da ist, damit man sich mit diesen Details nicht
> beschäftigen muß.

Abstraktionen sind gut, wenn man die Hintergründe verstanden hat, nicht 
umgekehrt. Die Sprachentwickler haben ja auch nicht ein paar 
Definitionen ausgeklinkt und anshließend nach Anwendungsfällen gesucht.

Was ich an den µCs so reizvoll finde, ist ihre Überschaubarkeit. So 
ähnlich war vor 40 Jahren die ganze Computerei.

Bei der Abstrahiererei wurde m.A. schon gerne mal übers Ziel 
rausgeschossen. Die Folge ist, daß man einen ewig komplizierten Kloß, 
dessen Struktur sich bestenfalls ganz langsam erschließt, oben auf einer 
mehr oder weniger simpel gestrickten Maschine liegen hat, der die Sicht 
auf das versperrt, was man mit seiner Anwendung eigentlich treibt.

Die Grundideen von C kann man jedenfalls sehr schön an einem ganz 
simplem Maschinenmodell regelrecht erfahrbar machen.

Aber diese Rangehensweise ist inkompatibel mit der Rausprüf-Ideologie...

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

> Uhu Uhuhu schrieb:
>> Die Array-Schreibweise wird damit auf die Pointer-Arithmetik
>> zurückgeführt und für den Anfänger ist das m.A. eine unverzichtbare
>> Einsicht, die den Umgang mit Pointern sehr erleichtert.
>
> Meiner Ansicht nach ist es genau das Gegenteil. Es ist eine Hürde für
> das Verständnis von Arrays und Pointern.

Meiner Meinung nach besteht das Hauptproblem, dass man im Umgang mit 
Neulingen nicht konsequent die Begriffe "Adresse" und "Pointer-Variable" 
trennt. Alleine durch diese sprachliche Unterscheidung lassen sich gut 
50% der ganzen Pointer-Probleme aus der Welt schaffen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.