Forum: Mikrocontroller und Digitale Elektronik Pointer auf Struct - Unterschiede


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Moin Moin..

Wo ist eigentlich der Unterschied? Kann es zur Laufzeit Fehler geben?
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
test_t ohne_ptr;
7
8
void read(test_t *stru){
9
}
10
11
/* GIBT ES HIER EINEN UNTERSCHIED <- ???*/
12
read(mit_ptr);
13
read(&ohne_ptr);

Kann es zur Laufzeit unterschiede geben? Wenn ich jetzt einen Pointer 
übergebe oder mit dem Adressoperator die Adresse vom Struct? Wo ist der 
Unterschied?

: Bearbeitet durch User
von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
im Prinzip ist es gleich. Nur ist hier noch ein Fehler drin, das der 
Pointer ins "nichts" Zeit. Man muss schon dafür sorgen der der Pointer 
wirklich auf eine Variable Zeigt.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> im Prinzip ist es gleich. Nur ist hier noch ein Fehler drin, das der
> Pointer ins "nichts" Zeit. Man muss schon dafür sorgen der der Pointer
> wirklich auf eine Variable Zeigt.

Wie würde das Aussehen?

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Eigentlich ist das nicht gleich.

Im ersten Fall wird eine Kopie von deinem Struct erzeugt und im Falle 
des Pointers nicht.

Daten im Struct kannst du also nur mit einem Pointer verändern. Nebenbei 
braucht das neu angelegte Struct auch evtl. mehr Platz im Speicher als 
ein Zeiger.

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Meh, vergiss meinen Post, ich brauch Kaffee

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Wie würde das Aussehen?


test_t ohne_ptr;
test_t *mit_ptr = &ohne_ptr;

