Pointer auf Struct - Unterschiede

OP #5043655
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?
Gast #5043669
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.
OP #5043712
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..
#5043715
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).
#5043803
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. ;-)
OP #5043822
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?!
Gast #5043853
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.
#5043866
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.
OP #5043877
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;
Persönliche Seite #5043921
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.
Persönliche Seite #5043953
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.
OP #5043960
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?
Persönliche Seite #5043962
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?
#5043992
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.
#5044221
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren