Liebe Profis, als "Zeiger Lehrling :-)" brauche ich dringend Unterstützung ! In dem gegenständlichen Beispiel wird am Anfang ein Zeiger deklariert und mit dem Wert 0 initialisiert. struct eeprom_giess *gpEEPROM = (struct eeprom_giess*)0; Das heißt doch, dass gpEEPROM ein Zeiger ist und eine Adresse beinhaltet welche auf die erste Stelle im EEProm verweist. Daher ist mir auch klar, dass in der Routine void get_flower_name ... nur gpEEPROM ohne "&" weitergegeben wird, da es sich ja schon um eine Adresse handelt. Aber warum wurde mit der oben angeführten Definition auch ein Array deklariert ? gpEEPROM[index] und warum wird in der Routine void print_csv das "&" verwendet wenn es sich doch schon um einen Zeiger handelt.
Gast
#4868813
Hm, ohne die Definition des Structes zu kennen ist das ein wenig Rätselraten. Andreas S. schrieb: > Das heißt doch, dass gpEEPROM ein Zeiger ist und eine Adresse beinhaltet > welche auf die erste Stelle im EEProm verweist. Nicht so ganz, in der Struct steht noch ein wenig mehr als nur die Adresse im Eeprom. Warscheinlich ist das Eeprom mit Daten des Structs vollgeknallt und der Autor greift einfach hart auf die Adressen zu. Das ist nicht schön, funktioniert aber unter gewissen Bedingungen. Wie gesagt, ohne Definition des Structs... Grüße,
Gast
#4868816
Hast du dich schon mit Zeigerarithmetik und Zeigerdreferenzierung beschäftigt?
Andreas S. schrieb: > Aber warum wurde mit der oben angeführten Definition auch ein Array > deklariert ? gpEEPROM[index] Das ist im Code keine Deklaration, sondern ein Zugriff. Such dir ein C Tutorial für Pointer. Das wird dich bei C ewig beschäftigen und zum verzweifeln bringen, wenn du die Grundlagen nicht verstanden hast.
test schrieb: > Hast du dich schon mit Zeigerarithmetik und Zeigerdreferenzierung > beschäftigt? und Michael .. schrieb: > Such dir ein C Tutorial für Pointer und wie ... ich hatte auch geglaubt es so halbwegs verstanden zu haben. Aber dieses Beispiel ???? nicht"Gast" schrieb: > Wie gesagt, ohne Definition des Structs... struct eeprom_giess { unsigned char automatik; uint16_t pump_on; uint16_t pump_off; char name[16]; uint16_t seconds_on; uint16_t hours_off; };
Hallo, vollständigkeitshalber der gesamte Header !
Gast
#4868859
Zeiger sind immer wieder ein Spass auch nach Jahren, aber vielleicht hilft das hier: http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/012_c_zeiger_001.htm#mjee28a882ef9125d2c4cc49121b2c65c1 Da sind eigentlich alle Infos drin die du suchst... Hoffe es hilft dir! Schau dir auch mal die "main.h", da ist die Datenstruktur "struct eeprom_giess" definiert auf den der Zeiger gpEEPROM nachher wahrscheinlich zeigen soll.
Point schrieb: > Schau dir auch mal die "main.h", da ist die Datenstruktur "struct > eeprom_giess" definiert ... eben nicht !!! "main.h" das ist die vorhin eingestellte Headerdatei "header.c" und darin ist die Struktur nur deklariert ? Definitionen zu dieser Struktur finden sich nur im Hauptprogramm und haben keinen Bezug zu gpEEPROM ??? Ich danke dir für den Link. LG
Gast
#4868875
Andreas S. schrieb: > Aber warum wurde mit der oben angeführten Definition auch ein Array > deklariert ? gpEEPROM[index] Weil in C Pointer und Arrays eng verwandt sind, wenn auch nicht identisch (bei einem Array wird Speicher für die Nutzdaten reserviert, bei einem Pointer nicht). Aber beim Verwenden kann man einen Zeiger genauso wie ein Array nutzen; man muß nur sichergestellt haben, daß irgendwo der Speicher alloziert wurde. Sieht man übrigens oft, wenn man einen Pointer hat und den Speicher dann per malloc reserviert - und dann der Zeiger wie ein Array genutzt wird. Oder auch, wenn man ein Array an eine Funktion übergibt - das verflacht dann zu einem Zeiger, weswegen man die Längeninformation dabei normalerweise als zusätzliche Variable mitgibt, wenn man das braucht. > und warum wird in der Routine void print_csv das "&" verwendet wenn es > sich doch schon um einen Zeiger handelt. Weil dort wird erst der Zeiger dereferentiert wird, dann auc das struct geguckt und die Adresse von einer spezifischen Variablen rangeholt wird. &gpEEPROM[i].pump_on im Einzelnen erklärt: - nimm den Zeiger gpEEPROM - addiere i-mal die Größe seines Datentyps drauf (d.h. gehe i von diesen structs weiter) - bei dem struct, wo man dann ist, nimm die Variable pump_on - und besorg Dir mit dem & davon jetzt die Adresse. Völlig übliches C-Idiom.
Nop schrieb: > man muß nur sichergestellt haben, daß > irgendwo der Speicher alloziert wurde. das muss aber anscheinend bei einem EEProm nicht zwingend geschehen, bzw. ist das in diesem Fall nicht gemacht worden ? Nop schrieb: > Weil dort wird erst der Zeiger dereferentiert wird, das heißt "&" bedeutet in diesem Fall Dereferentierung und neue Adresse ?
Gast
#4868911
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
hier wird doch der Speicherinhalt beginnend an der Adresse "&flower" + sizeof(struct eeprom_giess) (Typ struct eeprom_giess) aufs Eeprom beginnend an der Speicherstelle "&gpEEPROM[index]" + sizeof(struct eeprom_giess) geschrieben. Da iss doch der Zusammenhang!? Oder meinst du was anderes? Die Funktion eeprom_write_block schreibt bestimmt einfach stumpf an die Stelle im Eeprom die angegeben ist mit der Länge sizeof(struct eeprom_giess). Hast du das gemeint?
Gast
#4868912
int myvar = 0; // die normale Variable brauchen wir später 1.) Deklaration und Initialisierung int *ptr_myvar; // Zeiger vom Typ int deklarieren (zeigt noch auf nix) ODER int *ptr_myvar = (int *)0x0100; // deklarieren und initialisieren in einem an Adresse 0x0100 ODER int *ptr_myvar = &myvar; //deklarieren und initialisieren in einem mit Variable myvar 2.) in der Anwendung ptr_myvar = &myvar; // Zeiger ptr_myvar ADRESSE von myvar zuweisen *ptr_myvar = myvar; // Zeiger ptr_myvar WERT von myvar zuweisen *ptr_myvar = &myvar; // Zeiger ptr_myvar ADRESSE von myvar als Wert zuweisen ptr_myvar = myvar; // Zeiger ptr_myvar WERT von myvar als ADRESSE zuweisen
Nop schrieb: > Autor: > > Nop (Gast) nach kurzer Überlegung noch eine Frage: Wie unterscheidet der Compiler bei '&' zwischen 1) Dereferentierung und neue Adresse bzw. 2) Adresse des Zeigers ?
Gast
#4868917
Andreas S. schrieb: > das heißt "&" bedeutet in diesem Fall Dereferentierung und neue Adresse > ? die funktion 'eeprom_read_block' braucht vermutlich als zweiten Parameter eine Adresse. Das '&' ist hier ein Adressoperator.
test schrieb: > die funktion 'eeprom_read_block' braucht vermutlich als zweiten > Parameter eine Adresse. das stimmt, aber gpEEPROM beinhaltet doch schon eine Adresse ?? Das ist ja genau der Punkt den ich so schwer verstehe :-( struct eeprom_giess *gpEEPROM = (struct eeprom_giess*)0; struct eeprom_giess *gpEEPROM - Zeiger deklarieren (struct eeprom_giess*)0; dezimal 0 in Adresse umwandeln
Victor Vector schrieb: > *ptr_myvar = &myvar; // Zeiger ptr_myvar ADRESSE von myvar als Wert > zuweisen darüber muss ich noch nachdenken ... Was bedeutet das, wenn in einem Zeiger ein Wert steht ?
Gast
#4868953
Andreas S. schrieb: > das stimmt, aber gpEEPROM beinhaltet doch schon eine Adresse ?? Das hier
1 | |
musst Du dir so denken
1 | |
neben Zeigerarithmetik, Zeigerdereferenzierung musst Du dich auch unbedingt noch mit Operatorenprioritäten beschäftigen.
Victor Vector schrieb: > int *ptr_myvar = &myvar; //deklarieren und initialisieren in einem mit > Variable myvar ... Initialisierung mit der Adresse von myvar - oder ?
test schrieb: > musst Du dir so denken > &(gpEEPROM[i].pump_on) jetzt wird es heller :-)
zwischendurch vielen Dank für eure Unterstützung !!
Gast
#4869123
ptr_myvar = &myvar; // Zeiger ptr_myvar ADRESSE von myvar zuweisen
*ptr_myvar = myvar; // Zeiger ptr_myvar WERT von myvar zuweisen
Diese beiden Beispiele werden häufig gebraucht.
*ptr_myvar = &myvar; // Zeiger ptr_myvar ADRESSE von myvar als Wert
zuweisen
ptr_myvar = myvar; // Zeiger ptr_myvar WERT von myvar als ADRESSE
zuweisen
Diese beiden Beispiele sind SYNTAKTISCH korrekt, ergeben aber fast nie
einen Sinn im Programmkontext.
---------------------------------
var repräsentiert den Wert der Variablen
&var repräsentiert die Adresse der Variablen
ptr_var repräsentiert die Adresse des Zeigers
*ptr_var repräsentiert den Wert, auf den der Zeiger zeigt
*var und &ptr_var sind beide syntaktisch falsch
---------------------------------
Anwendungsbeispiel:
int var[] = {0,1,2,3} // array mit 4 Werten
int *ptr_var = var[0]; // ptr_var zeigt jetzt auf den ersten Wert im
array
ptr_var++; // ptr_var zeigt jetzt auf den 2. Wert im array
ptr_var++; // ptr_var zeigt jetzt auf den 3. Wert im array
Obwohl ++ immer um 1 erhöht ist springt der Zeiger bei ++ um 4 Byte, da
er vom Typ int ist. Der Zeiger "weiss" um sein Datenformat (eigendlich
weiss es der Compiler). Bei Funktionsaufrufen kann man das nutzen, um
nur einen Zeiger auf ein komplexes Datenformat als Parameter zu
übergeben statt viele Einzelparameter (z.B. ein struct).
Aber nichts ohne Ausnahme:
void *ptr_var ist ein Zeiger ohne Datenformat, der auf ein beliebiges
Format gecastet werden kann. Aber nichts überstürzen !
Gast
#4869363
Victor Vector schrieb: > *var und &ptr_var sind beide syntaktisch falsch nein &ptr_var ist nicht falsch, das ist die Adresse des Zeigers. Kann man beispielsweise gebrauchen, wenn man den Zeiger by reference übergibt, etwa für eine verlinkte Liste, wenn die ohne Dummy-Head-Element realisiert ist.
übersetze einfach *<irgendwas> = "Zeiger_auf"<irgendwas> &<irgendwas> = "Adresse_von"<irgendwas> und dann verinnerlichen, dass jedes Datenobjekt irgendwo im Speicher abgelegt wird. Jedes Datenobjekt halt also eine Adresse, wo es im Speicher liegt. Und diese Adresse kann man halt erreichen mit &<irgendwas>. und wer schaut auf dieses Datenobjekt? Natürlich ein Zeiger. Also zeigt ein Zeiger mit *<irgendwas> genau auf das Datenobjekt, welches an der Adresse &<irgendas> abgelegt ist.
Nop schrieb: > Weil in C Pointer und Arrays eng verwandt sind, wenn auch nicht > identisch (bei einem Array wird Speicher für die Nutzdaten reserviert, > bei einem Pointer nicht). Beim Array gibt es keinen (von C zugreifbaren) Ort, an dem die Adresse abgespeichert ist. > Aber beim Verwenden kann man einen Zeiger > genauso wie ein Array nutzen; Vorsicht. Der Arrayname ergibt die Adresse vom ersten Element des Arrays. Mehr nicht. Mit dieser Adresse kannst du dann arbeiten. Du kannst einem Array keinen neuen Bereich zuweisen, demnach sind Größe und Ort fest, Post/Pre-Inkrtement geht auch nicht. Der Adressoperator & ergibt unterschiedliche Werte und Typen und auch sizeof() liefert andere Werte. Der Compiler macht aus einem Arrayzugriff mit [] erstmal eine Dereferenzierung mit *
Gast
#4869609
Dirk B. schrieb: > Du kannst einem Array keinen neuen Bereich zuweisen, demnach sind Größe > und Ort fest, Post/Pre-Inkrtement geht auch nicht. Ja sicher, das folgt ja alles daraus, daß bei einem Array auch Speicher alloziert wird, bei einem Pointer nicht. Das mit Inkrement ist allerdings ein weiterer Gesichtspunkt, ja. Man kann aber z.B. auch einen Pointer mit den eckigen Klammern wie ein Array nutzen, die Klammern sind syntaktischer Zucker. Dirk B. schrieb: > Der Adressoperator & ergibt unterschiedliche Werte und Typen Gut, ich hab auch noch nie bei einem Array den Adreßoperator benutzt. > und auch sizeof() liefert andere Werte. Ja, weil bei einem Array der Speicher alloziert wird und der Arrayname nur ein Alias ist, während bei einem Pointer die Größe eines Zeigers auf der jeweiligen Plattform zurückkommt.
Nop schrieb: > Man kann aber z.B. auch einen Pointer mit den eckigen Klammern wie ein > Array nutzen, die Klammern sind syntaktischer Zucker. Wieso auch? Das hört sich so besonders an. Du kannst eine Adresse (ob vom Pointer oder Arraynamen) dereferenziern. Das kannst du mit dem * Operator oder (als Zucker) mit den [] machen. Nop schrieb: > Gut, ich hab auch noch nie bei einem Array den Adreßoperator benutzt. Ich auch nicht, aber schau mal in Anfängerforen beim Einlesn von C-Strings nach. "Wieso ist das überflüssig, es geht doch!" liest man dann da.
Liebe Profis, vielen, vielen Dank für eure Hilfe. Ihr habt mir sehr geholfen und ich kann leider nicht behaupten - ich hätte auch selber drauf kommen können :-) Eine ergänzende Frage hätte ich noch: Nop schrieb: > Man kann aber z.B. auch einen Pointer mit den eckigen Klammern wie ein > Array nutzen, die Klammern sind syntaktischer Zucker. Das war für mich eben unverständlich woher das Zeigerarray kommt welches gar nicht definiert wurde. eeprom_read_block(&schwelle, &gpEEPROM[i].pump_on, sizeof(schwelle)); im Detail: &gpEEPROM[i].pump_on übersetzt dank eurer Hilfe zu &(gpEEPROM[i].pump_on) soweit war das dann klar für mich mit Ausnahme der [] Klammer, was aber vermutlich nur bedeutet: &((gpEEPROM * i).pump_on - hoffe ich jedenfalls :-)
Gast
#4869667
Andreas S. schrieb: > &(gpEEPROM[i].pump_on) soweit war das dann klar für mich mit Ausnahme > der [] Klammer, > was aber vermutlich nur bedeutet: > &((gpEEPROM * i).pump_on - hoffe ich jedenfalls Nee, das nicht. Der Ausdruck "gpEEPROM[i]" ist dasselbe wie *(gpEEPROM + i). Man kann daher "&(gpEEPROM[i].pump_on)" ohne eckige Klammern auch so schreiben: &((*(gpEEPROM + i)).pump_on) oder so: &((gpEEPROM + i)->pump_on)
Nop schrieb: > Man kann aber z.B. auch einen Pointer mit den eckigen Klammern wie ein > Array nutzen, die Klammern sind syntaktischer Zucker. Das geht sogar noch weiter
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
Nop schrieb: > Der Ausdruck "gpEEPROM[i]" ist dasselbe wie *(gpEEPROM +i) der richtigkeitshalber müsste es nicht eher so sein?
1 | |
oder stehe ich gerade auf dem Schlauch?
Gast
#4869765
Dirk B. schrieb: > Das geht sogar noch weiter Ja, immer wieder gern gesehen bei obfuscated code contests. :-) Michael .. schrieb: > der richtigkeitshalber müsste es nicht eher so sein? Nee, Pointerarithmetik addiert automatisch die Größe des Datentyps dazu und nicht Bytes. Beispiel: Bei "char *p1" mit der Annahme p1==8 ergäbe p1+1 dann 9. Bei uint32_t *p2 mit der Annahme p2==8 ergäbe p2+1 dann 12. Das mit dem sizeof brauchste bei malloc, etwa um auf einen uint32-t-Pointer 5 uint32_t zu allozieren: uint32_t *p3; p3 = malloc(5 * sizeof(uint32_t));
Gast
#4869790
Nop schrieb: > uint32_t *p3; p3 = malloc(5 * sizeof(uint32_t)); Ach ja, und im Unterschied dazu dann noch calloc: p3 = calloc(5, sizeof(uint32_t)); Das ist schon ein hirnrissiger Teil der C-Standardbibliothek, daß man gleichartige Funktionen mit verschiedener API realisiert hat.
Michael .. schrieb: > Nop schrieb: >> Der Ausdruck "gpEEPROM[i]" ist dasselbe wie *(gpEEPROM +i) > > der richtigkeitshalber müsste es nicht eher so sein? >
1 | |
> oder stehe ich gerade auf dem Schlauch? Bei der Arrayschreibweise gesht du ja auch davon aus, dass immer die richtige Anzal Bytes weiter gezählt wird. Und aus Dirk B. schrieb: > // aus > c = feld[i]; > // macht der Compiler > c = *(feld+i); folgt dann, dass dies auch bei der normalen Zeigerarithmetik so ist.
Nop schrieb: > &((*(gpEEPROM + i)).pump_on) Michael .. schrieb: > *(gpEEPROM +sizeof(eeprom_giess)*i) hilft beides zu meinem Verständnis ! Vielen Dank nochmals an Alle !!!
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.