Parameter | Kursinformationen |
---|---|
Veranstaltung: | @config.lecture |
Semester | @config.semester |
Hochschule: | Technische Universität Freiberg |
Inhalte: | Funktionen |
**Link auf Repository: ** | https://github.com/TUBAF-IfI-LiaScript/VL_EAVD/blob/master/04_Funktionen.md |
Autoren | @author |
Fragen an die heutige Veranstaltung ...
- Welche Komponenten beschreiben Definition einer Funktion?
- Wozu werden in der Funktion die Parameter gebraucht?
- Wann ist es sinnvoll Referenzen-Parameter zu verwenden?
- Warum ist es sinnvoll Funktionen in Look-Up-Tables abzubilden, letztendlich kostet das Ganze doch Speicherplatz?
Erklären Sie die Idee hinter folgendem Code.
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
#define VALUECOUNT 17
int main(void) {
int a [] = {1,2,3,3,4,2,3,4,5,6,7,8,9,1,2,3,4};
// Ergebnis Histogramm
int hist[10] = {0,0,0,0,0,0,0,0,0,0};
// Ergebnis Mittelwert
int summe = 0;
// Ergebnis Standardabweichung
float abweichung = 0;
for (int i=0; i<VALUECOUNT; i++){
hist[a[i]]++;
summe += a[i];
}
float mittelwert = summe / (float)VALUECOUNT;
for (int i=0; i<VALUECOUNT; i++){
abweichung += pow((a[i]-mittelwert),2.);
}
// Ausgabe
for (int i=0; i<12; i++){
std::cout << std::setw(2) << i << " ";
}
std::cout << std::endl;
for (int i=0; i<12; i++){
std::cout << std::setw(2) << a[i] << " ";
}
std::cout << std::endl;
// Ausgabe Mittelwert
cout<<"Die Summe betraegt "<<summe<<", der Mittelwert "<<mittelwert<<"\n";
// Ausgabe Standardabweichung
float stdabw = sqrt(abweichung / VALUECOUNT);
cout<<"Die Standardabweichung der Grundgesamtheit betraegt "<<stdabw<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
Für die Verbesserung des Verständnisses bei der Generierung des Histogramms hat einer Ihrer Kommilitonen eine sehr anschauliche grafische Darstellung vorbereitet. Vielen Dank dafür!
Sie wollen den Code in einem neuen Projekt wiederverwenden. Was sind die Herausforderungen dabei?
Stellen Sie das Programm so um, dass es aus einzelnen Bereichen besteht und überlegen Sie, welche Variablen wo gebraucht werden.
Bessere Lesbarkeit
Der Quellcode eines Programms kann schnell mehrere tausend Zeilen umfassen. Beim Linux Kernel sind es sogar über 15 Millionen Zeilen und Windows, das ebenfalls zum Großteil in C geschrieben wurde, umfasst schätzungsweise auch mehrere Millionen Zeilen. Um dennoch die Lesbarkeit des Programms zu gewährleisten, ist die Modularisierung unerlässlich.
Wiederverwendbarkeit
In fast jedem Programm tauchen die gleichen Problemstellungen mehrmals auf. Oft gilt dies auch für unterschiedliche Applikationen. Da nur Parameter und Rückgabetyp für die Benutzung einer Funktion bekannt sein müssen, erleichtert dies die Wiederverwendbarkeit. Um die Implementierungsdetails muss sich der Entwickler dann nicht mehr kümmern.
Wartbarkeit
Fehler lassen sich durch die Modularisierung leichter finden und beheben. Darüber hinaus ist es leichter, weitere Funktionalitäten hinzuzufügen oder zu ändern.
Finden Sie Fehler im zuvor gezeigten Code?
In allen 3 Aspekten ist der Vorteil in der Kapselung der Funktionalität zu suchen.
Funktionen sind Unterprogramme, die ein Ausgangsproblem in kleine, möglicherweise wiederverwendbare Codeelemente zerlegen.
#include <iostream>
using namespace std;
// Funktion für den Mittelwert
// Mittelwert = f_Mittelwert(daten)
// Funktion für die Standardabweichung
// Standardabweichung = f_Standardabweichung(daten)
// Funktion für die Histogrammgenerierung
// Histogramm = f_Histogramm(daten)
// Funktion für die Ausgabe
// f_Ausgabe(daten, {Mittelwert, Standardabweichung, Histogramm})
int main(void) {
int a[] = {3,4,5,6,2,3,2,5,6,7,8,10};
// b = f_Mittelwert(a) ...
// c = f_Standardabweichung(a) ...
// d = f_Histogramm(a) ...
// f_Ausgabe(a, b, c, d) ...
return 0;
}
Wie findet sich diese Idee in großen Projekten wieder?
Write Short Functions
Prefer small and focused functions.
We recognize that long functions are sometimes appropriate, so no hard limit is placed on functions length. If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program.
Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it easier for other people to read and modify your code.
You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.
[Google Sthttps://stackoverflow.com/questions/2485963/c-alignmtionen
Rückgabedatentyp Funktionsname([Parameterliste]) {
/* Anweisungsblock mit Anweisungen */
[return Rückgabewert]
}
-
Rückgabedatentyp - Welchen Datentyp hat der Rückgabewert?
Eine Funktion ohne Rückgabewert wird vom Programmierer als
void
deklariert. Sollten Sie keinen Rückgabetyp angeben, so wird automatisch eine Funktion mit Rückgabewert vom Datentypint
erzeugt. -
Funktionsname - Dieser Bestandteil der Funktionsdefinition ist eine eindeutige Bezeichnung, die für den Aufruf der Funktion verwendet wird.
Es gelten die gleichen Regeln für die Namensvergabe wie für Variablen.
-
Parameterliste - Parameter sind Variablen (oder Pointer bzw. Referenzen darauf) die durch einen Datentyp und einen Namen spezifiziert werden. Mehrere Parameter werden durch Kommas getrennt.
Parameterliste ist optional, die Klammern jedoch nicht. Alternative zur fehlenden Parameterliste ist die Liste aus einen Parameter vom Datentyp
void
ohne Angabe des Namen. -
Anweisungsblock - Der Anweisungsblock umfasst die im Rahmen der Funktion auszuführenden Anweisungen und Deklarationen. Er wird durch geschweifte Klammern gekapselt.
Für die Funktionen gelten die gleichen Gültigkeits- und Sichtbarkeitsregeln wie für die Variablen.
int main (void) {
/* Anweisungsblock mit Anweisungen */
}
double pow (double base, double exponent){
/* Anweisungsblock mit Anweisungen */
}
//int y = pow(25.0,0.5));
void tauschen(int &var1,int &var2){
/* Anweisungsblock mit Anweisungen */
}
int mittelwert(int * array){
/* Anweisungsblock mit Anweisungen */
}
{{0-1}}
Merke: Die Funktion (mit der Ausnahme der
main
-Funktion) wird erst ausgeführt, wenn sie aufgerufen wird. Vor dem Aufruf muss die Funktion definiert oder deklariert werden.
Der Funktionsaufruf einer Funktionen mit dem Rückgabewert kann Teil einer Anweisung, z.B. einer Zuweisung oder einer Ausgabeanweisung.
#include <iostream>
#include <cmath>
using namespace std;
void info(){
cout<<"Dieses Programm rundet Zahlenwerte.\n";
cout<<"-----------------------------------\n";
}
int runden(float a){
if (a < 0)
return (int)(a - 0.5);
else
return (int)(a + 0.5);
}
int main(void){
info();
float input = -8.4565;
cout<<"Eingabewert "<<input<<" - Ausgabewert "<<runden(input)<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
Die Funktion runden
nutzt die Funktionalität des Cast-Operators int
aus.
-
Wenn N eine positive Zahl ist, wird 0.5 addiert
-
$15.2 + 0.5 = 15.7$ int(15.7) = 15
-
$15.7 + 0.5 = 16.2$ int(16.2) = 16
-
-
Wenn N eine negative Zahl ist, wird 0.5 subtrahiert
-
$-15.2 - 0.5 = -15.7$ int(-15.7) = -15
-
$-15.7 - 0.5 = -16.2$ int(-16.2) = -16
-
{{1-2}}
Hinweis: C++ unterstützt gleiche Codenahmen bei unterschiedlichen Parametern. Der Compiler "sucht sich" die passende Funktion aus. Der Mechanismus wird als Funktionsüberladung bezeichnet.
#include <iostream>
#include <cmath>
using namespace std;
void info(){
cout<<"Dieses Programm rundet Zahlenwerte.\n";
cout<<"-----------------------------------\n";
}
int runden(float a){
if (a < 0)
return (int)(a - 0.5);
else
return (int)(a + 0.5);
}
float rundenf(float a, int nachkomma){
float shifted= a* pow(10, nachkomma);
int result=0;
if (shifted < 0)
result = int(shifted -0.5);
else
result = int(shifted +0.5);
return (float)result * pow(10, -nachkomma);
}
int main(void){
info();
float input = -8.4565;
cout<<"Eingabewert "<<input<<" - Ausgabewert "<<runden(input)<<"\n";
cout<<"Eingabewert "<<input<<" - Ausgabewert "<<rundenf(input,1)<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
Welche Verbesserungsmöglichkeit sehen Sie bei dem Programm? Tipp: Wie können wir den redundanten Code eliminieren?
Rückgabewert ohne Rückgabedefintion
void foo()
{
/* Code */
return 5; /* Fehler */
}
int main(void)
{
foo()
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
{{1}} Erwartung eines Rückgabewertes
{{1}}
#include <iostream>
using namespace std;
void foo(){
cout<<"Ausgabe";
}
int main(void) {
int i = foo();
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
{{2}} Falscher Rückgabetyp
{{2}}
#include <iostream>
using namespace std;
float foo(){
return 3.123f;
}
int main(void) {
int i = foo();
cout<<i<<"\n";
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall -Wconversion main.cpp -o a.out
, ./a.out
)
{{3}} Parameterübergabe ohne entsprechende Spezifikation
{{3}}
#include <iostream>
int foo(void){ // <- Die Funktion erwartet explizit keine Parameter
return 3;
}
int main(void) {
int i = foo(5);
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall -Wconversion main.cpp -o a.out
, ./a.out
)
{{4}} Anweisungen nach dem return-Schlüsselwort
{{4}}
int foo()
{
return 5;
/* Code */ // Wird nie erreicht!
}
{{5}} Falsche Reihenfolgen der Parameter
{{5}}
#include <iostream>
using namespace std;
void foo(int index, float wert){
cout<<"Index - Wert\n";
cout<<index<<" - "<<wert<<"\n\n";
}
int main(void) {
foo(4, 6.5);
foo(6.5, 4);
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall -Wconversion main.cpp -o a.out
, ./a.out
)
#include <iostream>
using namespace std;
// int foo(void); // Explizite Einführung der Funktion foo()
int main(void) {
int i = foo(); // <- Aufruf der Funktion
cout<<"i="<<i<<"\n";
return 0;
}
int foo(void){ // <- Definition der Funktion
return 3;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Damit der Compiler überhaupt von einer Funktion Kenntnis nimmt, muss diese vor ihrem Aufruf bekannt gegeben werden. Im vorangegangenen Beispiel wird die die Funktion erst nach dem Aufruf definiert. Der Complier zeigt dies an.
{{1}}
Das Ganze wird dann relevant, wenn Funktionen aus anderen Quellcodedateien
eingefügt werden sollen. Die Deklaration macht den Compiler mit dem Aussehen der
Funktion bekannt. Diese werden mit dem Schlüsselwort extern
markiert.
{{1}}
extern float berechneFlaeche(float breite, float hoehe);
Bisher wurden Funktionen betrachtet, die skalare Werte als Parameter erhielten und ebenfalls einen skalaren Wert als einen Rückgabewert lieferten. Allerdings ist diese Möglichkeit sehr einschränkend.
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
// Rückgabe der Ergebnisse
// +------------------------------------+
// | |
int add(int a, int b){ // <--+ |
return a+b; // | Aufruf |
} // | mit |
// | Para- |
int main(void) { // | metern |
int i = add(5, 6); //----+ |
// ^ |
// +----------------------------------+
cout<<"i="<<i<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Es wird in vielen Programmiersprachen, darunter in C/C++, zwei generelle Konzepte der Parameterübergabe realisiert.
In allen Beispielen bis jetzt wurden Parameter an die Funktionen call-by-value, übergeben. Das bedeutet, dass innerhalb der aufgerufenen Funktion mit einer Kopie der Variable gearbeitet wird und die Änderungen sich nicht auf den ursprünglichen Wert auswirken.
#include <iostream>
using namespace std;
void doSomething(int a) {
// eine KOPIE von a wird um 1 erhöht
cout << ++a << " a in der Schleife\n";
}
int main(void) {
int a = 5;
cout << a << " a in main\n";
doSomething(a);
cout << a << " a in main\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Merke: Die _Call-by-value-_Funktionen können den Wert der Variablen nicht verändern.
Bei einer Übergabe als Referenz wirken sich Änderungen an den Parametern auf die ursprünglichen Werte aus, es werden keine Kopien von Parametern angelegt. Call-by-reference wird unbedingt notwendig, wenn eine Funktion mehrere Rückgabewerte hat.
In C++ kann die "call-by-reference"- Parameterübergabe mit Hilfe der Referenzen oder Pointern realisiert werden.
{{0-1}}
#include <iostream>
using namespace std;
void inkrementieren(int &variable){
variable++;
}
int main(void) {
int a=0;
inkrementieren(a);
cout<<"a = "<<a<<"\n";
inkrementieren(a);
cout<<"a = "<<a<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Vgl. Illustration mit Python-Tutor Link
Der Vorteil der Verwendung der Referenzen als Parameter besteht darin, dass in der Funktion mehrere Variablen auf eine elegante Weise verändert werden können. Die Funktion hat somit quasi mehrere Ergebnisse.
#include <iostream>
#include <cmath>
using namespace std;
void tauschen(char &anna, char &hanna){
char aux=anna;
anna=hanna;
hanna=aux;
}
int main(void) {
char anna='A',hanna='H';
cout<<anna<<" und "<<hanna<<"\n";
tauschen(anna,hanna);
cout<<anna<<" und "<<hanna<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
{{1-2}}
Es besteht ebenfalls die Möglichkeit, "call-by-reference"- Parameterübergabe mit Hilfe der Zeiger (Pointer)
zu realisieren. Allerdings muss dann im Unterschied zur Referenz jeweils eine Dereferenzierung vorgenommen werden *a = ...
.
#include <iostream>
#include <cmath>
using namespace std;
void runden(float* a){
if (*a < 0)
*a = (int)(*a - 0.5);
else
*a = (int)(*a + 0.5);
}
int main(void) {
float value = -8.4565;
float *pointer = &value;
runden(pointer);
cout<<"Eingabewert "<<value<<" - Ausgabewert "<<*pointer<<"\n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Ein realistisches Beispiel könnte die Verwendung eines Arrays sein.
Zur Erinnerung Eine Variable, die ein Array representiert zeigt auf den ersten Eintrag.
Dabei können zwei Varianten genutzt werden - die explizte Pointerschreibweise und die Array Schreibweise - beide drücken die Übergabe eines Pointers im Sinne von Call-by-Reference aus.
#include <iostream>
#include <cmath>
using namespace std;
// Variante 1
double hypothenuse(double *lookup_sin, int winkel, double gegenkathete){
return gegenkathete/lookup_sin[winkel];
}
/*
Variante 2
double hypothenuse(double lookup_sin[], int winkel, double gegenkathete){
return gegenkathete/lookup_sin[winkel];
}
*/
int main(void) {
double sin_values[360] = {0};
for(int i=0; i<360; i++) {
sin_values[i] = sin(i*M_PI/180);
}
cout<<"Größe des Arrays "<<sizeof(sin_values)<<"\n";
cout<<"Result = "<<hypothenuse(sin_values, 30, 20)<<" \n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
Die Visualisierung des Zugriffs finden Sie in einem Python-Tutor Beispiel.
Analog zur Bereitstellung von Parametern entsprechend dem "call-by-reference" Konzept können auch Rückgabewerte als Pointer oder Referenz vorgesehen sein. Allerdings sollen Sie dabei aufpassen ...
#include <iostream>
using namespace std;
int& doCalc(int &wert) {
int a = wert + 5;
return a;
}
int main(void) {
int b = 5;
cout<<"Irgendwas stimmt nicht "<<doCalc(b);
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall main.cpp -o a.out
, ./a.out
)
Mit dem Beenden der Funktion werden deren lokale Variablen vom Stack gelöscht. Um diese Situation zu handhaben können Sie zwei Lösungsansätze realisieren.
Variante 1 Sie übergeben den Rückgabewert in der Parameterliste.
#include <iostream>
#include <cmath>
using namespace std;
void kreisflaeche(double durchmesser, double &flaeche) {
flaeche = M_PI * pow(durchmesser / 2, 2);
// Hier steht kein return !
}
int main(void) {
double wert = 5.0;
double flaeche = 0;
kreisflaeche(wert, flaeche);
cout<<"Die Kreisfläche beträgt für d="<<wert<<"[m] "<<flaeche<<"[m²] \n";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
{{1}}
Variante 2 Für den Rückgabezeiger wird der Speicherplatz mit new
dynamisch angelegt, aber Achtung: zu jedem new gehört ein delete
.
{{1}}
#include <iostream>
#include <cmath>
using namespace std;
double* kreisflaeche(double durchmesser) {
double *flaeche=new double;
*flaeche = M_PI * pow(durchmesser / 2, 2);
return flaeche;
}
int main(void) {
double wert = 5.0;
double *flaeche;
flaeche=kreisflaeche(wert);
cout<<"Die Kreisfläche beträgt für d="<<wert<<"[m] "<<*flaeche<<"[m²] \n";
delete flaeche;
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out
)
#include <iostream>
#include <cstdlib>
using namespace std;
void printSizeOf(int intArray[])
{
cout<<"sizeof of array as parameter: "<<sizeof(intArray)<<"\n";
}
void printLength(int intArray[])
{
cout<<"Length of parameter: "<<sizeof(intArray) / sizeof(intArray[0])<<"\n";
}
int main()
{
int array[] = { 0, 1, 2, 3, 4, 5, 6 };
cout<<"sizeof of array: "<<sizeof(array)<<"\n";
printSizeOf(array);
cout<<"Length of array: "<< sizeof(array) / sizeof(array[0])<<"\n";
printLength(array);
cout<<"Size of int pointer: "<< sizeof(int*) <<"\n";
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall -Wconversion main.cpp -o a.out
, ./a.out
)
In jedem Programm muss und darf nur eine main
-Funktion geben. Diese Funktion
wird beim Programmstart automatisch ausgeführt.
Definition der main
-Funktion:
int main(void) {
/*Anweisungen*/
}
int main(int argc, char *argv[]) {
/*Anweisungen*/
}
Die Bezeichner argc
und argv
sind traditionell, können aber beliebig gewählt werden.
argc
ist die Anzahl der Argumente, die von den Benutzern des Programms in der Kommandozeile angegeben werden. Der argc-Parameter ist immer größer als oder gleich 1.
argv
ist ein Array von Befehlszeilenargumenten, wobei argv[0]
das Programm selbst und argv[argc]
immer NULL ist.
Im Beispiel wird die kompilierte Version von mainArgumente.cpp intern mit ./a.out 1 2 3 aus die Maus
aufgerufen.
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
for (int i=0;i<argc;i++)
cout<<argv[i]<<" ";
return 0;
}
@LIA.eval(["main.cpp"]
, g++ -Wall main.cpp -o a.out -lm
, ./a.out 1 2 3 aus die Maus
)
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
double Mittelwert(int *values, int entries);
int Summe(int *values, int entries);
void Ausgabe(int *values, int entries);
double Mittelwert(int *values, int entries){
double summe = Summe(values, entries);
return summe / entries;
}
int Summe(int *values, int entries){
int summe = 0;
for (int i=0; i<entries; i++){
summe += values[i];
}
return summe;
}
void Ausgabe(int *values, int entries){
for (int i=0; i<entries; i++){
std::cout << std::setw(2) << i << " ";
}
std::cout << std::endl;
for (int i=0; i<entries; i++){
std::cout << std::setw(2) << values[i] << " ";
}
std::cout << std::endl;
}
int main(void) {
int a [] = {1,2,3,3,4,2,3,4,5,6,7,8,9,1,2,3,3};
const int entries = sizeof(a)/sizeof(a[0]);
Ausgabe(a, entries);
int summe = Summe(a, entries);
double mittelwert = Mittelwert(a, entries);
cout<<"Die Summe betraegt "<<summe<<", der Mittelwert "<<mittelwert<<"\n";
return 0;
}
@LIA.evalWithDebug(["main.cpp"]
, g++ -Wall -Wconversion main.cpp -o a.out
, ./a.out
)
Wechen Rückgabewert liefert eine als
void
deklarierte Funktion? [( )] Es können alle Arten von Rückgabewerten zurückgegeben werden. [(X)] Es wird kein Wert zurückgegeben.
{{1}}
Welcher Datentyp wird automatisch als Rückgabewert ausgewählt, wenn Sie keinen Rückgabetyp angeben? [( )]
void
[(X)]int
[( )]float
[( )]double
[( )]char
[( )]boolean
{{2}}
Muss die Parameterliste einer Funktionen wenigstens einen Parameter enthalten? [( )] Ja [(X)] Nein
Wodurch muss
[_____]
ersetzt werden damit die Funktiondivi
ermittelt oba
ein Teiler vonb
ist? Die Lösung ist ohne Leerzeichen einzugeben.
#include <iostream>
using namespace std;
bool divi(int x, int y){
if(x%y == 0)
return true;
else
return false;
}
int main() {
int a = 11;
int b = 1001;
bool bdiv = [_____]
if(bdiv == 1)
cout << a << " ist ein Teiler von " << b << "." << endl;
else
cout << a << " ist kein Teiler von " << b << "." << endl;
}
[[divi(b,a);]]
ist dieses Programm fehlerfrei?
#include <iostream>
using namespace std;
int foo(){
return 42;
}
int main(void) {
int i = foo();
return 0;
}
[(X)] Ja [( )] Nein
Ist dieses Programm fehlerfrei?
#include <iostream>
using namespace std;
void foo(){
return 42;
}
int main(void) {
foo();
return 0;
}
[( )] Ja [(X)] Nein
Welche Fehler liegen bei diesem Programm vor?
#include <iostream>
using namespace std;
void foo(int index, float wert){
cout<<"Index - Wert\n";
cout<<index<<" - "<<wert<<"\n\n";
return index;
}
int main(void) {
float f = foo(6.5, 4);
return 0;
}
[[X]] Datentypen der Parameter beim Aufruf und der Defintion stimmen nicht überein
[[X]] Rückgabewert ohne Definition des Rückgabetyps
[[ ]] Anweisung nach dem return
Schlüsselwort
Ersetzen Sie
[_____]
durch eine explizite Deklaration der Funktionhw
.
#include <iostream>
using namespace std;
[_____]
int main(void) {
hw();
return 0;
}
void hw(void) {
cout << "Hello World!" << endl;
return;
}
[[void hw();]]
Mit welcher dieser Anweisungen kann eine Funktion aus einer anderen Quellcodedatei einzufügt werden? [(X)]
extern int x(int y, bool z);
[( )]import int x(int y, bool z);
[( )]using int x(int y, bool z);
Ordnen Sie die Eigenschaften den entsprechenden Arten der Parameterübergabe zu.
- [[call-by-value] [call-by-reference]]
- [ ( ) (X) ] Ermöglicht mehrere Rückgabewerte
- [ (X) ( ) ] Arbeitet mit einer Kopie der Variablen
- [ (X) ( ) ] Beeinflusst nicht den tatsächlichen Wert von Variablen in der
main
- [ ( ) (X) ] Beeinflusst den tatsächlichen Wert von Variablen in der
main
Wie lautet die Ausgabe dieses Programms?
#include <iostream>
using namespace std;
void f_a(int &variable){
variable++;
}
void f_b(int variable){
variable--;
}
void f_c(int &variable){
variable = 18;
}
int main(void) {
int a = 0;
f_a(a);
f_c(a);
f_b(a);
f_b(a);
f_a(a);
cout << a;
return 0;
}
[[19]]
Womit werden Array-Parameter übergeben? [( )] Referenz [(X)] Zeiger
Wo liegt der Fehler im folgenden Programm?
#include <iostream>
using namespace std;
int& doCalc(int &wert) {
int a = wert++;
return a;
}
int main(void) {
int b = 0;
cout << doCalc(b);
return 0;
}
[(X)] Die mit return
übergebene Referenz zeigt außerhalb der Funktion doCalc
auf einen nicht existierenden Speicherplatz
[( )] Referenzen dürfen nicht für die Rückgabe mit return
verwendet werden
Für die Variable
volumen
soll der Speicherplatz dynamisch zur Verfügung gestellt werden. Ersetzen Sie[_____]
um die notwendige Ergängung der Anweisung.
#include <iostream>
#include <cmath>
using namespace std;
double* kugelvolumen(double durchmesser) {
double *volumen = [_____]
*volumen = (4.0/3.0) * M_PI * pow(durchmesser / 2, 3);
return volumen;
}
int main(void) {
double wert = 5.0;
double *volumen;
volumen = kugelvolumen(wert);
cout << "Das Kugelvolumen beträgt für d=" << wert << "[m] " << *volumen << "[m³] \n";
delete volumen;
return 0;
}
[[new double;]]
Beurteilen Sie ob folgende Aussagen wahr oder falsch sind.
- [[Wahr] [Falsch]]
- [(X) ( ) ] In jedem Programm darf es nur eine (1)
main
-Fuktion geben. - [( ) (X) ] Solange alle Funktionen
void
zurückgeben darf es auch mehreremain
-Funktionen geben. - [( ) (X) ]
argc
wird als erstes Argument in der Befehlszeile übergeben und kann alle ganzzahligen positiven Werte grösser 0 annehmen. - [( ) (X) ]
argc
ist ein Array von Befehlszeilenargumenten. - [(X) ( ) ]
argv
ist ein Array von Befehlszeilenargumenten. - [(X) ( ) ]
argv[0]
ist das Programm selbst.
Was ist
argv[argc]
? [(X)] NULL-Zeiger [( )] Das letzte Argument in der Befehlszeile
Wie lautet die Ausgabe dieses Programms wenn die kompilierte Version des Programms intern mit
./a.out 3 2 1 Maus im Haus
aufgerufen wird?
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
cout << argv[4];
return 0;
}
[[Maus]]