Einführung
In diesem Lab lernst du die Funktionen in C++. Du wirst lernen, wie Funktionen definiert und aufgerufen werden, und wie Argumente an Funktionen übergeben werden.
💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken
In diesem Lab lernst du die Funktionen in C++. Du wirst lernen, wie Funktionen definiert und aufgerufen werden, und wie Argumente an Funktionen übergeben werden.
Manchmal muss ein bestimmter Codeabschnitt mehrfach verwendet werden. Es ist besser, ihn in eine „Unterroutine“ – Funktion – zu packen und diese Funktion mehrfach zu „aufrufen“ – um Wartbarkeit und Verständlichkeit zu gewährleisten.
Beim Verwenden einer Funktion sind zwei Parteien beteiligt: Der Anrufer, der die Funktion aufruft, und die aufgerufene Funktion. Der Anrufer übergibt Argument(e) an die Funktion. Die Funktion empfängt diese Argument(e), führt die im Funktionskörper programmierte Operation durch und gibt ein Ergebnis an den Anrufer zurück.
Angenommen, wir müssen die Fläche eines Kreises vielfach berechnen. Es ist besser, eine Funktion namens getArea()
zu schreiben und sie bei Bedarf wiederzuverwenden.
/* Test Function */
#include <iostream>
using namespace std;
const int PI = 3.14159265;
// Funktionsprototyp (Funktionsdeklaration)
double getArea(double radius);
int main() {
double radius1 = 1.1, area1, area2;
// rufe die Funktion getArea() auf
area1 = getArea(radius1);
cout << "area 1 is " << area1 << endl;
// rufe die Funktion getArea() auf
area2 = getArea(2.2);
cout << "area 2 is " << area2 << endl;
// rufe die Funktion getArea() auf
cout << "area 3 is " << getArea(3.3) << endl;
}
// Funktionsdefinition
// Gib die Fläche eines Kreises für einen gegebenen Radius zurück
double getArea(double radius) {
return radius * radius * PI;
}
Ausgabe:
area 1 is 3.63
area 2 is 14.52
area 3 is 32.67
In C++ musst du einen Funktionsprototyp deklarieren (bevor die Funktion verwendet wird) und eine Funktionsdefinition angeben, die einen Körper enthält, der die programmierten Operationen aufweist.
Die Syntax für die Funktionsdefinition lautet wie folgt:
returnValueType functionName ( parameterList ) {
functionBody ;
}
Ein Funktionsprototyp gibt der Compiler die Schnittstelle der Funktion an, d.h. den Rückgabetyp, den Funktionsnamen und die Liste der Parametertypen (die Anzahl und der Typ der Parameter). Die Funktion kann nun an beliebiger Stelle in der Datei definiert werden. Beispielsweise:
// Funktionsprototyp - platziert vor der Verwendung der Funktion.
double getArea(double); // ohne Parametername
double getArea(double radius); // Parameternamen werden ignoriert, dienen aber als Dokumentation
Der Rückgabetyp "void"
Wenn es nicht erforderlich ist, einen Wert an den Anrufer zurückzugeben, kannst du seinen Rückgabetyp als void
deklarieren. Im Funktionskörper kannst du eine Anweisung "return;
" ohne Rückgabewert verwenden, um die Steuerung an den Anrufer zurückzugeben.
Aktuelle Parameter vs. formale Parameter
Im obigen Beispiel ist die Variable (double radius)
, die in der Signatur von getArea(double radius)
deklariert ist, als formaler Parameter bekannt. Sein Gültigkeitsbereich liegt innerhalb des Funktionskörpers. Wenn die Funktion von einem Anrufer aufgerufen wird, muss der Anrufer sogenannte aktuelle Parameter (oder Argumente) liefern, deren Wert dann für die tatsächliche Berechnung verwendet wird. Beispielsweise ist bei der Funktionsoberfläche "area1 = getArea(radius1)
" radius1
der aktuelle Parameter mit einem Wert von 1.1
.
Gültigkeitsbereich von lokalen Variablen und Parametern einer Funktion
Alle Variablen, einschließlich der Parameter einer Funktion, die innerhalb einer Funktion deklariert werden, sind nur der Funktion verfügbar. Sie werden erstellt, wenn die Funktion aufgerufen wird, und freigegeben (zerstört) nachdem die Funktion zurückkehrt. Sie werden als lokale Variablen bezeichnet, weil sie der Funktion lokal sind und außerhalb der Funktion nicht verfügbar sind.
C++ führt sogenannte Standardargumente für Funktionen ein. Diese Standardwerte werden verwendet, wenn der Anrufer das entsprechende aktuelle Argument beim Aufruf der Funktion weglässt. Standardargumente werden im Funktionsprototyp angegeben und können in der Funktionsdefinition nicht wiederholt werden. Die Standardargumente werden anhand ihrer Positionen aufgelöst. Daher können sie nur verwendet werden, um die folgenden Argumente zu ersetzen, um eine Mehrdeutigkeit zu vermeiden. Beispielsweise:
/* Test Function default arguments */
#include <iostream>
using namespace std;
// Funktionsprototyp - Gib hier die Standardargumente an
int fun1(int = 1, int = 2, int = 3);
int fun2(int, int, int = 3);
int main() {
cout << fun1(4, 5, 6) << endl; // Keine Standardwerte
cout << fun1(4, 5) << endl; // 4, 5, 3(Standard)
cout << fun1(4) << endl; // 4, 2(Standard), 3(Standard)
cout << fun1() << endl; // 1(Standard), 2(Standard), 3(Standard)
cout << fun2(4, 5, 6) << endl; // Keine Standardwerte
cout << fun2(4, 5) << endl; // 4, 5, 3(Standard)
// cout << fun2(4) << endl;
// Fehler: Zu wenige Argumente für die Funktion 'int fun2(int, int, int)'
}
int fun1(int n1, int n2, int n3) {
// Standardargumente können in der Funktionsdefinition nicht wiederholt werden
return n1 + n2 + n3;
}
int fun2(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
Ausgabe:
15
12
9
6
15
12
C++ führt die Funktionsüberladung (oder Funktionspolymorphismus) ein, die es Ihnen ermöglicht, mehrere Versionen des gleichen Funktionsnamens zu haben, die durch die Parameterliste (Anzahl, Typ oder Reihenfolge der Parameter) unterschieden werden. Überladene Funktionen können nicht anhand des Rückgabetyps unterschieden werden (Compilerfehler). Die Version, die der Argumentliste des Anrufers entspricht, wird ausgewählt, um ausgeführt zu werden. Beispielsweise:
/* Test Function Overloading */
#include <iostream>
using namespace std;
void fun(int, int, int); // Version 1
void fun(double, int); // Version 2
void fun(int, double); // Version 3
int main() {
fun(1, 2, 3); // version 1
fun(1.0, 2); // version 2
fun(1, 2.0); // version 3
fun(1.1, 2, 3); // version 1 - double 1.1 wird zu int 1 umgewandelt (ohne Warnung)
// fun(1, 2, 3, 4);
// Fehler: keine passende Funktion für den Aufruf 'fun(int, int, int, int)'
// fun(1, 2);
// Fehler: Der Aufruf der überladenen Funktion 'fun(int, int)' ist mehrdeutig
// Hinweis: Kandidaten sind:
// void fun(double, int)
// void fun(int, double)
// fun(1.0, 2.0);
// Fehler: Der Aufruf der überladenen Funktion 'fun(double, double)' ist mehrdeutig
}
void fun(int n1, int n2, int n3) { // version 1
cout << "version 1" << endl;
}
void fun(double n1, int n2) { // version 2
cout << "version 2" << endl;
}
void fun(int n1, double n2) { // version 3
cout << "version 3" << endl;
}
Ausgabe:
version 1
version 2
version 3
version 1
Sie können auch Arrays an Funktionen übergeben. Allerdings müssen Sie auch die Größe des Arrays an die Funktion übergeben. Dies liegt daran, dass es keine Möglichkeit gibt, die Größe des Arrays aus dem Arrayargument innerhalb der aufgerufenen Funktion zu ermitteln. Beispielsweise:
/* Function to compute the sum of an array */
#include <iostream>
using namespace std;
// Funktionsprototyp
int sum(int array[], int size); // Die Arraygröße muss ebenfalls übergeben werden
void print(int array[], int size);
// Testtreiber
int main() {
int a1[] = {8, 4, 5, 3, 2};
print(a1, 5); // {8,4,5,3,2}
cout << "sum is " << sum(a1, 5) << endl; // sum is 22
}
// Funktionsdefinition
// Gib die Summe des gegebenen Arrays zurück
int sum(int array[], int size) {
int sum = 0;
for (int i = 0; i < size; ++i) {
sum += array[i];
}
return sum;
}
// Drucke die Inhalte des gegebenen Arrays
void print(int array[], int size) {
cout << "{";
for (int i = 0; i < size; ++i) {
cout << array[i];
if (i < size - 1) {
cout << ",";
}
}
cout << "}" << endl;
}
Ausgabe:
{8,4,5,3,2}
sum is 22
Es gibt zwei Möglichkeiten, wie ein Parameter an eine Funktion übergeben werden kann: Call-by-Value vs. Call-by-Reference.
Call-by-Value
Beim Call-by-Value wird eine "Kopie" des Arguments erstellt und an die Funktion übergeben. Die aufgerufene Funktion arbeitet auf der "Klonversion" und kann die ursprüngliche Kopie nicht modifizieren. In C/C++ werden grundlegende Datentypen (wie int
und double
) call-by-value übergeben.
/* Fundamental types are passed by value into Function */
#include <iostream>
using namespace std;
// Funktionsprototypen
int inc(int number);
// Testtreiber
int main() {
int n = 8;
cout << "Before calling function, n is " << n << endl; // 8
int result = inc(n);
cout << "After calling function, n is " << n << endl; // 8
cout << "result is " << result << endl; // 9
}
// Funktionsdefinitionen
// Gib number+1 zurück
int inc(int number) {
++number; // Modifiziere Parameter, hat keine Auswirkung auf den Aufrufer
return number;
}
Ausgabe:
Before calling function, n is 8
After calling function, n is 8
result is 9
Call-by-Reference
Andererseits wird beim Call-by-Reference eine Referenz auf die Variable des Aufrufers an die Funktion übergeben. Mit anderen Worten, die aufgerufene Funktion arbeitet auf den gleichen Daten. Wenn die aufgerufene Funktion den Parameter modifiziert, wird auch die gleiche Kopie des Aufrufers modifiziert. In C/C++ werden Arrays call-by-reference übergeben. C/C++ erlaubt es nicht, dass Funktionen ein Array zurückgeben.
/* Function to increment each element of an array */
#include <iostream>
using namespace std;
// Funktionsprototypen
void inc(int array[], int size);
void print(int array[], int size);
// Testtreiber
int main() {
int a1[] = {8, 4, 5, 3, 2};
// Bevor die Inkrementierung
print(a1, 5); // {8,4,5,3,2}
// Inkrementiere
inc(a1, 5); // Array wird call-by-reference übergeben (hat Nebenwirkungen)
// Nach der Inkrementierung
print(a1, 5); // {9,5,6,4,3}
}
// Funktionsdefinitionen
// Inkrementiere jedes Element des gegebenen Arrays
void inc(int array[], int size) { // array[] ist nicht const
for (int i = 0; i < size; ++i) {
array[i]++; // Nebenwirkung
}
}
// Drucke die Inhalte des gegebenen Arrays
void print(int array[], int size) {
cout << "{";
for (int i = 0; i < size; ++i) {
cout << array[i];
if (i < size - 1) {
cout << ",";
}
}
cout << "}" << endl;
}
Ausgabe:
{8,4,5,3,2}
{9,5,6,4,3}
Verwenden Sie const
, wann immer möglich, wenn Sie Referenzen übergeben, da dies verhindert, dass Sie die Parameter versehentlich modifizieren und Sie vor vielen Programmierfehlern schützt.
Beim linearen Suchen wird der Suchschlüssel linear mit jedem Element des Arrays verglichen. Wenn es eine Übereinstimmung gibt, wird der Index des übereinstimmenden Elements zurückgegeben; andernfalls wird -1 zurückgegeben. Der lineare Suchalgorithmus hat eine Komplexität von O(n).
/* Search an array for the given key using Linear Search */
#include <iostream>
using namespace std;
int linearSearch(const int a[], int size, int key);
int main() {
const int SIZE = 8;
int a1[SIZE] = {8, 4, 5, 3, 2, 9, 4, 1};
cout << linearSearch(a1, SIZE, 8) << endl; // 0
cout << linearSearch(a1, SIZE, 4) << endl; // 1
cout << linearSearch(a1, SIZE, 99) << endl; // 8 (nicht gefunden)
}
// Search the array for the given key
// If found, return array index [0, size-1]; otherwise, return size
int linearSearch(const int a[], int size, int key) {
for (int i = 0; i < size; ++i) {
if (a[i] == key) return i;
}
// a[0] = 1;
// Dies führt zu einem Fehler, weil a[] konstant ist, was bedeutet, dass es nur lesbar ist
return -1;
}
Ausgabe:
0
1
-1
Sie können einen Parameter eines grundlegenden Typs per Referenz übergeben, indem Sie den Referenzparameter verwenden, der durch &
gekennzeichnet ist.
/* Test Pass-by-reference for fundamental-type parameter
via reference declaration */
#include <iostream>
using namespace std;
int squareByValue (int number); // Call-by-value
void squareByReference (int &number); // Call-by-reference
int main() {
int n1 = 8;
cout << "Before call, value is " << n1 << endl; // 8
cout << squareByValue(n1) << endl; // keine Nebenwirkung
cout << "After call, value is " << n1 << endl; // 8
int n2 = 9;
cout << "Before call, value is " << n2 << endl; // 9
squareByReference(n2); // Nebenwirkung
cout << "After call, value is " << n2 << endl; // 81
}
// Übergebe Parameter per Wert - keine Nebenwirkung
int squareByValue (int number) {
return number * number;
}
// Übergebe Parameter per Referenz, indem Sie als Referenz (&) deklarieren
// - mit Nebenwirkung für den Aufrufer
void squareByReference (int &number) {
number = number * number;
}
Ausgabe:
Before call, value is 8
64
After call, value is 8
Before call, value is 9
After call, value is 81
###2.8 Mathematische Funktionen
C++ stellt in der Bibliothek <cmath>
viele häufig verwendete mathematische Funktionen zur Verfügung
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x):
Nehmen Argument- und Rückgabetyp von float, double, long double.
sinh(x), cosh(x), tanh(x):
Hyperbelfunktionen.
pow(x, y), sqrt(x):
Potenz und Quadratwurzel.
ceil(x), floor(x):
Gibt die Decke und den Boden des Gleitkommazahls als Ganzzahl zurück.
fabs(x), fmod(x, y):
Gleitkomma-Absolutwert und Modulo.
exp(x), log(x), log10(x):
Exponenten- und Logarithmusfunktionen.
Die cstdlib
-Headerdatei (portiert aus C's stdlib.h
) liefert eine Funktion rand()
, die eine pseudozufällige Ganzzahl zwischen 0 und RAND_MAX
(einschließlich) generiert.
/* Test Random Number Generation */
#include <iostream>
#include <cstdlib> // für rand(), srand()
#include <ctime> // für time()
using namespace std;
int main() {
// rand() generiert eine Zufallszahl im Bereich [0, RAND_MAX]
cout << "RAND_MAX is " << RAND_MAX << endl; // 32767
// Generiere 10 pseudozufällige Zahlen zwischen 0 und 99
// ohne Initialisierung des Zufallsgenerators.
// Sie erhalten die gleiche Sequenz jedes Mal, wenn Sie dieses Programm ausführen
for (int i = 0; i < 10; ++i) {
cout << rand() % 100 << " "; // benötigt <cstdlib>-Header
}
cout << endl;
// Initialisiere den Zufallsgenerator mit der aktuellen Zeit
srand(time(0)); // benötigt <cstdlib> und <ctime>-Header
// Generiere 10 pseudozufällige Zahlen
// Sie erhalten eine andere Sequenz bei jedem Ausführungsversuch,
// da die aktuelle Zeit unterschiedlich ist
for (int i = 0; i < 10; ++i) {
cout << rand() % 100 << " "; // benötigt <cstdlib>-Header
}
cout << endl;
}
Ausgabe:
RAND_MAX is 2147483647
83 86 77 15 93 35 86 92 49 21
29 0 83 60 22 55 97 80 68 87
- name: check if keyword exist
script: |
#!/bin/bash
grep -i 'rand' /home/labex/Code/test.cpp
error: Oops! We find that you didn't use "rand()" method in "test.cpp".
timeout: 3
Die Vorteile der Verwendung von Funktionen sind: