Forum: Compiler & IDEs Frage zur Wertübergabe an eine Funktion bei Strukturen


von S. L. (lonci)


Lesenswert?

Hallo!
Ich möchte mir eine "RTC" programmieren und übergebe an die Funktion 
leap_year die Adresse des Strukturelements year.

Meine Frage: Warum muss meine Pointervariable *year_ptr vom Datentyp 
unsigned int sein? Der Datentyp der Strukturelemente ist doch eigentlich 
RTC oder?
1
#include <avr/io.h>
2
3
typedef struct
4
{
5
  unsigned int second;    // value of the actual second
6
  unsigned int minute;    // value of the actual minute
7
  unsigned int hour;      // value of the actual hour
8
  unsigned int monthDay;    // value of the actual day in the month
9
  unsigned int month;      // value of the actual month
10
  unsigned int year;      // value of the actual year
11
}RTC;              // Datatype = RTC
12
13
/*** Funktion Schaltjahr berechnen. (Parameterübergabe call by reference) ***/
14
int check_leapyear (unsigned int *year_ptr)
15
{
16
  unsigned int year_value = *year_ptr;
17
  
18
  if ( (year_value % 4 == 0 && year_value % 100 != 0) || (year_value % 400 == 0) )
19
    return 29;
20
}
21
22
RTC time, date;          // Deklaration der Variablen time und date vom Datentyp RTC
23
int x, schaltjahr = 0;
24
25
int main(void)
26
{
27
  time.second    = 0;    // Initialisierungswert = 0
28
  time.minute    = 0;    // Initialisierungswert = 0
29
  time.hour    = 0;    // Initialisierungswert = 0
30
  date.monthDay  = 1;    // Initialisierungswert = 1 (1 = Montag)
31
  date.month    = 1;    // Initialisierungswert = 1 (1 = Jänner)
32
  date.year    = 2016;    // Initialisierungswert = 2016
33
  
34
  while(1)
35
  {
36
    if ( (x = check_leapyear(&date.year)) == 29 )  // Parameterübergabe = Adresse des Strukturelements year
37
      schaltjahr = 1;    // Ein Schaltjahr wurde erkannt
38
    else
39
      schaltjahr = 0;    // Kein Schaltjahr
40
  }
41
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

S. Lonci schrieb:
> Meine Frage: Warum muss meine Pointervariable *year_ptr vom Datentyp
> unsigned int sein?

Weil das der Datentyp des Strukturelements ist:

>   unsigned int year;      // value of the actual year


> Der Datentyp der Strukturelemente ist doch eigentlich
> RTC oder?

Nein. Das ist der Datentyp der gesamten Struktur, nicht aber ihrer 
Elemente.

Hast Du schon mal einen Blick in ein C-Buch geworfen?

von S. L. (lonci)


Lesenswert?

Rufus Τ. Firefly schrieb:
> S. Lonci schrieb:
>> Meine Frage: Warum muss meine Pointervariable *year_ptr vom Datentyp
>> unsigned int sein?
>
> Weil das der Datentyp des Strukturelements ist:
>
>>   unsigned int year;      // value of the actual year
>
>
>> Der Datentyp der Strukturelemente ist doch eigentlich
>> RTC oder?
>
> Nein. Das ist der Datentyp der gesamten Struktur, nicht aber ihrer
> Elemente.

ja, dass klingt jetzt logisch! Danke für den Hinweis!

> Hast Du schon mal einen Blick in ein C-Buch geworfen?

Würde denn ein Blick in ein C-Buch dieses wunderbare Forum ersetzen? ;-)

von San L. (zwillingsfreunde)


Lesenswert?

S. Lonci schrieb:
> Würde denn ein Blick in ein C-Buch dieses wunderbare Forum ersetzen? ;-)

Nein, aber viele unnötige/extrem simple Fragen.

von S. L. (lonci)


Lesenswert?

San Lue schrieb:
> S. Lonci schrieb:
>> Würde denn ein Blick in ein C-Buch dieses wunderbare Forum ersetzen? ;-)
>
> Nein, aber viele unnötige/extrem simple Fragen.

unnötig für wen?
Strukturen und Pointer sind extrem simple? Klar, damit beginnt jeder der 
lernt C zu programmieren! ;-)
Aber da haben wohl die "Profis" andere Ansichten!

von foobar (Gast)


Lesenswert?

1
int check_leapyear (unsigned int *year_ptr)
2
{
3
  unsigned int year_value = *year_ptr;
4
  
5
  if ( (year_value % 4 == 0 && year_value % 100 != 0) || (year_value % 400 == 0) )
6
    return 29;
7
}

Sollte man nicht der Form halber noch irgendwo definieren was die 
Funktion zurückgibt wenn die Bedingung nicht erfüllt ist?

Außerdem halte ich den Rückgabewert 29 für nicht sehr glücklich gewählt 
wenn die Funktion check_leapyear heißt, aber das ist vielleicht 
Geschmackssache...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

