Funktionen, Prototypen Fragen
-
Also ich habe mal ein Paar Fragen zu folgendem Programm (s.U.). Ein Main-Programm soll drei Funktionen aufrufen. Eins soll 80 Zufallszahlen bestimmen und an main übergeben. Die zweite Funktion soll Mittelwert, Maximum und Minimum berechnen und an Main übergeben. Die dritte Funktion soll die Werte ausgeben. Unten zitiere ich die Programm auschnitte, zu welchen ich Fragen habe:
Ich habe hier die Lösung und habe zu dieser allerdings noch ein Paar Fragen:
#include <iostream> using namespace std; void generiereZahlen(int N, int array[]) void berechneWerte(int N, int array[], int &min, int &max, int &mid) void ausgabe(int min, int max, int mid) int main() { const int N = 10; int werte[N] = {0}; int min= 0; int max = 0; int mid= 0; generiereZahlen(N, werte); berechneWerte(N, werte, min, max, mid); ausgabe(min, max, mid); return 0; } void generiereZahlen(int N, int array[]) { srand(0); for (int i=0;i<N;i++) { array[i]=rand()%1000; } } void berechneWerte(int N, int array[], int &min, int &max, int &mid) { min = array[0]; max = array[0]; for (int i=0;i<N;i++) { mid += array[i]; if (array[i]>max) { max = array[i]; } if (array[i]<min) { min = array[i]; } } mid /= N; } void ausgabe(int min, int max, int mid) { cout << "Minimum:\t" << min << endl; cout << "Maximum:\t" << max << endl; cout << "Mittelwert:\t" << mid << endl; }Und nun zu meinen Fragen:
void generiereZahlen(int N, int array[]) void berechneWerte(int N, int array[], int &min, int &max, int &mid) void ausgabe(int min, int max, int mid)Ich weiß, dass diese Prototypenbestimmung nicht notwendig ist, wenn man die Funktionen vor main schreibt, aber wir sollen das so machen. Meine Frage ist, weil mir aufgefallen ist, dass in allen Lösungen die Zeilen der Prototypbestimmung einfach eine Kopie sind der Funktionsanfänge (Namen??), ist das immer so? Weil dann wäre der Aufwand ja auch nur minimal.
const int N = 10; int werte[N] = {0}; int min= 0; int max = 0; int mid= 0;Warum muss hier nicht int i=0; stehen, also ebenfalls deklariert werden?
for (int i=0;i<N;i++) { array[i]=rand()%1000; }Ich verstehe nicht ganz, was die Endbedingung bedeutet, also was N genau für einen Wert hat. Und wieso 80 Zahlen dann dabei rauskommen, wenn 80 nirgends Erwähnung findet?
%1000 bedeutet, dass die Zufallszahlen im Bereich zwischen 0-1000 liegen oder?void berechneWerte(int N, int array[], int &min, int &max, int &mid) { min = array[0]; max = array[0]; for (int i=0;i<N;i++) { mid += array[i]; if (array[i]>max) { max = array[i]; } if (array[i]<min) { min = array[i]; } } mid /= N; }Hier verstehe ich ganrichts mehr. Warum wir hier pointer benutzen ist mir klar, aber auf welche Adresse im Programm zeigen die gerade? Vielleicht auf die Variablendeklaration in int main?
Wieso arbeitet min und max über ein Array und mid nicht?
was bedeutet die Zeile mid /=N; also was macht die?Vielen Dank im Voraus für eure Hilfe oder zumindest fürs Interesse!
Und eine allgemeine Frage noch:
Darf i deshalb in allen Funktionen den gleichen Namen haben, weil sie nicht global ist und jede Funktion i deshalb einen anderen Wert zuweist?
-
Der Prototyp besteht nur aus der Signatur der Funktion. Und auch die Signatur muss in der Funktionsdefinition stehen. Also ja, da kannst du copy paste machen.
Du deklarierst i in der for-Schleife mit int i = 0. Du kannst in C++ Variablen in Blöcken deklarieren (eine for-Schleife ist beispielsweise ein Block). Diese sind dann einfach jeweils innerhalb des Blocks sichtbar.
Du generierst keine 80 Zufallszahlen, sondern nur 10. Dein Array hat ja nur die Länge 10 ond die for-Schleife wird nur 10 mal durchlaufen. Du müsstest N = 80 setzen für 80 Zufallszahlen.
Du übergibst die Adressen von max, min usw. Das heisst dass sich die Variablen im ganzen Programm ändern, wenn du sie in der Funktion änders. Normalerweise werden die Werte ja kopiert und es wird nur mit Kopien gearbeitet. Hier übergibst du aber die Adresse.
Was das /= bedeutet weiss ich nicht, hab ich noch nie gesehen in C++. In Eiffel bedeutet /= das selbe wie !=, also "ungleich".
Wie schon oben erwähnt kannst du Variablen in einem Block definieren, siehe C++ Scope
-
mid /= N;entspricht
mid = mid / N;
-
kjljkljk schrieb:
mid /= N;entspricht
mid = mid / N;Ui mist, das habe ich ja ganz vergessen. Bin wohl blind geworden, weil ich ein halbes Jahr lang /= als != verwenden musste ^^
-
icarus2 schrieb:
Der Prototyp besteht nur aus der Signatur der Funktion. Und auch die Signatur muss in der Funktionsdefinition stehen. Also ja, da kannst du copy paste machen.
Nein, der Prototyp besteht aus dem Rückgabetyp und der Signatur der Funktion. Bei Template-Funktionen hingegen ist der Rückgabetyp Teil der Signatur.
icarus2 schrieb:
Du übergibst die Adressen von max, min usw. Das heisst dass sich die Variablen im ganzen Programm ändern, wenn du sie in der Funktion änders. Normalerweise werden die Werte ja kopiert und es wird nur mit Kopien gearbeitet. Hier übergibst du aber die Adresse.
Ich sehe abgesehen von "werte" keine Übergabe von Adressen. Die Funktinsparameter min, max und mid sind Referenzen und somit Aliase (Aliasse?).
-
@kjljkljk: Danke, die Zeile ist mir jetzt auf jeden Fall klar.
@icarus2: Vielen Dank.
N wurde durch 80 ersetzt, scheint ein Fehler in der Lösung zu sein. Aber jetzt macht es auch Sinn und ich verstehe das wieder:)Nochmal etwas anderes:
-
Wieso deklarieres ich in main int werte [N], wenn ich mit diesem Array garnicht arbeite?, ich arbeite in den Funktionen ja nur mit int array [].
-
Bei int main, welche Dinge gehören da in die Paramaterangabe eines Funktionsaufrufs? Beispiel berechneWerte (N, werte, min, max, mid). Sind das die, die ich im Endeffekt wieder zurück in main haben will (Rückgabewerte) oder die, mit denen ich dort in der Funktion arbeiten möchte?
-
-
Doch, du übergibst das in main() erzeugte Argument an die Funktion. In der Funktion arbeitest du dann mit diesem Array.
Beides. Es gibt in C++ einen Unterschied zwischen Call by reference und Call by value. Bei ersterem übergibst du eine Referenz auf das Objekt. Beim zweiten wird der Wert, den du übergibst kopiert.
Da eine Funktion nur einen Rückgabewert haben kann ist call by reference eine ziemlich angenehme sache.Als Beispiel für eine Funktion mit call by reference und call by value:
void add_by_val( int a, int b ) { a += b; } void add_by_ref( int &a, int b ) { a += b; } int main() { int a = 10; cout << a << endl; add_by_val(a, 5); // Hier bleibt a in main gleich gleich cout << a << endl; add_by_ref(a, 5); // Hier wird a in main um 5 erhöht cout << a << endl; }Falls du es noch nicht verstehst google mal nach call by value und call by reference.
-
boenz666 schrieb:
Nochmal etwas anderes:
- Wieso deklarieres ich in main int werte [N], wenn ich mit diesem Array garnicht arbeite?, ich arbeite in den Funktionen ja nur mit int array [].
Die Variable werte in main hat den Typ int[10] (wenn const int N = 10).
Beim Aufruf einer deiner Funktionen zerfällt das array in einen Pointer, der auf das erste Element des arrays zeigt. Diesen Pointer übergibst du per value an die Funktion. Dabei wird der Pointer kopiert und mit dieser Kopie wird der Funktionsparameter initialisiert.
Lass dich nicht täuschen:void generiereZahlen(int N, int array[])ist absolut das gleiche wie:
void generiereZahlen(int N, int * array)Innerhalb der Funktion arbeitest du nun mit dem Pointer namens array der nach wie vor auf das erste Element des erstellten arrays zeigt (werte in main).
boenz666 schrieb:
- Bei int main, welche Dinge gehören da in die Paramaterangabe eines Funktionsaufrufs? Beispiel berechneWerte (N, werte, min, max, mid). Sind das die, die ich im Endeffekt wieder zurück in main haben will (Rückgabewerte) oder die, mit denen ich dort in der Funktion arbeiten möchte?
Da Funktionen nur einen Wert zurückgeben können kann man Argumente per reference übergeben, wenn eigentlich mehrere Werte zurückgegeben werden sollten.
Somit können die Werte innerhalb der Funktion geändert werden, da du nicht auf Kopien arbeitest, sondern mit Alias-Namen für die ursprünglichen Variablen.
In deinem Beispiel betrifft das min, max und mid.
N und werte werden per value übergeben, es werden also Kopien davon erstellt (im Fall von werte allerdings um eine Kopie eines pointers, da der array eben zu einem pointer zerfällt).
-
Wow, zwei Beiträge, welche sich mir definitiv die Materie besser erschließen lassen. Finde das Thema schon reichlich schwer und danke euch, mir da ein Stück weit weitergeholfen zu haben.
-
Nur noch eine kleine Ergänzung, weil ich mir nicht sicher bin, ob du das ganz verstanden hast:
Grundsätzlich existieren Variablennamen nur innerhalb ihres Gültigkeitsbereiches (z.B. innerhalb der Funktion). Wenn du Variablen an eine Funktion übergibst, gelten für diese Funktion die Namen, die du den Parametern gegeben hast.
int foo(int & i); int main() { int a = 4; // Gültigkeitsbereich: main-Funktion foo(a); } int foo(int & i) { // Der Bezeichner "a" ist hier unbekannt, in dieser Funktion existiert eine // Variable mit der Bezeichnung "i" (selbst wenn es sich in diesem Fall // [Referenz] tatsächlich um die Variable aus der main-Funktion handelt). }