Forum: PC-Programmierung Funktion mit mehreren Argumenten


von Dennis (Gast)


Lesenswert?

Hey Leute, ich habe folgende Aufgabe in der Schule nicht verstanden, ich 
hoffe ihr könnt mir helfen, da ich gerade für eine Klausur lerne.
Ich habe folgenden Code gegeben und soll bestimmen, was das Endergebnis 
ist,das auf dem Bildschirm angezeigt wird:
1
#include <stdio.h>
2
#include <stdarg.h>
3
4
void main( void ){
5
int willy = harry( 2, 1, 2, 3, -2, -3 );
6
printf("%i", willy);
7
}
8
9
int harry( int zahl, ...){
10
int ergebnis = 0;
11
va_list arg_ptr;
12
va_start(arg_ptr, zahl);
13
ergebnis += va_arg(arg_ptr, int);
14
ergebnis += va_arg(arg_ptr, int);
15
ergebnis += va_arg(arg_ptr, int);
16
va_end(arg_ptr);
17
return( ergebnis );
18
}

Addieren sich die Argumente einzeln, sprich: (2+2+2+2,1+1+1+1,......) ?
somit wäre das Ergebnis: (8,4,8,12,-8,-12)

oder addieren sich die Argumente im gesamten, sprich: (2+1+2+3-2-3)*3 ?
somit wäre das Ergebnis: (9)

Leider kann ich den Code nicht in einfach testen , da es einige Fehler 
zu geben scheint!

: Bearbeitet durch User
von Dennis (Gast)


Lesenswert?

Hey ich bin es nochmal.
Ich bereite mich gerade auf eine Informatikklausur (C) vor und habe ein 
Problem bei folgender Aufgabe:



Wie ist der Aufruf in Zeile 4 korrekt zu ergänzen, damit anschließend 
auf den ersten variablen Parameter der Funktion tueIrgendwas zugegriffen 
werden kann?