foobar schrieb:
> Sollte man nicht der Form halber noch irgendwo definieren was die
> Funktion zurückgibt wenn die Bedingung nicht erfüllt ist?

Da sollte eigentlich der Compiler eine Fehlermeldung ausgeben, à la "not 
all control paths return a value".

von Peter II (Gast)


Lesenswert?

dann könnte man ja gleich fragen warum ein Pointer übergeben wird und 
dann gleich eine Kopie gemacht wird
1
int check_leapyear (unsigned int *year_ptr)
2
{
3
  unsigned int year_value = *year_ptr;

da kann man gleich
1
int check_leapyear (unsigned int year_value)

schreiben.

von S. L. (lonci)


Lesenswert?

Peter II schrieb:
> dann könnte man ja gleich fragen warum ein Pointer übergeben wird und
> dann gleich eine Kopie gemacht wird
>
>
1
> int check_leapyear (unsigned int *year_ptr)
2
> {
3
>   unsigned int year_value = *year_ptr;
4
>

Ich muss mit dem Wert rechnen...das geht mit der Pointervariablen aber 
nicht!
1
if ( (year_value % 4 == 0 && year_value % 100 != 0) || (year_value % 400 == 0) )
2
    return 29;

> da kann man gleich
>
>
1
> int check_leapyear (unsigned int year_value)
2
>
>
> schreiben.

Ja, kann man. Das verbraucht aber Speicher! Und ich persönlich finde es 
per Pointer einfach eleganter.

von Peter II (Gast)


Lesenswert?

S. Lonci schrieb:
> Ich muss mit dem Wert rechnen...das geht mit der Pointervariablen aber
> nicht!

warum sollte man damit nicht rechnen können?
1
if ( (*year_value % 4 == 0 && *year_value % 100 != 0) || (*year_value % 400 == 0) )
2
    return 29;

> Ja, kann man. Das verbraucht aber Speicher!
nein, es braucht weniger Speicher als deine Lösung. du braucht extra 
noch 2 Byte auf dem Stack.

> Und ich persönlich finde es per Pointer einfach eleganter.
ich nicht, dann kann man nicht erkennen ob jemand den wert ändert.

von Karl H. (kbuchegg)


Lesenswert?

S. Lonci schrieb:

> Ich muss mit dem Wert rechnen...das geht mit der Pointervariablen aber
> nicht!

Könnte man genausogut. Aber eigentlich geht das am Kern der Frage 
vorbei. Denn der lautet: Wozu überhaupt der Pointer? Den braucht doch 
keiner.

Benutze keine Pointer, wenn du nicht musst!

> Ja, kann man. Das verbraucht aber Speicher!

Und deine lokale Variable verbraucht keinen Speicher?
Tatsächlich braucht deine Lösung sogar noch mehr Speicher. Denn in 
deiner Version muss für die vom Aufrufer übergebene Adresse eine lokale 
Pointer Variable eingerichtet werden, in die der Adresswert kopiert 
wird. Und das dann noch zusätzlich zum unsigned int, der dann den Wert 
kriegt.

> Und ich persönlich finde es
> per Pointer einfach eleganter.

Das ist nicht nicht mal Ansichtssache. So wie geschrieben ist das die 
uneleganteste Form.

Die Peter II Version kann ich auch in dieser Form benutzen
1
   Tage = check_leapyear( 2025 );
um die Anzahl der Tage im Februar des Jahres 2025 feststellen zu lassen. 
Bei deiner Version geht das nicht. Da brauch ich erst mal etwas, dessen 
Adresse ich bestimmen kann
1
  unsigned int checkYear = 2025;
2
   Tage = check_leapyear( &checkYear );
Elegant ist das nicht gerade.

Benutze Pointer dann, wenn du Pointer benutzen musst! Aber nicht einfach 
so. Diese Version braucht keinen Pointer als Argument. Die Funktion ist 
vollkommen zufrieden, wenn sie eine Jahreszahl bekommt, die sie 
überprüfen soll. Mehr braucht sie nicht. Also mach auch nicht mehr 
draus.

Pointer als Funktionsargument brauchst du, wenn die Funktion in der Lage 
sein soll, auf eine oder mehrere Variablen des Aufrufers schreibend 
zuzugreifen. Pointer brauchst du, wenn du einer Funktion ein komplettes 
Strukturobjekt zur Verfügung stellst und du die Kosten zur Erzeugung 
einer Kopie des Strukturobjektes nicht tragen willst oder kannst. In 
allen andern Fällen brauchst du an dieser Stelle keinen Pointer.

von Karl H. (kbuchegg)


Lesenswert?

Wenn wir schon über Speicherverbrauch reden
1
typedef struct
2
{
3
  unsigned int second;    // value of the actual second

ein unsigned int, also etwas mit einem Wertebereich von 0 bis 65535 
(weil 16 BIt), um einen Wert zu speichern, der sich immer im Bereich 0 
bis 59 abspielen wird, also locker in 8 Bit (= 1 Byte) untergebracht 
werden kann?
Das nenn ich mal sinnlose Speicherverschwendung.

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.