von Kaj (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Wie würde das Aussehen?
1
test_t ohne_ptr;
2
test_t *mit_ptr = &ohne_ptr;
3
4
test_t *new_ptr = new test_t;  //  C++
5
test_t *malloc_ptr1 = (test_t *)malloc(sizeof(test_t));  //  C/C++
6
test_t *malloc_ptr2 = malloc(sizeof(test_t));  //  C

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Kaj schrieb:
> Jan H. schrieb:
>> Wie würde das Aussehen?
>
1
> test_t ohne_ptr;
2
> test_t *mit_ptr = &ohne_ptr;
3
> 
4
> test_t *new_ptr = new test_t;  //  C++
5
> test_t *malloc_ptr1 = (test_t *)malloc(sizeof(test_t));  //  C/C++
6
> test_t *malloc_ptr2 = malloc(sizeof(test_t));  //  C
7
>

Ich kann es aber ohne Fehler Kompilieren. Was passiert denn wenn ich es 
einfach nur so übergebe?
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
7
8
read(mit_ptr){
9
}

Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen 
dann..

von Phantomix X. (phantomix) Flattr this


Bewertung
0 lesenswert
nicht lesenswert
"mit_ptr" ist auch nur eine Variable

Ja, eine Adressvariable, semantisch gesehen halt ein Pointer.
Uninitialisiert zeigt es halt irgendwohin*, nicht auf eine vorhandene 
Speicherstruktur.


* vermutlich auf Adresse 0, hängt von den verwendeten 
Initialisierungsroutinen ab (das was vor der main-Funktion schon 
passiert).

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
7
8
read(mit_ptr){
9
}
>
> Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen
> dann..

Nach ISO C ist es genau umgekehrt: Er kann nichts falsch machen, denn 
jede beliebige Reaktion auf diesen Code gilt als korrekt (Unter der 
Annahme, dass read() den Zeiger dereferenziert).
Das nennt sich "undefined behavior" (Undefiniertes Verhalten). Der 
Zeiger ist nicht initialisiert, das heißt, es steht irgendeine mehr oder 
weniger zufällige Adresse darin. Wenn du den dereferenzierst, ohne ihm 
vorher einen gültigen Wert zu geben, rufst du undefiniertes Verhalten 
hervor, und dann kann nach ISO C alles passieren.
In der Newsgroup comp.std.c sprach man davon, dass dann Dämonen aus 
deiner Nase kommen können ( 
http://www.urbandictionary.com/define.php?term=nasal%20demons ). Nach 
ISO C wäre das tatsächlich eine erlaubte Reaktion auf deinen Code. ;-)

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Jan H. schrieb:
>
1
> typedef struct test{
2
>   Uint8_t var;
3
> }test_t;
4
> 
5
> test_t *mit_ptr;
6
> 
7
> 
8
> read(mit_ptr){
9
> }
10
>
>>
>> Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen
>> dann..
>
> Nach ISO C ist es genau umgekehrt: Er kann nichts falsch machen, denn
> jede beliebige Reaktion auf diesen Code gilt als korrekt (Unter der
> Annahme, dass read() den Zeiger dereferenziert).
> Das nennt sich "undefined behavior" (Undefiniertes Verhalten). Der
> Zeiger ist nicht initialisiert, das heißt, es steht irgendeine mehr oder
> weniger zufällige Adresse darin. Wenn du den dereferenzierst, ohne ihm
> vorher einen gültigen Wert zu geben, rufst du undefiniertes Verhalten
> hervor, und dann kann nach ISO C alles passieren.
> In der Newsgroup comp.std.c sprach man davon, dass dann Dämonen aus
> deiner Nase kommen können (
> http://www.urbandictionary.com/define.php?term=nasal%20demons ). Nach
> ISO C wäre das tatsächlich eine erlaubte Reaktion auf deinen Code. ;-)

Das heißt, würde ich mit einem Pointer auf einem struct arbeiten wollen, 
so benötige ich doppelten Speicherplatz?
1
typedef struct{
2
  
3
  int var;
4
}test_t;
5
6
test_t ohne_ptr;
7
test_t *mit_ptr_0;
8
test_t *mit_ptr = &ohne_ptr;

Ich muss ja die Struktur gezwungener Maßen zwei mal anlegen?!

von Michael F. (sharpals)


Bewertung
0 lesenswert
nicht lesenswert
Im quellcode ja.

Aber zu laufzeit, ist es wirklich nur eine struktur, auf die dann der 
zeiger gesetzt wird.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Michael F. schrieb:
> Im quellcode ja.
>
> Aber zu laufzeit, ist es wirklich nur eine struktur, auf die dann der
> zeiger gesetzt wird.

Wird das bei der Speicherplatzberechnung mit einfließen die beiden 
Structs?

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Ich muss ja die Struktur gezwungener Maßen zwei mal anlegen?!

Nein, du must sie nur einmal anlegen. Ein Zeiger auf deine Struktur ist 
was völlig anderes. Du kannst das Wort Zeiger wortwörtlich nehmen. Der 
Zeigt, wo deine Struktur liegt. Deswegen musst du ihn auch auf eine 
angelegte Variable "einstellen" sprich zuweisen. Sonst zeigt der einfach 
irgend wo hin und behauptet, das wäre deine struct.


Wenn du einen Zeiger an eine Funktion übergeben muss, legt man 
üblicherweise nicht erst einen an, sondern benutzt den Adressoperator &. 
Die Variante kennst du ja schon.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Okay.

Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch 
doppelten Speicher oder wird das nicht mit einberechnet?
Sprich der Compiler weiß, dass er dort nur hinzeigen soll?

von Rolf M. (rmagnus)


Bewertung
1 lesenswert
nicht lesenswert
Jan H. schrieb:
> Okay.
>
> Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch
> doppelten Speicher oder wird das nicht mit einberechnet?

Welche zweifache Anlegung? Deine Struktur gibt es nur ein mal. Da 
kannst du auch eine Million Zeiger drauf zeigen lassen, und doch ist die 
Struktur nur einmal vorhanden. Natürlich brauchen die Zeiger selbst auch 
Platz, aber eben nur den Platz für eine Adresse, nicht für die Daten 
selbst.

> Sprich der Compiler weiß, dass er dort nur hinzeigen soll?

Stell dir mal vor, du fährst an einem Schild vorbei, das dir sagt, in 
welche Richtung du zu einer Stadt fahren musst. Auch wenn um die Stadt 
herum viele Schilder stehen, die in Richtung dieser Stadt zeigen, gibt 
es die Stadt selbst dennoch nur einmal.

: Bearbeitet durch User
von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Jan H. schrieb:
>> Okay.
>>
>> Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch
>> doppelten Speicher oder wird das nicht mit einberechnet?
>
> Welche zweifache Anlegung? Deine Struktur gibt es nur ein mal. Da
> kannst du auch eine Million Zeiger drauf zeigen lassen, und doch ist die
> Struktur nur einmal vorhanden. Natürlich brauchen die Zeiger selbst auch
> Platz, aber eben nur den Platz für eine Adresse, nicht für die Daten
> selbst.
>
>> Sprich der Compiler weiß, dass er dort nur hinzeigen soll?
>
> Stell dir mal vor, du fährst an einem Schild vorbei, das dir sagt, in
> welche Richtung du zu einer Stadt fahren musst. Auch wenn um die Stadt
> herum viele Schilder stehen, die in Richtung dieser Stadt zeigen, gibt
> es die Stadt selbst dennoch nur einmal.

Wie groß ist dann der Zeiger?
1
test_t *mit_ptr = &ohne_ptr;

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Wie groß ist dann der Zeiger?
> test_t *mit_ptr = &ohne_ptr;

So groß, dass er die Adresse eines Objekts aufnehmen kann. Wieviel das 
ist, hängt vom Prozessor und der Größe dessen Adressraums ab. Bei µCs 
wird er meist 2 oder 4 Bytes groß sein.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Jan H. schrieb:
>> Wie groß ist dann der Zeiger?
>> test_t *mit_ptr = &ohne_ptr;
>
> So groß, dass er die Adresse eines Objekts aufnehmen kann. Wieviel das
> ist, hängt vom Prozessor und der Größe dessen Adressraums ab. Bei µCs
> wird er meist 2 oder 4 Bytes groß sein.

Ist er bei einem 8 Bit µC nicht nur ein Byte groß?

von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Ist er bei einem 8 Bit µC nicht nur ein Byte groß?

nein, weil sonst könnte man nur 256 byte ram verwenden.

von Naj H. (janiiix3)


Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Jan H. schrieb:
>> Ist er bei einem 8 Bit µC nicht nur ein Byte groß?
>
> nein, weil sonst könnte man nur 256 byte ram verwenden.

Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?

von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?

allgemein von den Möglichkeiten der Hardware.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?

Wie ich schon schrieb: Sie ist abhängig von der Größe des Adressraums. 
Letztendlich bestimmt die Prozessor-Architektur das. Auf einem 64-Bit-PC 
ist ein Zeiger z.B. 8 Bytes groß, unabhängig davon, ob da nun 1 GB RAM 
oder 1 TB drin steckt.

von Naj H. (janiiix3)


Bewertung
-1 lesenswert
nicht lesenswert
Peter II schrieb:
> Jan H. schrieb:
>> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?
>
> allgemein von den Möglichkeiten der Hardware.

Kannst du das mal bitte etwas genauer erklären..?

von N. G. (newgeneration) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Jan H. schrieb:
> Wie groß ist dann der Zeiger?test_t *mit_ptr = &ohne_ptr;

Wenn man keine ABI-Referenz zur Hand hat, dann tuts auch ein simples 
sizeof():
1
int main() {
2
    printf("No Bytes of a pointer: %zu\n", sizeof(void*));
3
}
Dieser Test ergibt auf dem PC (Win 7, 64bit)
1
No Bytes of a pointer: 8
Also 64bit-Pointer

Auf einem AVR (gut, man würde kein printf() nehmen) ergibt es:
1
No Bytes of a pointer: 2
Also 16bit-Pointer


Jan H. schrieb:
> Peter II schrieb:
>> Jan H. schrieb:
>>> Ist er bei einem 8 Bit µC nicht nur ein Byte groß?
>>
>> nein, weil sonst könnte man nur 256 byte ram verwenden.
>
> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?

Nein, andersherum wird ein Schuh draus.
Die Größe der Pointer gibt den maximal adressierbaren Speicher an.
Diese Größe muss dann sinnvoll gewählt werden.

Mit freundlich Grüßen,
N.G.

von Naj H. (janiiix3)


Bewertung
-1 lesenswert
nicht lesenswert
Warum zeigt er mir jetzt 1 Byte für einen char an?
1
char *ptr = NULL;
2
3
int main(void){  
4
  printf("Size of Pointer %d\n\r",sizeof(*ptr));
5
}

: Bearbeitet durch User
von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Warum zeigt er mir jetzt 1 Byte für einen

weil der * zu viel ist

von N. G. (newgeneration) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Warum zeigt er mir jetzt 1 Byte für einen
> char an?
> char *ptr = NULL;
>
> int main(void){
>   printf("Size of Pointer %d\n\r",sizeof(*ptr));
> }

Weil du den Pointer de-referenzierst. Damit bekommst du die Größe vom 
Typ, auf den der Pointer zeigt (hier char).
Also lass das Sternchen vor ptr im sizeof weg

Mit freundlichen Grüßen,
N.G.

von Naj H. (janiiix3)


Bewertung
-1 lesenswert
nicht lesenswert
N. G. schrieb:
> Jan H. schrieb:
>> Warum zeigt er mir jetzt 1 Byte für einen
>> char an?
>> char *ptr = NULL;
>>
>> int main(void){
>>   printf("Size of Pointer %d\n\r",sizeof(*ptr));
>> }
>
> Weil du den Pointer de-referenzierst. Damit bekommst du die Größe vom
> Typ, auf den der Pointer zeigt (hier char).
> Also lass das Sternchen vor ptr im sizeof weg
>
> Mit freundlichen Grüßen,
> N.G.

Okay. Wieso ist der Zeiger aber größer als der Eigentliche 
Speicherbereich?
Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er 
nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die 
Adresse aufzunehmen?

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Wieso ist der Zeiger aber größer als der Eigentliche Speicherbereich?
> Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er
> nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die
> Adresse aufzunehmen?

Überleg' mal. Wenn ein Pointer so groß wäre wie das Objekt, auf das er 
zeigt, würde das die Anzahl damit verwaltbarer Objekte beeinflussen.

Bei Deinem 1-Byte-Beispiel könntest Du also nur 256 chars damit 
verwalten.

Na? Klingelt's?

: Bearbeitet durch Moderator
von Kaj (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Das würde doch ausreichen um die
> Adresse aufzunehmen?
Wie willst du mit einem Byte 4GB (2^32 - 1 Byte) RAM adressieren?

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jan H. schrieb:
> Okay. Wieso ist der Zeiger aber größer als der Eigentliche
> Speicherbereich?
> Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er
> nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die
> Adresse aufzunehmen?

Du musst dich von der Vorstellung verabschieden, dass die Größe eines 
Zeigers irgendwas mit der Größe des Objekts zu tun hat, auf das er 
zeigt.
In einem Zeiger steht eine Adresse, d.h. er ist so groß wie eine 
Adresse. Ob an dieser Adresse nun ein Byte steht oder eine 10 kB große 
komplexe Struktur, hat keinen Einfluss darauf, wie groß die Adresse 
selber ist.

von Michael F. (sharpals)


Bewertung
0 lesenswert
nicht lesenswert
Oder stell es dir, wie eine langes straße vor und dein pointer soll auf 
das jeweilige haus zeigen. Ob das haus groß , oder klein ist , spielt 
keine rolle.

Dasselbe macht der zeiger auch, er gibt an, an welcher speicherstelle 
das gesuchte liegt.

Hast du eine CPU mit linearen speicher, dann muß er eben so groß sein, 
daß er wiklich auf alle zellen zeigen kann.

Ist es eine segmentierte CPU, dann ist er so froß, wie das segment ist.

Aber hier bei den Atmels, sind es einfach lineare adressen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.