MINT lernen

Übungen: Funktionen

Warum bleibt eine Variable unverändert, obwohl die Funktion sie verdoppelt? Hier findest du es heraus.

Dein Fortschritt:
0 / 0 Aufgaben
1

Übungsaufgaben

Zehn Übungen zum Klicken, Zuordnen, Nachverfolgen und Knobeln — von AFB I bis AFB III. Jede Übung gibt dir sofort Rückmeldung; wenn du nicht weiterkommst, helfen dir die gestuften Tipps.

A1
Teile einer Funktion
AFB I

Die Mensa-Kasse berechnet Preise mit Rabatt.

C · Funktion rabatt
double rabatt(double preis, int prozent) {
    return preis * (100 - prozent) / 100;
}

Ordne jedem Teil den passenden Fachbegriff zu.

Ansatz: Lies den Funktionskopf von links nach rechts: Typ, Name, Klammer mit Parametern.
Weiter: Ein Aufruf enthält keine Typangaben — ein Prototyp schon.
A2
Stimmt's? — Funktionen
AFB I

Fünf Behauptungen über Funktionen und Header. Nenne jeweils, ob sie stimmt.

Fünf Aussagen nacheinander. Eine falsche Einschätzung reicht — dann startest du die Serie mit „Neue Runde“ neu.
Aussage 1 von 5

Die zweite Aussage ist die wichtigste: In C bekommt eine Funktion nur eine Kopie des Werts (call by value). Wer einen neuen Wert „nach draußen“ braucht, gibt ihn mit return zurück und weist ihn beim Aufruf zu.
Ansatz: Denke daran, was beim Aufruf mit dem Argument passiert: Wird die Variable selbst oder ihr Wert übergeben?
Weiter: return wirkt wie ein Notausgang aus der Funktion.
A3
Welche Zeile in welche Datei?
AFB I

Die Wetterstation wird auf drei Dateien verteilt: main.c, temperatur.h und temperatur.c. Ordne jede Zeile der Datei ein, in die sie gehört.

Ziehe jede Karte in den passenden Korb — oder wähle sie mit Enter aus und drücke dann die Ziffer des Korbs (0 legt sie zurück).
1main.c
2temperatur.h
3temperatur.c
Die Regel: Der Header enthält nur Ankündigungen (Prototypen mit ;) und den Include-Guard, die .c-Datei die Definitionen mit Rumpf. Typischer Fehler: Funktionsdefinitionen in den Header schreiben. Wird er dann von zwei .c-Dateien eingebunden, meldet der Linker die Funktion doppelt.
Ansatz: Unterscheide: Endet die Zeile mit ; oder hat sie einen Rumpf in { }?
Weiter: Alles mit #ifndef / #define gehört zum Include-Guard des Headers.
A4
Aufrufe verfolgen
AFB II
C · Ausschnitt
int stufe(int x) {
    x = x * 2;
    return x + 1;
}

int main(void) {
    int a = 5;
    int b = stufe(a);
    int c = stufe(b) - a;
    printf("%d %d %d\n", a, b, c);
    return 0;
}

Wende die Regeln für Funktionsaufrufe an und gib die Werte Schritt für Schritt an.

Arbeite die Kette Schritt für Schritt ab: Erst wenn ein Schritt stimmt, wird der nächste freigeschaltet. Enter prüft.
  1. Wert von b
  2. Wert von a nach dem ersten Aufruf
  3. Rückgabewert von stufe(b)
  4. Wert von c
Die Falle ist Schritt 2: In stufe wird x verdoppelt — aber x ist nur eine Kopie von a. a bleibt 5. Deshalb ist c = 23 − 5 = 18 und nicht 23 − 10.
Ansatz: Rechne stufe(5) Zeile für Zeile: x = 10, Rückgabe 11.
Weiter: Die Variable a in main und der Parameter x sind zwei verschiedene Speicherplätze.
A5
Sterne für Vielfache von 3
AFB II
Gewünschte Ausgabe
***
******

Ergänze das Programm so, dass genau diese Ausgabe entsteht.

Wähle in jedem Menü den passenden Eintrag und prüfe dann alle auf einmal.
C · sterne.c
 sterne(int n) {
    for (int i = 0; i < n; i++) {
        printf("*");
    }
    printf("\n");
}

 ist_teiler(int t, int z) {
     z % t == 0;
}

int main(void) {
    for (int z = 1; z <= 6; z++) {
        if (ist_teiler(, z)) {
            sterne();
        }
    }
    return 0;
}
sterne gibt nur aus und liefert nichts — also void. ist_teiler muss dagegen einen Wert (0 oder 1) für das if zurückgeben. Typischer Fehler bei Lücke 5: t wählen. t ist ein Parameter von ist_teiler und in main unbekannt — gcc bricht ab. Mit sterne(3) kämen zweimal drei Sterne.
Ansatz: Welche Funktion wird in einer Bedingung benutzt und braucht deshalb einen Rückgabewert?
Weiter: Die zweite Zeile hat sechs Sterne — so groß ist z im zweiten Treffer.
A6
Ein Projekt, drei Dateien
AFB II

Im Projekt „Geometrie“ steckt die Funktion kreisflaeche in eigenen Dateien. Stelle den Aufbau des Projekts vollständig dar, indem du die Lücken füllst — zwei Bausteine bleiben übrig.

Wort anklicken, dann Lücke anklicken (oder umgekehrt) — mit Tab und Enter geht es genauso. Ein Klick auf eine gefüllte Lücke legt das Wort zurück.