1: int tueIrgendwas( int iWert, float fWert, ...)
2: {
3: va_list pArg;
4: va_start(


Meine Lösung: pArg,iWert);

Ist diese korrekt?
MfG Dennis

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Lesen kannst aber?

http://linux.die.net/man/3/stdarg

Die Aufgabe ist so nicht lösbar, denn es fehlt das Include von stdarg.h

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Hey ich bin es nochmal.
> Ich bereite mich gerade auf eine Informatikklausur (C) vor und habe ein
> Problem bei folgender Aufgabe:
>
>
>
> Wie ist der Aufruf in Zeile 4 korrekt zu ergänzen, damit anschließend
> auf den ersten variablen Parameter der Funktion tueIrgendwas zugegriffen
> werden kann?
>
> 1: int tueIrgendwas( int iWert, float fWert, ...)
> 2: {
> 3: va_list pArg;
> 4: va_start(
>
>
> Meine Lösung: pArg,iWert);

Nein.
übliche Leseart in unserem Kulturkreis ist von links nach rechts. D.h. 
der letzte benannte Parameter in der Argumentliste war fWert. Bei 
va_start gibst du den letzten benannten Parameter an.

http://www.cplusplus.com/reference/cstdarg/va_start/

von Dr. Sommer (Gast)


Lesenswert?

Dennis schrieb:
> Leider kann ich den Code nicht in einfach testen , da es einige Fehler
> zu geben scheint!
Wie wärs dann damit, damit anzufangen, die Fehler zu beheben?

Der Rückgabetyp von "main" muss "int" sein, nicht void. Vor der "main" 
Funktion muss erst die "harry"-Funktion deklariert werden.

Dennis schrieb:
> Addieren sich die Argumente einzeln, sprich: (2+2+2+2,1+1+1+1,......) ?
> somit wäre das Ergebnis: (8,4,8,12,-8,-12)
>
> oder addieren sich die Argumente im gesamten, sprich: (2+1+2+3-2-3)*3 ?
> somit wäre das Ergebnis: (9)

Weder noch. Schau dir den Code an:

Dennis schrieb:
> ergebnis += va_arg(arg_ptr, int);
> ergebnis += va_arg(arg_ptr, int);
> ergebnis += va_arg(arg_ptr, int);
Wie viele Additionen zählst du hier? Wie viele Zahlen werden hier also 
addiert? Und wie kommst du überhaupt auf *3 ?

Überraschenderweise ist die Funktion von va_arg usw. dokumentiert. Wie 
wäre es damit das zu lesen und dann zu überlegen was der Code tut?
https://en.wikipedia.org/wiki/Stdarg.h
http://www.cplusplus.com/reference/cstdarg/

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das Programm zeigt Undefined Behaviour, da für den korrekten Aufruf von 
harry() dessen Definition / Deklaration fehlt.

von Dennis (Gast)


Lesenswert?

Nach einiger Überlegung ist mir aufgefallen, dass ich das ergebnis = 0 
übersehen habe.
somit wäre ja:

harry( 2, 1, 2, 3, -2, -3 );   = 3

dann folgt:

ergebnis += va_arg(arg_ptr, int);
ergebnis += va_arg(arg_ptr, int);
ergebnis += va_arg(arg_ptr, int);

also wäre das Egebnis 9, richtig?

von Daniel A. (daniel-a)


Lesenswert?

Der code Compiliert nicht weil die funktion harry vor der ersten 
Verwendung noch nicht Deklariert wirde.

Das Ergebnis ist 6:
va_start benötigt als Zweites argument das letzte Argument vor der 
Parameterliste der Funkion in der es steht, tut damit aber nichts. 
va_arg liefert das nächste Argument. Es werden 3 argumente der variablen 
argumentliste mit va_arg geholt, addiert und zurückgegeben. Jedes 
Argument das keinem Parameter der funktion entspricht ist teil der 
Argumentliste, das erste argument von harry ist zahl und gehlrt zum 
ersten parameter von harry, "zahl". Der rest ist teil der variablen 
argumentliste. Somit werden 1, 2, und 3 addiert, das ergiebt 6

von Dr. Sommer (Gast)


Lesenswert?

Dennis schrieb:
> also wäre das Egebnis 9, richtig?
Nö.

Die "harry" Funktion ist im übrigen ziemlich bescheuert, weil sie eine 
feste Anzahl an Argumenten zum Funktionieren braucht (4) aber dennoch 
eine variadische Parameterliste hat, und außerdem das erste Argument und 
alle ab dem 5. ignoriert.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:

> Addieren sich die Argumente einzeln, sprich: (2+2+2+2,1+1+1+1,......) ?
> somit wäre das Ergebnis: (8,4,8,12,-8,-12)

Du scheinst da eine sehr seltsame Sichtweise zu haben.

va_arg holt genau 1 Wert von der Argumentliste. Nicht mehr und auch 
nicht weniger.

wenn du also einen Aufruf hast
1
   ... harry( 2, 1, 2, 3, -2, -3 );

dann geht die erste 2 an die Variable zahl. Denn die ist in der 
Argumentliste ja als erstes
1
int harry( int zahl, ...)
2
               ****

die erste Benutzung von va_arg bringt dir die 1
1
   ... harry( 2, 1, 2, 3, -2, -3 );
2
                ***
die nächste Benutzung eine 2
1
   ... harry( 2, 1, 2, 3, -2, -3 );
2
                   ***
und die dritte Benutzung die 3
1
   ... harry( 2, 1, 2, 3, -2, -3 );
2
                      ***
da keine weiteren va_arg Benutzungen mehr im Code vorkommen, werden die 
restlichen Argument nicht weiter benutzt.

Was also ist das Ergebnis von
1
  ergebnis = 0;
2
  ergebnis += va_arg(arg_ptr, int);
3
  ergebnis += va_arg(arg_ptr, int);
4
  ergebnis += va_arg(arg_ptr, int);
oder wenn wir die Zahlen einsetzen
1
  ergebnis = 0;
2
  ergebnis += 1;   // geliefert vom ersten va_arg
3
  ergebnis += 2;   // geliefert vom zweiten va_arg
4
  ergebnis += 3;   // geliefert vom dritten va_arg

: Bearbeitet durch User
von Dennis (Gast)


Lesenswert?

Vielen Dank für die zahlreichen und schnellen Antworten!

Ich habe jetzt alles verstanden, außer, wieso die 2 nicht erscheint.

ist es wegen " va_start(arg_ptr, zahl); " ?
arg_ptr ruft also die 2 auf und schreibt sie in "zahl", richtig?

von Dennis (Gast)


Lesenswert?

Karl H. schrieb:
> Nein.
> übliche Leseart in unserem Kulturkreis ist von links nach rechts. D.h.
> der letzte benannte Parameter in der Argumentliste war fWert. Bei
> va_start gibst du den letzten benannten Parameter an.

also va_start(pArg,fWert); ?

Somit würde wäre iWert der erste ausgegebene Wert richtig?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dennis schrieb:
> Somit würde wäre iWert der erste ausgegebene Wert richtig?

Nein. Der fällt unter den Tisch, wie fWert auch.

von Dennis (Gast)


Lesenswert?

und wie greife ich dann auf den ersten Wert zu, bzw was ist denn dann zu 
ergänzen, wenn beides unter den Tisch fällt?

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Vielen Dank für die zahlreichen und schnellen Antworten!
>
> Ich habe jetzt alles verstanden, außer, wieso die 2 nicht erscheint.
>
> ist es wegen " va_start(arg_ptr, zahl); " ?
> arg_ptr ruft also die 2 auf und schreibt sie in "zahl", richtig?

Nein.
arg_ptr ruft überhaupt nichts auf.

arg_ptr richtet die arg_list so ein, dass die erste Benutzung von va_arg 
das nächste Argument von der Argumentliste holt, das nach dem benannten 
Parameter 'zahl' auftaucht.

Die erste 2 wird ganz normal an den ersten benannten Parameter gebunden
1
    harry(       2, 1, 2, 3, -2, -3 );
2
                 |
3
                 |
4
                 v
5
 int harry( int zahl, ...){

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> und wie greife ich dann auf den ersten Wert zu, bzw was ist denn dann zu
> ergänzen, wenn beides unter den Tisch fällt?

Ähm. Über den Variablennamen des Parameters?
1
 int tueIrgendwas( int iWert, float fWert, ...)
2
 {
3
   int irgendwas = iWert + fWert;
4
5
   ....

mit denen gibt es ja kein Problem. Die haben ja Variablennamen. Nur 
alles was danach kommt, dafür hast du keinen Namen mit dem du es 
ansprechen könntest.

Rück mal ein wenig zur Seite. Du sitzt gerade mächtig auf der Leitung. 
Das ist viel einfacher als du jetzt denkst.

: Bearbeitet durch User
von Dennis (Gast)


Lesenswert?

Ahhh, jetzt habe ich das verstanden =)
Vielen Dank Karl Heinz, diese Erklärung hat mir sehr geholfen.

Die zweite Aufgabe verstehe ich allerdings immer noch nicht... :(

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Ahhh, jetzt habe ich das verstanden =)
> Vielen Dank Karl Heinz, diese Erklärung hat mir sehr geholfen.
>
> Die zweite Aufgabe verstehe ich allerdings immer noch nicht... :(

was verstehst du daran nicht.

Beim Aufruf von
1
 int tueIrgendwas( int iWert, float fWert, ...)
welches ist denn der erste 'variable Parameter'?

Na der der nach fWert kommt. Denn die ersten beiden sind ja fix. Die 
ersten beiden müssen sein, sind also nicht variabel in dem Sinne dass 
sie da sein können oder auch nicht.

Mit dem Protoypen klopft dir ein Compiler auf die Finger wenn du
1
   tueIrgendwas( 5 );
machen willst. Denn die Funtkion fordert mindestens 2 Argumente. 2 
Argumente sind fix gefordert.
1
  tueIrgendwas( 5, 8 );
wäre also ok.
Aber auch
1
  tueIrgendwas( 5, 8, 3 );
ist ok. die 3 ist halt der erste variable Paramater. er kann da sein, 
muss aber nicht.

Wenn also standardmässig sowieso erst mal die Bindung an die benannten 
fixen Parameter erfolgt
1
  tueIrgendwas(          5,           8,      3 );
2
                         |            |
3
                         |            |
4
                         v            v      
5
 int tueIrgendwas( int iWert, float fWert, ...)

welche ist dann der letzte benannte Parameter ehe dann der variable Teil 
der Argumentliste anfängt?
Genau - fWert.
setzt du die va_list so mit einem va_start auf fWert auf, dann liefert 
der erste va_arg dann eben die 3

: Bearbeitet durch User
von Dennis (Gast)


Lesenswert?

Ich sitze vermutlich schon viel zu lange vor dem Bildschirm und sollte 
eine Pause machen...

wenn ich also also
va_start(pArg,fWert);
aufrufe, dann würde in deinem Beispiel mit einem Aufruf von va_arg die 3 
ausgegeben werden, weil diese der erste Variable Wert ist.

von Karl H. (kbuchegg)


Lesenswert?

Dennis schrieb:
> Ich sitze vermutlich schon viel zu lange vor dem Bildschirm und sollte
> eine Pause machen...
>
> wenn ich also also
> va_start(pArg,fWert);
> aufrufe, dann würde in deinem Beispiel mit einem Aufruf von va_arg die 3
> ausgegeben werden, weil diese der erste Variable Wert ist.

An dieser Stelle sind wir soweit, dass man mit Fug und Recht behaupten 
kann:
Du hast einen Compiler vor dir. Probier es aus.

von Dennis (Gast)


Lesenswert?

Vielen Dank für deine Geduld mit mir Karl Heinz,
ich glaube, dass ich es jetzt wirklich verstanden habe
(der Compiler sagt mir dann tatsächlich 3 )

=)

von DirkB (Gast)


Lesenswert?

Bei
1
int tueIrgendwas( int iWert, float fWert, ...)
2
tueIrgendwas( 5, 8, 3 );
Wird die 8 auch in ein float gewandelt

Karl H. schrieb:
> Du hast einen Compiler vor dir. Probier es aus.

Da muss man aber aufpassen.
Nicht alles was dein Compiler macht, macht auch ein anderer Compiler.
In C gibt es genug Freiheiten und UB (undefined behaviour)

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.