Funktionen (Rückgabewert/Parameterwert)
-
Ich beschäftige mich seit 2 Tagen mit Funktionen. Dazu habe ich mir verschiedene Lektüren durchgelesen und folgende Videos angesehen:
http://www.youtube.com/watch?v=VFkQK0h_Jf4
http://www.youtube.com/watch?v=mDsTw6s3C4oDoch ich verstehe immer noch nicht das Prinzip des Parameter- und Rückgabewerts. Dabei sind 4 Unterschiede vorhanden:
1. Mit Rückgabewert + ohne Parameterwert
2. Mit Rückgabewert + Mit Parameterwert
3. Ohne Rückgabewert + ohne Parameterwert
4. Ohne Rückgabewert + ohne ParameterwertIch verstehe bei allen nicht den Unterschied. Irgendwie schaff ich es nicht durch das Fenster zu blicken.
Der Aufbau einer Funktion sieht wie folgt aus:
Rückgabetyp Funktionsname(Parametertyp)
Der Rückgabetyp sagt dem Hauptprogramm bescheid, welcher Datentyp am Ende des Unterprogramms herrauskommen wird. Gilt Rückgabetyp=Rückgabewert?
Der Funktionsname beschreibt das Unterprogramm.Mit Parametertyp sind die zu deklarierenden Werte gemeint mit welchen programmiet werden im Unterprogramm. Gilt Parametertyp=Parameterwert ?
Es wäre wirklich sehr nett wenn mir jemand helfen könnte, den ich bekomme es einfach nicht hin es zu verstehen. Ich brauche einfach nur einen Durchblick. Vielleicht kann mir jemand helfen.
Edit: Das Programm ist z.b. einfach nachzuvollziehen. Aber sobald Zahlen berücksichtig werden kann ich gar nicht mehr folgen.
#include <iostream> using namespace std; void ausgabe() { cout << "TEXT" ; } int main() { ausgabe(); cin.sync(); cin.get(); return 0; }
-
ZetaGamma schrieb:
Gilt Rückgabetyp=Rückgabewert? [...]
Mit Parametertyp sind die zu deklarierenden Werte gemeint mit welchen programmiet werden im Unterprogramm. Gilt Parametertyp=Parameterwert?Dass macht keinen Sinn, denn es gilt immer Typ!=Wert.
Eine Funktion ist vergleichbar mit einer mathematischen Funktion. Man steckt Werte hinein und bekommt andere zurück.
Z.B. f(x) = x*x
Dann gilt: f(4) = 16 und f(-1) = 1
Im Gegensatz zu mathematischen Funktionen können sie in C++ aber nicht nur berechnen, sondern jede Art einer gültigen Anweisung bearbeiten.
-
Danke, das habe ich auch gelesen. Können sie sich eventuell
http://www.youtube.com/watch?v=VFkQK0h_Jf4
bei 6:20 anschauen? Ich verstehe einfach nicht wieso 4 Variablen deklariert werden. Wieso C=A und D=B ist macht mich sehr verwirrend. Wieso kann ich nicht einfach immer A und B nutzen und wieso muss ich das so machen, obwohl sie anscheinend dieselben Werte sind? Das ist sehr verwirrend und schwer. Zumindest wenn man dort nicht durchblickt!
-
Wenn du es wirklich lernen willst, musst du dir andere Quellen als solche Videos suchen. Nicht nur, dass Videos generell ein schlechtes Medium für solchen Stoff darstellen, der Typ, der das macht, ist auch offensichtlich nicht gerade ein Experte...
-
Das mach ich bereits, aber ich blicke wie gesagt da auch nicht durch, da ich auf dieselben Probleme stoße. Zum Beispiel in Bezug zu zwei folgenden Codes:
#include <iostream> using namespace std; //Prototypen von allen Funtkionen im Programm [b]void addition();[/b]//ohne Rückgabewert, ohne Übergabeparameter int main(void) { [b] addition();[/b] cin.sync(); cin.get(); return 0; } [b]void addition()[/b] { float zahl_1, zahl_2; cout << "Zahl 1 eingeben: "; cin >> zahl_1; cout << "Zahl 2 eingeben: "; cin >> zahl_2; cout << zahl_1 + zahl_2; }
Dieser Code ist mir völlig klar. Aber bei folgendem kann ich schon nicht mehr folgen:
#include <iostream> using namespace std; //Prototypen von allen Funtkionen im Programm [b]float subtraktion();[/b]//mit Rückgabewert, ohne Übergabeparameter int main(void) { [b]cout << subtraktion();[/b] cin.sync(); cin.get(); return 0; } [b]float subtraktion()[/b] { float zahl_1, zahl_2; cout << "Zahl 1 eingeben: "; cin >> zahl_1; cout << "Zahl 2 eingeben: "; cin >> zahl_2; return zahl_1 - zahl_2; }
Z.b. Verstehe ich nicht wieso auf einmal cout genutzt wird. Aber ich habe soebend eine Idee bekommen! Es ist wahrscheinlich daher, da das Unterprogramm beim ersten direkt im Unterprogramm ausgegeben wird und im zweiten erst im Hauptprogramm ausgegeben wird oder ?
Das heißt das ich beim ersten gar keinen Rückgabewert bekomme und beim zweiten zahl_1 - zahl_2 zurück bekomme, wobei ich nun mit zahl_1 - zahl_2 im Hauptprogramm weiter arbeiten könnte. Hier wurde es z.b. im Hauptprogramm dann ausgegeben mit
cout << zahl_1 - zahl_2.
Ist das richtig ?
-
Ui ui,
warum willst du gleich mit Ein- und Ausgabe arbeiten, wenn du Funktionen lernen willst? Versuch es doch einmal zunächst im mathematischen Sinne.Sagen wir du gibst die Variable x vor und möchtest in y das Quadrat von x speichern: Wie musst du in Zeile 5 des folgenden Codes die Funktion definieren, dass du f(x) = x^2 programmiert hast?
#include <iostream> using namespace std; // hier die Funktion f definieren int main() { double x = 1.0; double y = f(x); return 0; }
Gruß,
-- Klaus.
-
Ich denke ich brauche nur mal diesen durchbruch um das richtig zu verstehen. Das fällt mir aber sehr schwer..
#include <iostream> using namespace std; double f(x); { Quadrat = x*x; return Quadrat; } int main() { double x = 1.0; double y = f(x); cout<< y; return 0; }
-
ZetaGamma schrieb:
Ich denke ich brauche nur mal diesen durchbruch um das richtig zu verstehen. Das fällt mir aber sehr schwer..
Um Funktionen zu verstehen, mußt Du zwischen dem Formalparameter und dem Aktualparameter unterscheiden.
Der Formalparameter erscheint im Kopf der Funktionsdefinition und kann im Funktionsrumpf wie eine lokale Variable benutzt werden, nur daß er nicht initialisiert werden muß. Er sollte ja nicht einmal initialisiert werden, weil das passiert nämlich beim Aufruf der Funktion durch den Aktualparameter.
Der Aktualparameter erscheint beim Aufruf der Funktion und kann eine Konstante (int oder Stringliteral etc.) oder auch eine Variable des Aufrufers sein. Die Variable des Aufrufers kann zwar den gleichen Namen wie der Formalparameter haben, muß aber nicht.
Der Aufrufer muß beim Funktionsaufruf alle formalen Parameter mit Werten versorgen. In C++ kann man aber von rechts einen, mehrere oder gar alle formalen Parameter mit Defaultwerten versehen. Ist sowas gegeben, kann der Aufrufer diese Parameter beim Funktionsaufruf weglassen stattdessen werden die Defaultwerte übergeben. Das muß aber dem Aufrufer bekannt sein, weshalb das in einer Funktionsdeklaration gemacht werden muß.
mfg Martin
-
Bashar schrieb:
Wenn du es wirklich lernen willst, musst du dir andere Quellen als solche Videos suchen. Nicht nur, dass Videos generell ein schlechtes Medium für solchen Stoff darstellen, der Typ, der das macht, ist auch offensichtlich nicht gerade ein Experte...
Über die Qualität des Autors als C++-Entwickler lässt sich nur sehr schwer was sagen. Seine didaktischen Fähigkeiten tendieren aber gegen 0. Lustig fand ich den Teil, wo er die beiden Operanden einer Summe vertauscht. Er hat ein wenig am Film geschnippselt, weshalb das irgendwie aus dem Zusammenhang fiel. Aber so weit ich weiß, lernt man das Kommutativgesetz der Addition schon in der Grundschule spätestens aber in der 5. Klasse.
mfg Martin
-
So die zwei Situationen ohne Rückgabewert/Ohne Übergabeparameter und Mit Rückgabewert/Ohne Übergabeparameter verstehe ich nun. Auch was der Formalparameter macht ist mir nun klar. Er ist eine Art deklarierter Wert, bloß als eigenes Programm.
Können Sie mir eventuell nur erklären, wie der Computer hier denkt bei den markierten Stellen:
#include <iostream> using namespace std; //Prototypen von allen Funtkionen im Programm void multiplikation(float zahl_1, float zahl_2);/*ohne Rückgabewert, mit Übergabeparameter*/ int main(void) { [b]float zahl_1, zahl_2;[/b] cout << "Zahl 1 eingeben: "; cin >> zahl_1; cout << "Zahl 2 eingeben: "; cin >> zahl_2; multiplikation(zahl_1, zahl_2);//ohne Rückgabewert, mit Übergabeparameter cin.sync(); cin.get(); return 0; } void multiplikation [b](float a, float b)[/b] { cout << a * b; }
Ich sehe vier verschiedene Variablen. Dabei sind zahl_2 und zahl_2 deklarierte Variablen. Initialisiert werden diese durch die Eingabe vom Benutzer aus. Wieso das float a und float b ? Das versteh ich nicht. Wieso a*b ? Wieso nicht zahl_1 * zahl_2 ?
-
Hallo ZetaGamma,
ZetaGamma schrieb:
#include <iostream> using namespace std; double f(x); { Quadrat = x*x; return Quadrat; }
Da sind schon ein paar richtige Ideen dabei:
Zeile 5: Richtig, dass du den Rückgabewert der Funktion definierst, nämlich double. Auch richtig, dass der Funktionsname f lautet. Unvollständig: Die Funktion weiß noch nicht welchen Typ sie als x übergeben bekommt, als muss aus
double f(x)
eindouble f(double x)
werden.
Falsch ist noch in Zeile 5, dass du mit Semikolon abschließt, es muss der Rumpf - das in geschweiften Klammern folgen, alsodouble f(double x) { // Inhalt ... }
Falsch ist noch in Zeile 7, dass die Variable Quadrat innerhalb der Funktion (also innerhalb der geschweiften Klammern von Zeile 7 bis 11) nicht definiert ist, also eher
double f(double x) { double Quadrat = x * x; return Quadrat; }
Klar soweit?
Gruß,
-- Klaus.
-
Da fehlen wohl noch mehr Begriffe. Deklaration, Definition, Initialisierung.
Eine Deklaration teilt dem Compiler mit, daß es was gibt. Das Objekt wird aber nicht im Speicher angelegt. Bei Variablen macht man dies nur für globale Variablen. Beispiele sind
extern int myGlobalStuff; int myFunction( int, int ); class myClass;
Eine Definition teilt dem Compiler mit, daß er Daten oder Code im Speicher anlegen muß. Beispiele:
int myVariable; int myFunc( int param ) { return param; } class myClass { int member; }
EDIT: Bei Typdefinitionen wird natürlich nichts im Speicher erzeugt.
Eine Initialisierung gibt es nur für Variablen. Da wird der initiale Wert reingeschrieben
myVariable = 0;
Die Initialiserung und Deklaration kann (muß aber nicht) in einem Schrit erfolgen:
int myVar=0;
Eine Externdeklaration einer Variablen mit Initialiserung ist auch gleich eine Definition:
extern int myVar = 0;
Eine Definition ist auch immer eine Deklaration. Umgekehrt gilt dies nicht.
Deklarieren darfst Du jedes Objekt beliebig oft, definieren aber nur einmal. Mehrere Deklaration dürfen sich aber nicht widersprechen. Daher deklariert man jedes Objekt nur einmal in der Headerdatei (falls man es in anderen Modulen braucht) oder am Anfang der Quelldatei.
Variablen darfst Du beliebig oft initialiseren, allerdings überschreibt jede Initialiserung die Werte der vorhergehenden Initialiserungen.
Bei der Definition einer globalen oder statischen Variablen wird der Speicher für die Variable im Datensegment des Programmes reserviert. Bei der Definition einer Funktion wird dies im Codesegment gemacht.
Bei der Definition einer lokalen Variable wird dies für gewöhnlich auf dem Stack der CPU passieren. Es kann aber auch ein Register benutzt werden. Das gleiche gilt aber auch für Funktionsparameter. Bei Variablen ist die Funktions selbst dafür verantwortlich, sich den Platz auf dem Stack zu reservieren. Bei Funktionsparametern ist des der Aufrufer nicht die aufgerufene Funktion, die den Stack entsprechend manipuliert. Muß ja auch sein, da der Aufrufer ja schließlich die Aktualparameter in die Formalparameter schreiben muß. Das Aufräumen des Stacks geschieht dann immer hinterher. Bei den Parameter nachdem die aufgerufene Funktion beendet wurde *). Bei lokalen Varablen bevor die Funktion zurück springt.
Zu Deinem Code:
Zeile 12 reserviert zwei float variablen auf dem Stack.
In Zeile 18 wird der Inhalt der beiden Variablen auf den Stack geschrieben und somit der Speicher für die beiden Formalparameter in Zeile 25 reserviert. Zeile 27 liest dann genau diesen Speicher nicht aber den aus Zeile 12.mfg Martin
Es gibt zwar noch andere Aufrufkonventionen aber wir wollen heute nicht übertreiben.
-
mgaeckler schrieb:
EDIT: Bei Typdefinitionen wird natürlich nichts im Speicher erzeugt.
Da fällt mir noch ein, der Unterschied zwischen einer Typdefinition und einer -deklaration ist.
Nach einer Typdeklaration darfst Du den Typ benutzen, wann immer ein Typ gefragt wird aber solange der Compiler nicht die Größe kennen muß. Wenn der Compiler die Größe kennen muß, um z.B. eine Variable zu definieren, muß auch der Typ definiert sein.mfg Martin
-
mgaeckler schrieb:
Bashar schrieb:
Wenn du es wirklich lernen willst, musst du dir andere Quellen als solche Videos suchen. Nicht nur, dass Videos generell ein schlechtes Medium für solchen Stoff darstellen, der Typ, der das macht, ist auch offensichtlich nicht gerade ein Experte...
Über die Qualität des Autors als C++-Entwickler lässt sich nur sehr schwer was sagen.
Doch, guck dir Folge #17 an.
-
Bashar schrieb:
mgaeckler schrieb:
Bashar schrieb:
Wenn du es wirklich lernen willst, musst du dir andere Quellen als solche Videos suchen. Nicht nur, dass Videos generell ein schlechtes Medium für solchen Stoff darstellen, der Typ, der das macht, ist auch offensichtlich nicht gerade ein Experte...
Über die Qualität des Autors als C++-Entwickler lässt sich nur sehr schwer was sagen.
Doch, guck dir Folge #17 an.
Also wirklich!
Hat doch glatt vergesen den Speicher am Ende des Programmes zu löschen:for (iter = list.begin(); iter != list.end(); ++iter) { delete &*iter; }
Böses Speicherleck.
-
Not sure if joking...
Ich hoffe mgaeckler macht sich ein eigenes Bild. Und der OP lässt sich nicht verwirren.
-
Bashar schrieb:
Not sure if joking...
Ja, joking.
Hätt ich net machen sollen.
-
Nathan schrieb:
Bashar schrieb:
Not sure if joking...
Ja, joking.
Hätt ich net machen sollen.Richtig. Das Problem ist, daß ja die meisten Programmiertechniken, die Anfänger lernen sollen, erfunden wurden, um komplexe Programme sicher entwickeln zu können. Viele der Programmiertechniken, die bei Profis so verpönt sind (globale Variablen, vergessen der Speicherfreigabe etc.), können bei simplen Helloworldprogrammen problemlos benutzt werden. Vergessener Speicher wird vom OS recycled. Probleme mit globalen Variablen treten bei simplen Programmen eher nicht auf bzw. können leicht beherscht werden.
Programmierer wollen aber über das Anfängerstadium hinaus. Dann müssen solche Techniken ins Fleisch und Blut übergangen sein. Daher sollten auch solche Tutorials, die für Anfänger gedacht sind, solche Techniken verwenden.
Eine Integervariable mit new zu erzeugen und dieses nie freizugeben ist daher dumm. Sowas hat in einem Tutorial nichts verloren. Überhaupt stellt sich die Frage, warum er eine Variable mit new erzeugt. Eine lokale Variable hätte es auch getan.
Sicher, auch ich mache mir nicht immer die Mühe, wenn ich hier Beispielcode poste, alle Facetten aus zu formulieren. Das ist aber dann OK, wenn es für die Beantwortung der aktuellen Frage nicht notwendig ist, und ich schreibe es auch (fast) immer dazu.
mfg Martin
-
mgaeckler schrieb:
Überhaupt stellt sich die Frage, warum er eine Variable mit new erzeugt.
Weil er so einiges nicht kapiert hat.
Für alle, die das Video auch nicht angesehen haben, er macht etwa sowas:
std::list<int> liste; std::list<int>::iterator it; for (int i = 0; i < 10; i++) { int *p = new int(10 + i); liste.push_back(*p); } for (it = liste.begin(); it != liste.end; it++) { cout << *it << endl; // Hier stand zuerst nur cout << it << endl, dann kommt eine Bemerkung wie // "Ach wir haben ja Pointer in der Liste", und er fügt das Sternchen hinzu }
Sorry, aber da kann man ja mehr von Jürgen Wolf lernen.
-
Bashar schrieb:
mgaeckler schrieb:
Überhaupt stellt sich die Frage, warum er eine Variable mit new erzeugt.
Weil er so einiges nicht kapiert hat.
Für alle, die das Video auch nicht angesehen haben, er macht etwa sowas:
std::list<int> liste; std::list<int>::iterator it; for (int i = 0; i < 10; i++) { int *p = new int(10 + i); liste.push_back(*p); } for (it = liste.begin(); it != liste.end; it++) { cout << *it << endl; // Hier stand zuerst nur cout << it << endl, dann kommt eine Bemerkung wie // "Ach wir haben ja Pointer in der Liste", und er fügt das Sternchen hinzu }
Sorry, aber da kann man ja mehr von Jürgen Wolf lernen.
Das Video habe ich gar nicht gesehen. Der wiederholt seinen Scheiß auch noch.
mfg Martin