Die Datei enthält nur den Prototyp double kreisflaeche(double r);. Die Definition mit Rumpf steht in . main.c bindet den Header mit ein. Übersetzt wird das Projekt mit . Der Include-Guard besteht aus #ifndef GEOMETRIE_H, #define GEOMETRIE_H und am Schluss .

Beide Ablenker sind echte Fehlerquellen: Mit <geometrie.h> sucht der Präprozessor nur in den Systemordnern und meldet No such file. Und gcc main.c -o geo übersetzt geometrie.c gar nicht mit — der Linker meldet undefined reference to `kreisflaeche'. Der Header selbst steht nie im gcc-Befehl.
Ansatz: Header = Ankündigung (.h), Quelldatei = Umsetzung (.c).
Weiter: Dem gcc-Befehl gibst du alle .c-Dateien, die übersetzt werden sollen.
A7
Verschachtelte Aufrufe
AFB II
C · Funktionen
int plus_eins(int x) { return x + 1; }
int doppelt(int x) { return 2 * x; }

// in main:
printf("%d\n", doppelt(plus_eins(doppelt(3))) - plus_eins(4));

Berechne, welche Zahl ausgegeben wird.

Rechne selbst und trage das Ergebnis ein — Enter prüft direkt.
Von innen nach außen: doppelt(3) = 6, plus_eins(6) = 7, doppelt(7) = 14. Dann 14 − plus_eins(4) = 14 − 5 = 9. Typischer Fehler: von außen nach innen rechnen und doppelt zuerst auf 3 und dann erst plus_eins anwenden — oder die Klammern falsch zuordnen.
Ansatz: Werte immer den innersten Aufruf zuerst aus — sein Ergebnis ist das Argument des nächsten.
Weiter: doppelt(3) ist 6. Welcher Aufruf umschließt ihn direkt?
A8
Fehlersuche: Zeitrechner
AFB III

Das Projekt soll 2 min 30 s in Sekunden umrechnen und 150 ausgeben. Übersetzt wird mit gcc -Wall main.c zeit.c -o zeit. Von main.c siehst du nur die Zeilen um den Aufruf. Überprüfe die drei Dateien — drei Zeilen sind fehlerhaft.

In diesem Code stecken Fehler. Klicke genau die fehlerhaften Zeilen an — die richtigen musst du stehen lassen.
Der dritte Fehler ist der gemeinste: Zeile 11 ist gültiges C, gcc gibt nur mit -Wall die Warnung control reaches end of non-void function aus. Ohne -Wall übersetzt alles still, und das Programm gibt eine zufällige Zahl aus. Zeile 10 dagegen ist korrekt: Bei der Definition steht kein Semikolon hinter der Klammer.
Ansatz: Prüfe getrennt: die Art der #include-Klammern, den Unterschied Prototyp/Definition, und ob die Funktion ihr Ergebnis zurückgibt.
Weiter: Vergleiche Zeile 7 mit Zeile 10: Die eine ist ein Prototyp, die andere der Kopf einer Definition.
A9
Teiler zählen
AFB III Mix

Mit Schleife und Verzweigung aus 2.1.3 wird eine Funktion anzahl_teiler gebaut, die zählt, wie viele Teiler eine Zahl hat (für 12: 1, 2, 3, 4, 6, 12 → 6). Eine zweite Funktion nutzt sie: Eine Primzahl hat genau zwei Teiler.

Implementiere beide Funktionen, indem du die Zeilen ordnest.

Ziehe die Karten in die richtige Reihenfolge — mit der Tastatur: ↑/↓ verschiebt, Shift+↑/↓ wechselt nur den Fokus.
1int anzahl_teiler(int n) {
2 int anzahl = 0;
3 for (int t = 1; t <= n; t++) {
4 if (n % t == 0) { anzahl++; }
5 }
6 return anzahl;
7}
8int ist_primzahl(int n) { return anzahl_teiler(n) == 2; }
Am häufigsten verrutscht return anzahl; in die Schleife: Dann endet die Funktion schon beim ersten Durchlauf und liefert immer 1. Auch int anzahl = 0; muss vor der Schleife stehen, sonst wird der Zähler in jedem Durchlauf zurückgesetzt. ist_primzahl(1) liefert übrigens korrekt 0: 1 hat nur einen Teiler.
Ansatz: Eine Funktion besteht aus Kopf, Rumpf und schließender Klammer — erst danach kann die nächste beginnen.
Weiter: Der Rückgabewert steht erst fest, wenn alle möglichen Teiler geprüft sind.
A10
Wer gibt 10 aus?
AFB III Trick
C · Funktionen
void erhoehe(int x) { x = x + 5; }
int erhoehe2(int x) { x = x + 5; return x; }

Jede Zeile unten steht allein in main. Lege für jede Zeile fest, ob sie 10 ausgibt — markiere alle, bei denen das zutrifft.

Mehrere Antworten sind richtig. Markiere alle zutreffenden und klicke dann auf „Prüfen“.
Nur return bringt einen Wert aus der Funktion heraus — und nur, wenn der Aufrufer ihn auch verwendet. erhoehe(a) und ein nicht zugewiesenes erhoehe2(a) ändern a nicht: Ausgabe 5. Die Falle: Dass der Parameter genauso heißt wie die Variable in main (x), ändert nichts — es bleiben zwei verschiedene Variablen. Zeile 4 gibt trotzdem 10 aus, weil erst bei der Ausgabe 5 addiert wird; erhoehe2(erhoehe2(a)) - a ist 15 − 5.
Ansatz: Frage bei jeder Zeile: Wird ein Rückgabewert benutzt — zugewiesen oder direkt ausgegeben?
Weiter: Gleiche Namen in main und im Parameter bedeuten nicht dieselbe Variable.