Hallo,
ich habe Probleme damit in C Funktionen aufzustellen.
Die Aufgabe lautet: Schreibe eine Funktion, die 3 float-Zahlen einliest.
Mit Hilfe zwei weiteren Funktionen soll die größte float-Zahl und der
Durchschnittswert der Zahlen ausgegeben werden. Rufen Sie die Funktionen
direkt aus der Parameterliste einer printf()-Anweisung als Parameter von
printf() auf.
Die Funktionen sollen wie folgt benannt werden:
Maximalwert: float max()
Durchschnitt: float average()
Ich hoffe jemand kann mir hierbei Schritt für Schritt helfen. Es muss
auch nicht diese Aufgabe sein. Mir geht es viel mehr um das Verständnis
:)
Meine Ideen:
Ohweh, da fehlt einiges. Das Programm wird nie etwas sinnvolles
ausgeben.
Du deklarierst Deine Variablen erst in der Funktion "einlesen". Das sind
damit lokale Variablen. Was passiert mit lokalen Variablen, wenn die
Funktion verlassen wird?
Du hast mehrere Möglichkeiten die Variablen nutzbar zu machen:
1. Globale Variablen, ist aber schlechter Stil und sollte vermieden
werden
2. Pointer, wenn Ihr davon schon was gehört habt
3. Über Return-Wert
Außerdem wird keine der Funktionen so wie Du es geschrieben hast, als
Parameter von printf() aufgerufen.
Überlege Dir:
Was ist eine Funktion?
Was ist ein Funktionsparameter?
Was ist printf()?
Rufen Sie die Funktionen direkt aus der Parameterliste einer
printf()-Anweisung als Parameter von printf() auf.
Im die Funktion average kommt kein printf! raus damit. Die soll den Wert
doch berechnen.
Matthias Lipinsky schrieb:> Float max (float zahl1, float zahl2, float zahl3)> {> Float max = 0;> If ( max < zahl1) max = zahl1;> If ( max < zahl2) max = zahl2;> If ( max < zahl3) max = zahl3;> Return max;> }
Und bei negativen Zahlen ist dann 0 das Maximum.
Darum erstmal dem max den ersten Wert zuweisen:
1
floatmax=0;
2
if(max<zahl2)max=zahl2;
3
if(max<zahl3)max=zahl3;
4
returnmax;
Leyla S. schrieb:> Pointer hatten wir nocht nicht, also muss ich mit return arbeiten.
Und was machst du bei scanf?
Sehr schön. Damit wurde Dein Problem extern gelöst. Da Du aber Deinem
Lehrer/Professor/Wasauchimmer das Programm erklären müssen wirst,
solltest Du trotzdem versuchen Dir über die Fragen, die ich gestellt
habe, Gedanken zu machen.
Dazu kommt, dass Du, wenn Du die Lösung von Lippy nehmen möchtest, Dir
überlegen musst, was der Unterschied zwischen
if und If
sowie zwischen
float und Float ist.
Die obige Lösung wird sich nicht kompilieren lassen.
Die Antwort bezog sich auf Lippys Quellcode. Die Fehler hast Du schon
bereinigt.
Bei "einlesen" wird nur eine Zahl eingelesen, dafür aber die Funktion
dreimal aufgerufen. Mit dem return-Wert weist Du den Variablen ihren
Wert zu.
Ja ich versuche die Lösung grad zu verstehen.
Ich weiß, dass Funktionen kleine Unterprogramme der Hauptfunktionen main
sind. Die Parameter sind die Übergabewerte.
Mit printf wird etwas ausgegeben. Und das c case sensitive ist, ist mir
bewusst.
Aber das Programm konnte ich trotzdem nicht kompilieren.
Die funktionsprototypen vor dem main stimmen nicht mit denennach dem
Main überein. Entweder anpassen oder die Prototypen löschen und die
hilfsfunktionen vor das main schreiben
> Mit printf wird etwas ausgegeben.
Worauf ich hinaus wollte: printf() ist genauso eine Funktion wie es
Deine average-Funktion auch ist. Sie hat genauso Übergabeparameter wie
die anderen Funktionen. Du sollst dort halt als Übergabeparameter die
average-Funktion statt einer Variablen nutzen. Da aber die
Average-Funktion den Wert einer Variablen als return an die
printf-Funktion übergibt, ist es, als wenn dort eine Variable stehen
würde.
Leyla S. schrieb:> Ok nochmal zum Einlesen, wo sehe ich, dass die Funktion dreimal> aufgerufen wird? Liegt es hier an dem Code-Fragment:> float zahl1 = einlesen();> float zahl2 = einlesen();> float zahl3 = einlesen();
Ja. Die Funktion wird doch dreimal aufgerufen, dreimal wird damit der
return-Wert an jeweils unterschiedliche Variablen übergeben.
Gibst Du denn bei der printf-Funktion einen Datentyp an?
Einen Datentyp benötigst Du nur, wenn Du einen return-Wert erwartest.
Was ist der Unterschied zwischen void bla() und int blub()?
So und da wäre noch eine Sache mit der ich auch schon angefangen habe.
Und zwar soll diese Aufgabe in eine Menü untergebracht werden. Menü soll
hierbei auch eine Funktion darstellen. Das müsste ich ja jetzt
hinkriegen, aber mir habe scheinbar einen Fehler in der Deklaration.
Leyla S. schrieb:
Wenn ich mir das so durchlese, denke ich der Fisch fängt hier zum
stinken an:
> Muss immer ein Datentyp angegeben werden?>>>
1
floatzahl1=einlesen();
Du hast nicht begriffen, dass hier 2 Dinge passieren.
Zum einen wird eine Variable defniniert
1
inti;
2
intj;
3
floatzahl;
Das ist die Definition einer variablen wie jeder andere auch.
Und einer Variablen kann man bei der Definition einen Initialwert
mitgeben.
1
inti=5;
2
intj=8;
3
intzahl=3.141592654;
soweit so gut.
Das andere ist ein Funktionsaufruf
1
einlesen();
wird der Name einer Funktion mit einem () verwendet (und gegebenenfalls
Argumente an die Funktion übergeben, die dann in den Klammern stehen),
dann wird die Funktion aufgerufen und macht ihr Ding.
Jetzt gibt es aber Funktionen, die einen Wert berechnen. Zum Beispiel
Sinus oder auch die Wurzel. Rufst du die Funktion auf, dann gibts du ihr
den Wert mit, ....
1
sqrt(8);
... die Funktion macht ihr Ding und liefert einen Wert. Nur: Du musst
mit dem Wert auch etwas machen! Denn sonst ist es recht sinnlos eine
Funktion aufzurufen, die irgendwas berechnet, wenn mit dem Berechneten
nichts geschieht.
Der Wert, den die Funktion liefert, das ist ein Wert wie jeder andere.
Er kann zb in Ausdrücken weiterverwendet werden
1
3*sqrt(8);
und genauso wie dieser Ausdruck einen neuen Wert berechnet und zur
Verfügung stellt, den man dann an eine Variable zuweisen kann
1
k=3*sqrt(8);
genauso kannst du auch einfach den Wert den die Funktion liefert an eine
Variable zuweisen
1
k=sqrt(8);
Rechts vom = steht ein arithmetischer Ausdruck. So ein Ausdruck setzt
sich zusammen aus Konstanten
1
5
aus Operation, die mit Konstanten gemacht werden
1
5+3
oder den Werten, die in Variablen stehen
1
k
1
5+k
oder eben auch den Werten, die von Funktionen zugeliefert werden
1
5+sqrt(12)
Aber auch die Werte, die an eine Funktion gehen, sind (in diesem Fall)
einfach nur arithmetische Ausdrücke
1
5+sqrt(3*j)
Jeder Bestandteil, der vertreten ist, liefert einfach nur einen Wert, wo
auch immer der herkommt. Konstanten stehen für sich selbst als Wert, bei
Variablen ist ihr Inhalt gemeint und bei Funktionsaufrufen ist eben der
Wert, den die Funktion zuliefert. Und mit den arithmetischen Operationen
werden diese Werte verknüpft, wird also wieder ein weiterer Wert
errechnet, bis dann auf der rechten Seite von
1
k=.....
ein einziger Wert entstanden ist und der wird dann der Variablen
zugewiesen.
Was hat das jetzt mit dem am Anfang über Variablen Definitionen zbw.
Initialisierungen Gesagten zu tun?
Nun ganz einfach.
Hier
1
floatzahl=3.141592654;
steht nur deshalb einen Zahlenkonstante, weil ich da eine hingeschrieben
habe. Es könnte aber genausogut irgendein anderer arithmetischer
Ausdruck sein ...
1
floatzahl=(3+2)*5;
... der natürlich genausogut den Aufruf einer Funktion beinhalten kann,
die einen Wert liefert.
1
floatzahl=sqrt(5);
Hier, in der letzten Zeile, sind also einfach nur ein paar Dinge
zusammengeführt und gemeinsam in einer einzigen Zeile benutzt worden!
Mehr steckt da nicht dahinter.
Wenn es mir nicht so wichtig ist, das Ganze als Initialisierung zu
sehen, kann ich das selbstverständlich auch so schreiben
1
floatzahl;
2
3
zahl=sqrt(5);
Dann hat eben die Variable Zahl, wenn sie zur Welt kommt, keinn
eindeutig definierten Wert, sondern kriegt ihn erst, wenn ihr der Wert
aus dem Funktionsaufruf zugewiesen wird.
Wie schreibt man nun eine Funktion, die einen Wert liefert? Wie muss
sqrt, also die Wurzelfunktion, aussehen, damit sie genau das kann: Einen
Wert übernehmen und einen Wert liefern.
So
1
floatsqrt(floatzahl)
2
{
3
floatergebnis;
4
5
....
6
// mach dein Ding zur Berechnnung der Wurzel von 'zahl'
7
// das Resultat dieses Dings soll in der lokalen Variablen 'ergebnis'
8
// vorliegen
9
10
returnergebnis;
11
}
Das erste float, das vor dem Funktionsnamen, bezeichnet den Datentyp des
Ergebnisses. Innerhalb der Funktion gibt es eine lokale Variable, in der
die Berechnung gemacht wird. Am Ende der Funktion, wenn das korrekte
Ergebnis in 'ergebnis' vorliegt, kommt der 'return' zur Ausführung. Und
beim return gebe ich einen Ausdruck an, der den Wert bestimmt, welcher
als Rückgabewert der Funktion dienen soll. D.h. hier wird dann der Wert
auf die Reise geschickt, der beim Aufrufer
1
floatzahl=sqrt(12);
dann wieder auftaucht und in diesem Fall zur Initialisierung der
Variablen dient. Wie gesagt: das muss keine Intialisierung sein. Ich
kann mit dem Wert, den ich bekomme, machen was ich will. Zb in einer
Berechnung verwenden
1
hjk=5*sqrt(8);
oder ich kann diesen Wert zum Beispiel auch dazu benutzen, dass ich ihn
an eine andere Funktion als Argument übergebe, die dann ihrerseits mit
dem so erhaltenen Wert wieder was berechnet
1
j=sin(sqrt(3));
Das kann auch wieder die Funktion selber sein
1
j=sqrt(sqrt(4)),
das ist alles an dieser Stelle nicht wirklich wichtig. Wichtig ist, dass
diese Funktion sqrt einen Wert übernimmt und einen Wert liefert. Wo der
Wert herkommt, den die Funktion übernimmt, ist nicht das Bier der
Funktion, die kriegt einfach nur den ausgerechneten Wert als Argument
mit
1
j=sqrt(3*4+8);
bzw. sie liefert einen Wert, mit dem ich dann weiterarbeite.
Wenn es in Funktionen reingeht, dann bist du in deiner Ausbildung so
weit, dass du erkennen musst, das es nicht für alles und jedes ein
Kochrezept gibt, dem du nur folgen musst. Es beginnt jetzt immer mehr
die Phase, in der du anfängst, die bisher gelernten Basisdinge
miteinander zu kombinieren. Dazu musst du diese Basisdinge aber auch
erkennen können und musst sie kennen! Und ja. Das ist eines der Dinge,
die in Programmiersprachen das Um und Auf darstellen:
Programmiersprachen sind deswegen mächtig, weil man Konzepte miteinander
kombinieren kann. Das ist wie beim Schach-Spiel: Wie die Figuren ziehen
können, das lernt man in 2 Stunden. Aber wie man aus der Kombination
dieser Möglichkeiten sein Spiel so anlegt, dass man gewinnt, daran lernt
man ein Leben lang. Nichts desto trotz, ist aber die Kenntnis der
Zugmöglichkeiten die Grundlage für alles weitere. Wenn du also in den
bisherigen Unterrichtseinheiten nicht aufgepasst hast, weil das ja eh
alles pipi-einfach ist bzw. die Übungen nicht selbst gemacht hast, dann
solltest du das Versäumte schleunigst nachholen. Denn das sind die
Grundlagen, auf denen alles weitere aufbaut. Beherrscht du die nicht,
dann überrollt dich alles weitere, ohne das du eine Chance hast, dagegen
etwas zu tun.
Vielen Dank für die ausführliche Antwort. Habe jetzt noch eine Sache im
Programm umgeändert, undzwar habe ich in case 2 einlesen() drinstehen
(und int aufgabe2() entfernt),dies müsste doch jetzt die Funktion float
einlesen aufrufen? Innerhalb der Funktion float einlesen() erwartet die
Funktion printf den Wert max, also müsste doch auf die entsprechende
Funktion, weiter unten zugegriffen werden? Was aber wohl hier nicht der
Fall ist.
Leyla, das mag jetzt etwas hart klingen, aber Du hast nichts von dem
verstanden, was wir Dir, insbesondere Karl-Heinz, versucht haben, zu
erklären. Du wirst große Probleme bekommen, wenn Du das Programm Deinem
Lehrer vorstellen musst.
Leyla S. schrieb:
1
>
2
>floateinlesen(floatzahl1,floatzahl2,floatzahl3)
3
>{
4
>floatzahl;
5
>printf("Bitte geben Sie eine Zahl ein:\n");
6
>scanf("%f",&zahl);
7
>printf("\n%f ist die groesste eingelesene Kommazahl\n",
wo sollen denn zahl1, zahl2, zahl3, die Du der Funktion einlesen als
Parameter übergibst, denn herkommen? Welche Berechnungen führst Du mit
zahl durch?
Was in Deinem Programm passiert:
1
>floateinlesen(floatzahl1,floatzahl2,floatzahl3)
Du rufst eine Funktion auf und übergibst ihr drei Variablen, die zuvor
nirgends auftauchten. Sollte sich das so kompilieren lassen, sind die
Werte der drei Zahlen zufällig. Kann irgendwas sein.
1
>floatzahl;
2
>printf("Bitte geben Sie eine Zahl ein:\n");
3
>scanf("%f",&zahl);
Du deklarierst eine Variable zahl und weist ihr mit scanf einen Wert zu.
Eine Variable, ein Wert!
1
>printf("\n%f ist die groesste eingelesene Kommazahl\n",
2
>max(zahl1,zahl2,zahl3));
Du rufst eine Funktion max() auf, übergibst ihr die drei Variablen aus
den Parametern, deren Werte immer noch zufällig sind. Aus diesen drei
Werten wird der größte Wert ermittelt (oder besser sollte, denn in der
Funktion max() ist auch noch ein Fehler). Doch da die Werte der
Variablen zufällig sind, ist auch das Ergebnis zufällig. Dieser
zufällige Wert wird an die Funktion printf() übergeben und ausgegeben.
Hier passiert dasselbe, wie eben beschrieben. Drei zufällige Werte in
den Variablen, zufälliges Ergebnis.
1
>returnzahl;
Hier gibst Du den Wert, den Du zuvor mit scanf() eingelesen hast,
unverändert an die aufrufende Funktion menue() zurück. Dort wird, da der
Wert in der Funktion menue() keiner weiteren Variablen zugewiesen wird,
der Wert einfach verworfen. Aber was sollte sie auch mit dem Wert.
Ich hoffe, Du erkennst, dass Du einiges nochmal nachlesen solltest.
Selbst wenn ich Dir die Lösung hier hinschreibe, hilft Dir das nichts,
denn die Fehler, die Du machst, sind so grundlegend, dass sie bei jeder
weiteren Aufgabe wieder auftauchen.
Wenn Du verstanden hast, warum Deine Funktion einlesen() nicht
funktionieren kann, dann bist Du auch in der Lage, den Fehler in der
Funktion max() selbst zu finden und zu eliminieren.
@libba da hast du recht im Endeffekt bringen mir die Lösungen nichts.
Die Aufgabe werde ich nicht vorstellen, dafür war sie nicht gedacht.
Vielmehr versuche ich das Thema mit den Funktionen zu verstehen, aber
habe momentan ziemlich viele Schwierigkeiten damit. Ich werde mich
gleich auch dransetzen und nochmal alles dazu durchlesen und versuchen
alles nachzuvollziehen, auch was Karl geschrieben hat.
Also auf jeden Fall vielen Dank nochmal für eure Hilfe.
Hat jemand zufällig Buch Empfehlungen?
Leyla S. schrieb:> Hat jemand zufällig Buch Empfehlungen?
Ja.
Brian Kernighan & Dennis Ritchie, "Programmieren in C", zweite Ausgabe,
Hanser-Verlag.
Das ist zwar schon recht alt, beschreibt aber nach wie vor die
relevanten Grundzüge des Programmierens in C.
Zwar sind mittlerweile Erweiterungen des C-Sprachstandards
hinzugekommen, die auch ihre Daseinsberechtigung haben, aber nichts von
dem, was 1989 korrekt war, ist jetzt falsch. Jetzt geht nur manches auf
noch andere Art und Weise.
Für Deine Probleme aber ist das nicht von Belang, die Konzepte "Was ist
eine Variable", "Was ist die 'Sichtbarkeit' und was die 'Gültigkeit'
einer Variablen" und "Wie werden Variablen an Funktionen übergeben" sind
unveränderte Klassiker.
Das hat zwar jetzt ziemlich lange gedauert, aber besser spät als nie.
Ist es so richtig bzw erlaubt, float zahl1, zahl2, zahl3 unter case zu
deklarieren, so wie ich es gemacht habe?
1
#include<stdio.h>
2
intmenue(intaufgabe);
3
floatmax(floatzahl1,floatzahl2,floatzahl3);
4
floataverage(floatzahl1,floatzahl2,floatzahl3);
5
floateinlesen(floatzahl1,floatzahl2,floatzahl3);
6
intmain(){
7
intaufgabe;
8
menue(aufgabe);
9
return0;
10
}
11
intmenue(intaufgabe){
12
13
do{
14
printf("\nAufgabe waehlen: \n\n");
15
printf("(2) Aufgabe 2\n");
16
printf("(0) Programm Beenden\n\n");
17
scanf("%d",&aufgabe);
18
19
switch(aufgabe){
20
21
case2:
22
printf("Aufgabe 2\n\n");
23
floatzahl1,zahl2,zahl3;
24
einlesen(zahl1,zahl2,zahl3);
25
break;
26
case0:
27
printf("Programm beendet!\n");
28
break;
29
default:
30
printf("Falsche Eingabe\n");
31
}
32
}while(aufgabe!=0);
33
34
return0;
35
}
36
37
38
39
floateinlesen(floatzahl1,floatzahl2,floatzahl3){
40
41
printf("\n");
42
43
printf("Bitte 1. Kommazahl eingeben: ");
44
scanf("%f",&zahl1);
45
46
printf("Bitte 2. Kommazahl eingeben: ");
47
scanf("%f",&zahl2);
48
49
printf("Bitte 3. Kommazahl eingeben: ");
50
scanf("%f",&zahl3);
51
printf("\n%f ist die groesste eingelesene Kommazahl\n",max(zahl1,zahl2,zahl3));
Leyla S. schrieb:> Das hat zwar jetzt ziemlich lange gedauert, aber besser spät als nie.> Ist es so richtig bzw erlaubt, float zahl1, zahl2, zahl3 unter case zu> deklarieren,
das kannst du ganz leicht feststellen, in dem du es durch den Compiler
jagst. Wenn der Compiler nichts dazu zu sagen hat, dann ist es zumindest
syntaktisch schon mal nicht falsch ....
> so wie ich es gemacht habe?
... was allerdings nicht heisst, dass es auch von der Bedeutung her
korrekt ist.
"Das Flugzeug strickt die Fischstäbchen."
ist ein nach Duden korrekter Satz. Er erfüllt alle
Grammatikanforderungen, alle Wörter sind definiert, der Satzbau ist
korrekt und auch alle Wortformen stimmen.
Trotzdem ist er Unsinn.
Das eine ist die Syntax. Also die Grammatikregeln einer
Programmiersprache.
Das andere ist die Semantik. Also die Bedeutung, die ein bestimmtes
Konstrukt hat. Da verwechselst hier die beiden Dinge bzw. gehst davon
aus, dass du ein sinnvolles korrektes Programm hast, wenn du die
Sprachregeln eingehalten hast. Dem ist aber nicht so.
Welche Hilfsmittel verwendest du eigentlich?
Wurde dir ein Buch empfohlen oder gibt es ein Skript oder alles nur
mündlich?
Wie testest du, ob das was du machst funktioniert? Dann wirst du ja
sehen, wie sich dein Programm verhält. Wenn du dann noch einfach einen
Schrittbetrieb mit einem debugger machst, dann kannst du Fehler selbst
finden und beheben.
Es gibt grundlegende Einführungsbeispiele zu C im Internet (über google
und Co zu finden).
Das war jetzt bewusst nicht konstruktiv. Bitte erst mal die Grundlagen
erarbeiten und dann an die Aufgabe. Die Aufgabenstellung klingt so, als
wenn genau das gefordert wird. Etwas Zeit investieren und sich die
Sachen Stück für Stück aneignen. Dann macht es auch Spass.
Matthias hat dir hier
Beitrag "Re: Funktionen in C"
die Eingabefunktion auf eine Variante gearbeitet, die nur 1 Wert
einliest. Und er tat das aus einem guten Grund! Offenbar habt ihr noch
nicht gelernt, wie man eine Funktion schreibt, die ihre Ergebnisse über
die Argumentschnittstelle zurück liefert. Entweder das, oder du hast es
verschwitzt, wie das geht.
So
1
einlesen(zahl1,zahl2,zahl3);
2
...
3
4
floateinlesen(floatzahl1,floatzahl2,floatzahl3){
5
...
funktioniert das nicht. Hier müsste man mit Pointern arbeiten, damit dir
Funktion in der Lage ist, die Variablen zahl1, zahl2 und zahl3 des
Aufrufers zu verändern.
Allerdinfs erhebt sich auch die Frage, wozu die Funktion überhaupt diese
Argumente benötigt. Denn sie braucht diese Argumente nicht, weil sie
sowieso alles selber erledigt. Das könnte man genausogut auch mit
lokalen Variablen erledigen
1
voideinlesen(){
2
3
floatzahl1,zahl2,zahl3;
4
5
printf("\n");
6
7
printf("Bitte 1. Kommazahl eingeben: ");
8
scanf("%f",&zahl1);
9
10
printf("Bitte 2. Kommazahl eingeben: ");
11
scanf("%f",&zahl2);
12
13
printf("Bitte 3. Kommazahl eingeben: ");
14
scanf("%f",&zahl3);
15
printf("\n%f ist die groesste eingelesene Kommazahl\n",max(zahl1,zahl2,zahl3));
Karl Heinz schrieb:> Matthias hat dir hier> Beitrag "Re: Funktionen in C"> die Eingabefunktion auf eine Variante gearbeitet, die nur 1 Wert> einliest. Und er tat das aus einem guten Grund! Offenbar habt ihr noch> nicht gelernt, wie man eine Funktion schreibt, die ihre Ergebnisse über> die Argumentschnittstelle zurück liefert. Entweder das, oder du hast es> verschwitzt, wie das geht.
Also ich habe das schon verstanden, aber wusste nicht wie ich den ganzen
Part in main hier auf diesen Fall umschreibe. Da in meiner main Funktion
nur die aufgabe stehen darf. Ich hoffe du verstehst wo mein Problem
liegt bzw. was ich meine.
Zum Zweiten das mit void einlesen() als Funktion verstehe ich besser.
Christopher schrieb:> Welche Hilfsmittel verwendest du eigentlich?> Wurde dir ein Buch empfohlen oder gibt es ein Skript oder alles nur> mündlich?
C Galileo Openbook gibt's online und Programmieren in C, ich habe mir
auch die jeweiligen Sachen dazu durchgelesen. Ja mit dem Debugger sehe
ich meine Fehler, hier wurden mir keine angezeigt. Deswegen wollte ich
nochmal im Forum fragen, weil ich mir eben an dieser einen Stelle
unsicher war.