You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Dominic Grimm e4d3248276
Update
18 hours ago
praktikum_1_2 Init 1 month ago
praktikum_3 Update paper 4 weeks ago
praktikum_4 Update paper 4 weeks ago
praktikum_5 Update paper to include praktikum 6 4 weeks ago
praktikum_6 Update paper to include praktikum 6 4 weeks ago
praktikum_7 Update 3 weeks ago
praktikum_8 Update 18 hours ago
praktikum_9 Update 18 hours ago
praktikum_10 Update 18 hours ago
.gitignore Init 1 month ago
README.md Update 3 weeks ago
header.tex Update paper 4 weeks ago
paper.sh Update paper 4 weeks ago
programmierung_praktikum.pdf Update 3 weeks ago

README.md

title author date lang papersize titlepage titlepage-color titlepage-text-color titlepage-rule-color
Programmierung Praktikum inoffizielle Musterlösungen (WS 22/23) [Dominic Grimm <dominic@dergrimm.net>] 2022-11-09 de a4 true 008a54 ffffff 00663E

Praktikum 3

Aufgabe 1 (Überprüfung Schaltjahr)

Für eine Jahreszahl soll berechnet werden, ob es sich um ein Schaltjahr handelt. Erstellen Sie hierzu einen Ausdruck. Zur Erinnerung: Ein Schaltjahr ist durch 4, aber nicht durch 100 teilbar; es gilt jedoch folgende Ausnahme: Jahreszahlen, die durch 400 teilbar sind, sind Schaltjahre. Testen Sie Ihr Programm mit geeigneten Jahreszahlen.

Lösung

#include <stdio.h>

int main(void) {
  printf("Gebe ein Jahr ein: ");
  int jahr;
  scanf("%i", &jahr);
  printf("%i ist ein Schaltjahr: %s\n", jahr,
         ((jahr % 4 == 0 && jahr % 100 != 0) || jahr % 400 == 0)
            ? "JA"
            : "NEIN");

  return 0;
}

Erklärung

In dieser Aufgabe wird ein Programm benötigt, welches Jahreszahlen einliest und dann ausgibt, ob es ein Schaltjahr ist.

Zeile Inhalt Erklärung
1 #include <stdio.h> Bindet die "Standard Input/Output"-Bibliothek ein. Eine Bibliothek ist nichs mehr, als ein Programm, das jemand anderes schon für einen geschrieben hat, um uns das Leben zu vereinfachen. Die stdio-Bibliothek ermöglicht es uns mit der Konsole zu interagieren. Das heißt wir können Text (char[]: Texte/Strings sind mehrere Textzeichen), Zahlen (int, float) oder Textzeichen (char) aus dem Textfenster einlesen oder ausgeben, in dem das Programm läuft. (In der JetBrains IDE CLion, die benutzt werden sollte, befindet sich dieses Fenster unten am Monitor.)
3 int main(void) { Hier wird der Einstiegspunkt in das Programm (das, was beim Starten als Erstes passiert) main festgelegt. Mit dem Zahlentyp int, welcher vor dem Namen der Methode steht, gibt man an, dass das Programm eine Zahl zurück gibt, nachdem es beendet wird. Diese Zahl wird nicht ausgedruckt oder gar angezeigt, sondern gibt sie dem Betriebssystem an, ob das gestartete Programm sich ohne aufgetretene Fehler selbst beendigt hat. Wenn dies der Fall ist, wird die Zahl 0 zurückgegeben (Zeile 12). Die geöffnete geschweifte Klammer ({) gibt an, dass Code folgt. Mit der Geschlossenen (}) ist der Code für die Methode beendet.
4 printf("Gebe ein Jahr ein: "); Hier wird mit der Funktion printf der Text Gebe ein Jahr ein: in die Konsole ausgegeben/gedruckt. printf wird mit dem Einbinden von stdio verfügbar gemacht. Mit dem Semikolon (;) wird die Anweisung beendet.
5 int jahr; Die Variable jahr mit dem Zahlentyp int wird erstellt. Zahlen des Typ int können negativ, als auch positiv sein.
6 scanf("%i", &jahr); Mit der Funktion scanf, welche auch in stdio mitgeliefert wird, kann aus der Konsole eingelesen werden. Das erste Argument ("%i"), sagt der Funktion, dass das Eingelesene vom Typ int sein soll (mehr dazu in der Präsentation der Vorlesungen auf Folie 94ff). Das zweite Argument (&jahr) gibt der Funktion eine Referenz (-> Zeiger/Pointer) zu der Variable jahr, in der die eingelesene Zahl gespeichert werden soll. Wenn das Argument jahr wäre, würde nicht in die Variable eingespeichert werden, sondern an einem zufällig anderem Ort im Speicher des Programms. Durch die Erstellung eines Pointers mit dem Kaufmannsund (&) vor dem Namen der Variable, übergibt man einen Wert, der sagt, dass die Variable, in die Gespeichert werden soll, an einem anderen Ort liegt.
7 printf("%i ist ein Schaltjahr: %s\n", jahr, Text wird zur Konsole ausgegeben mit den folgenden Werten, welche durch die %-Schalter eingefügt werden: Wert von Variable jahr und, ob das Jahr ein Schaltjahr ist. Weitere Argumente folgen in den darauf liegenden Zeilen.
8 `((jahr % 4 == 0 && jahr % 100 != 0) jahr % 400 == 0)` Wahrheitsausdruck (Boolescher Ausdruck, kann entweder false oder true sein), der bestimmt, ob das Jahr ein Schaltjahr ist. jahr % 4 == 0 schaut, ob das Jahr durch 4 teilbar ist und somit der Rest der Division 0 entspricht. jahr % 100 != 0 schaut, ob das Jahr nicht durch 100 teilbar ist, da der Rest nicht 0 sein darf (!=). Mit der logischen UND-Verknüpfung (&&) werden diese zwei Ausdrücke aneinander gekoppelt; wenn beide Werte true sind, also wahr sind, ist der resultierende Werte auch true, wenn nicht, dann false. (Mehr dazu unter Boolescher Algebra.) Wenn aber das Jahr durch 400 teilbar ist, ist es auch auch Schaltjahr. Dies wird mit der logischen ODER-Verknüpfung (` ) erreicht; wenn eine der beiden Werte trueist, dann ist der resultierende Wert auchtrue, wenn nicht, dann false`.
9, 10 ? "JA" : "NEIN"); Gibt den Text JA an die printf-Funktion über, wenn der Schaltjahrausdruck true entspricht, wenn nicht, dann den Text NEIN.
12 return 0; Wie oben beschrieben, hat das Programm bis jetzt noch nicht beendet, weshalb wir es mit der Zahl für Erfolg 0 beenden.
13 } Code für Einstiegspunkt ist hiermit beendet.

Aufgabe 2 (Zuweisungen)

Schreiben Sie ein Programm, das für eine Zahl zwischen 0 und 255 die Binärdarstellung ausgibt. Verwenden Sie keine for- oder while-Schleife.

Lösung

#include <stdio.h>

int main(void) {
  printf("Enter number: ");
  unsigned char num;
  scanf("%hhu", &num);

  printf("%u", num >> 7);
  printf("%u", (num >> 6) & 1);
  printf("%u", (num >> 5) & 1);
  printf("%u", (num >> 4) & 1);
  printf("%u", (num >> 3) & 1);
  printf("%u", (num >> 2) & 1);
  printf("%u", (num >> 1) & 1);
  printf("%u", num & 1);
  printf("\n");

  return 0;
}

Erklärung

In diesem Programm soll eine Zahl eingelesen werden und diese in Binärdarstellung ausgegeben werden. Da die Zahl im gegebenen Intervall

$$ \text{n} \in \mathopen]0, 255\mathclose[ $$

enthalten ist, kann geschlussfolgert werden, dass maximal 8 Bits für die Repräsentation der Zahl benötigt wird. Deswegen wird der Zahlentyp unsigned char benutzt. char ist zwar der Typ eines Textzeichens, jedoch hat dieser genau 8 Bits Größe; unsigned lässt den Wert nicht negativ sein.

Die sich wiederholenden Teile des Programms sind aus den vorherigen Erklärung herauszulesen.

Zeile Inhalt Erklärung
5 unsigned char num; Erstellt Variable num mit dem möglichen Wertebereich von 0 bis 255. Dies ist der Wertebereich, den eine Zahl mit der Größe von 8 Bits, also einem Byte, auch besitzt.
6 scanf("%hhu", &num); Liest eine Zahl ein und sie in der Variable num ab.
8 - 15 Geben Bit für Bit die Binärdarstellung der Zahl aus. Durch Bitverschiebungen (<</>>) wird eine Zahl jeweils binär n-Mal entweder nach links oder nach rechts verschoben. So wird 0b00000001 << 3 zu 0b00001000 und 0b10110000 >> 7 zu 0b0000001. Mit dem UND-Operator (&) kann ein bestimmtes Muster auf eine Zahl gelegt werden, und binär schauen, an welchen Positionen sich eine Zahl und das Muster überlappen. (0b00101011 >> 4) & 1 wird somit zu 0b000000101 & 1. Das Muster 1 kann auch binär dargestellt werden: 0b00000001. Die zwei Zahlen überlappen sich an einer Stelle, dem ersten Bit. Deswegen ist der daraus folgende Wert 0b00000001 oder 1.
Angewendet für die binäre Ausgaben kann man nun Bit für Bit die Zahl nach rechts verschieben und dann den ersten (also den ganz rechts) an die Konsole ausgeben.
8 printf("%u", num >> 7); Die Zahl wird um 7 Bits nach rechts verschoben. Es wird keine UND-Operation benötigt, um den ersten Bit zu markieren, da nur dieser durch die Verschiebung nicht Null sein könnte.
9 - 14 printf("%u", (num >> 6) & 1); Dekrementierende Verschiebung und Markierung vom ersten Bit.
15 printf("%u", num & 1); Erster Bit kann direkt markiert werden, deswegen ist eine Verschiebung um 0 Bit nach rechts nicht nötig.
16 printf("\n"); Druckt einen Zeilenumbruch aus, da dieser noch nicht bei der Bitausgabe gegeben war.

Aufgabe 3 (Prüfziffernberechnung)

Auf Verpackungen von Waren befinden sich häufig Strichcodes mit Code-Nummern. In der Breite wird das sogenannte EAN-13-System (Europäische Artikel-Nummerierung mit 13 Ziffern) eingesetzt. Bei Büchern wird seit vielen Jahren ein ähnlicher Code verwendet: Internationale Standard-Buchnummer, kurz ISBN.

Beide Codes beinhalten eine Prüfziffer, d.h. eine Ziffer wird gemäß einer definierten Formel aus den restlichen Ziffern abgeleitet. Die EAN-Prüfziffer (13. Ziffer) wird wie folgt berechnet: Man multipliziert die ersten zwölf Ziffern abwechselnd mit 1 und 3 und bildet die Summe der Produkte. Die Prüfziffer ist die Differenz der Summe zum nächsten Vielfachen von 10. Ist die Summe durch 10 teilbar, ist die Prüfziffer die 0.

Die ISBN-Prüfziffer (10. Ziffer) wird wie folgt berechnet: Man multipliziert die erste Ziffer mit eins, die zweite mit zwei, die dritte mit drei und so fort bis zur neunten Ziffer, die mit neun multipliziert wird. Es werden nun die Produkte addiert und die Summe ganzzahlig durch 11 dividiert. Der Divisionsrest ist die Prüfziffer. Ist der Rest 10 , wird das Zeichen “X” genommen.

Implementieren Sie das EAN-13-Verfahren und ISBN-Verfahren. Testen Sie Ihre Lösung an Hand von “greifbaren” Artikeln mit Code-Nummern. Verwenden Sie keine for- oder while-Schleife.

EAN Lösung

#include <stdio.h>
#include <string.h>

int main(void) {
  char ean[14];
  printf("EAN: ");
  scanf("%13s", ean);
  const unsigned long int len = strlen(ean);
  if (len != 13) {
    fprintf(stderr, "Angegebene EAN hat eine invalide Länge: %lu != 13\n", len);
    return 1;
  }

  unsigned int uneven_sum = 0, even_sum = 0;
  even_sum += ean[0] - '0';
  uneven_sum += ean[1] - '0';
  even_sum += ean[2] - '0';
  uneven_sum += ean[3] - '0';
  even_sum += ean[4] - '0';
  uneven_sum += ean[5] - '0';
  even_sum += ean[6] - '0';
  uneven_sum += ean[7] - '0';
  even_sum += ean[8] - '0';
  uneven_sum += ean[9] - '0';
  even_sum += ean[10] - '0';
  uneven_sum += ean[11] - '0';

  const unsigned char rem = (even_sum * 3 + uneven_sum) % 10;
  const unsigned char res = rem == 0 ? 0 : 10 - rem;

  printf("Prüfziffer ist: %u\n", res);

  return 0;
}

EAN Erklärung

Das Programm soll eine EAN mit 13 Ziffern einlesen und damit die Prüfziffer berechnen.

Ein häufiger Fehler liegt darin, dass die 13 Ziffern einzeln eingelesen wurden und dies zu unleserlichem und unbenutzbaren Code geführt hat. Auch müsste bei dieser Option auch bei jede der 13 Variablen als Pointer übergeben werden.

Hier wird die EAN als Text mit 14 Zeichen eingelesen. Das 14. Zeichen ist für den Null-Byte-Terminator \0 reserviert. Die zwölf Zeichen werden dann durch eine sich auf die ASCII-Tabelle beziehende Subtraktion in Zahlen umgewandelt.

Hier ein interessanter Ausschnitt der ASCII-Tabelle:

Hexadezimal Textzeichen
... ...
0x30 '0'
0x31 '1'
0x32 '2'
0x33 '3'
0x34 '4'
... ...

Wie hier zu erkennen ist, sind die Zahlen von 0-9 in ASCII so dargestellt, dass diese mit einem Versatz von hexadezimal 0x30 beginnen.

Das heißt ein Textzeichen '7' kann zu einer puren Zahl umgewandelt werden, indem von dem Textzeichen der Wert 0x30, oder besser: der Versatz direkt als Textzeichen '0' repräsentiert, subtrahiert wird.

Beispiel:

const char textzeichen = '4';
const unsigned char zahl = textzeichen - '0'; // auch möglich: textzeichen - 0x30
printf("%u", zahl); // => 4
Zeile Inhalt Erklärung
2 #include <string.h> Die string-Bibliothek wird eingebunden/importiert. Sie besitzt die strlen-Funktion, welche genutzt werden kann, um die Länge eines Textes/Strings zu ermitteln.
5 char ean[14]; String ean mit 14 Zeichen wird erstellt.
7 scanf("%13s", ean); Text wird aus Konsole eingelesen und in dem String ean eingespeichert. Die Zahl 13 vor dem s-Schalter in scanf ermöglicht, dass die maximale Länge der Eingabe 13 Zeichen lang sein darf. Dies schützt vor undefiniertem Verhalten, wenn die Länge höher 14 ist. Für den String ean muss keine Referenz erstellt werden, wenn in diese geschrieben werden soll mit scanf. Das ist der Fall, weil Strings selbst pointerähnliches Verhalten besitzen und auf Speicherorte verweisen.
8 const unsigned long int len = strlen(ean); Die Länge des Inputs wird ausgerechnet und in einer konstanten Variable len gespeichert.
9 - 12 if (len != 13) { ... Beendet das Programm mit dem Exitcode für Fehlverhalten 1, wenn die Länge der Eingabe nicht 13 ist. fprintf(stderr, ...) ist genau das Gleiche, wie printf, nur, dass das erste Argument (hier stderr) eine Datei oder einen Stream annimmt und in diesen ausgibt. Dies ist aber noch nicht relevant, sollte aber bei Fehlermeldungen vor Programmabbruch mit stderr benutzt werden. stderr ist eine spezielle Ausgabemöglichkeit für Fehlermeldungen.
14 unsigned int uneven_sum = 0, even_sum = 0; Die Variablen uneven_sum und even_sum werden erstellt. Statt für jede zweite eingelesene Ziffer zu multiplizieren, wird am Ende die gerade Summe even_sum mit 3 multipliziert.
15 even_sum += ean[0] - '0'; Von dem erstem Textzeichen aus dem String ean wird der Versatz/Offset abgezogen und das Textzeichen somit zu einer puren Zahl umgewandelt.
16 uneven_sum += ean[1] - '0'; Hier das Gleiche, nur für die gerade Summe even_sum.
17 - 26 Die zwei oberen Zeilen werden wiederholt und der Index jeweils um eins erhöht, bis zum Index 11, also das zwölfte Zeichen.
28 const unsigned char rem = (even_sum * 3 + uneven_sum) % 10; Die gerade Summe wird verdreifacht und mit der Ungeraden addiert. Der Rest der Division mit 10 wird ausgerechnet und in eine Variable rem gespeichert.
29 const unsigned char res = rem == 0 ? 0 : 10 - rem; Wenn die Summe durch 10 teilbar ist, also rem == 0, so ist die Prüfziffer 0, wenn nicht dann ist die Prüfziffer die Differenz zum nächst höheren Vielfachen von 10. Die Prüfziffer wird in die Variable res gespeichert.

ISBN Lösung

#include <stdio.h>
#include <string.h>

int main(void) {
  printf("ISBN: ");
  char isbn[11];
  scanf("%10s", isbn);
  const unsigned long len = strlen(isbn);
  if (len != 10) {
    fprintf(stderr, "Angegebene ISBN hat eine invalide Länge: %lu != 10", len);
    return 1;
  }

  unsigned int sum = 0;
  sum += (isbn[0] - '0') * 1;
  sum += (isbn[1] - '0') * 2;
  sum += (isbn[2] - '0') * 3;
  sum += (isbn[3] - '0') * 4;
  sum += (isbn[4] - '0') * 5;
  sum += (isbn[5] - '0') * 6;
  sum += (isbn[6] - '0') * 7;
  sum += (isbn[7] - '0') * 8;
  sum += (isbn[8] - '0') * 9;

  const unsigned char rem = sum % 11;
  const char res = rem == 10 ? 'X' : '0' + rem;
  printf("Die Prüfziffer ist: %c\n", res);

  return 0;
}

ISBN Erklärung

Die allgemeine Programmstruktur ist effektiv die Gleiche wie bei der EAN. Hier jedoch wird die ISBN10 verwendet.

Zur Berechnung der ISBN Prüfziffer werden die ersten 9 Zeichen auch wieder in Zahlen umgewandelt und dann mit der Zahl 1-9 multipliziert, entsprechend dem aktuellen Index. Der Divisionsrest dieser Zahl mit 11 ist nun die Prüfziffer. Wenn aber der Rest 10 entspricht, dann ist die Prüfziffer das Textzeichen 'X'.

Zeile Inhalt Erklärung
14 unsigned int sum = 0; Variable sum für die Summe wird erstellt.
15 sum += (isbn[0] - '0') * 1; Eingelesene Ziffer wird mit Position multipliziert und der Summe hinzuaddiert.
16 - 23 Für die Positionen bis 9 wird das Obere wiederholt.
25 const unsigned char rem = sum % 11; Divisionsrest mit 11 wird in Variable rem gespeichert.
26 const char res = rem == 10 ? 'X' : '0' + rem; Wenn Rest 10 ist, dann ist die Prüfziffer 'X', wenn nicht dann wird der Wert der Variable rem durch die umgedrehte vorhin beschriebene ASCII-Operation zu einem Textzeichen umgewandelt.

Aufgabe 4 (if-Anweisung)

Schreiben Sie ein Programm, das eine Zahl einliest und folgende Funktion f mit Hilfe von if-Anweisungen implementiert:

$$ \mathrm{f}(x) = \begin{cases} -1 & \text{falls } x < 0 \ 0 & \text{falls } x = 0 \ 1 & \text{falls } x > 0 \end{cases} $$

Lösung

#include <stdio.h>

int main(void) {
  printf("Zahl: ");
  int x;
  scanf("%i", &x);

  char res;
  if (x < 0) {
    res = -1;
  } else if (x == 0) {
    res = 0;
  } else {
    res = 1;
  }
  printf("Resultat ist: %i\n", res);

  return 0;
}

Erklärung

Zeile Inhalt Erklärung
5 int x; Erstellt Variable x mit Typ int.
6 scanf("%i", &x); Liest eine Zahl ein und speichert diese in x ab.
8 char res; Erstellt Variable res mit Zahlentyp char. Zwar ist char nicht per se ein Zahlentyp, jedoch kann dieser in solch Situationen so benutzt werden, wenn die darzustellende Zahl die maximale Größe von einem Byte hat.
9, 10 if (x < 0) { ... Wenn x kleiner 0, dann ist das Resultat -1.
11, 12 } else if (x == 0) { ... Wenn x gleich 0, dann ist das Resultat 0.
13 - 15 } else { ... Wenn keines davon eintritt, muss x also größer 0 sein, deswegen ist das Resultat dann 1.

Aufgabe 5 (Quadratische Gleichung)

Die Lösungen einer quadratischen Gleichung

$$ x^2 + px + q = 0 $$

können mit folgender Formel berechnet werden:

$$ x_{1,2} = -\frac{p}{2} \pm \sqrt{(\frac{p}{2})^2 - q} $$

Schreiben Sie ein Programm, das zu gegebenen Werten p und q die beiden Lösungen $x_{1}$ und $x_{2}$ ausgibt. Falls keine (reelle) Lösung existiert, soll eine entsprechende Meldung ausgegeben werden.

Überprüfen Sie auch, ob Ihre berechneten Werte $x_{1}$ und $x_{2}$ tatsächlich Nullstellen der quadratischen Gleichung sind.

Lösung

#include <float.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>

#define PRECISION 0.000001

bool double_compare(double x, double y) {
  return (x - PRECISION) < y && (x + PRECISION) > y;
}

int main(void) {
  printf("p: ");
  double p;
  scanf("%lf", &p);
  printf("q: ");
  double q;
  scanf("%lf", &q);

  const double x1 = -(p / 2) + sqrt(pow(p / 2, 2) - q);
  const double x2 = -(p / 2) - sqrt(pow(p / 2, 2) - q);
  if (x1 != x1 || x2 != x2 || x1 < -FLT_MAX || x1 > FLT_MAX || x2 < -FLT_MAX ||
      x2 > FLT_MAX || !double_compare(pow(x1, 2) + p * x1 + q, 0) ||
      !double_compare(pow(x2, 2) + p * x2 + q, 0)) {
    fprintf(stderr, "Keine Lösung gefunden!\n");
    return 1;
  }

  printf("x1: %f\nx2: %f\n", x1, x2);

  return 0;
}

Erklärung

Zeile Inhalt Erklärung
1 #include <float.h> Bindet die float-Bibliothek ein. Wird benötigt für Konstanten, wie FLT_MAX.
2 #include <math.h> Bindet die math-Bibliothek ein. Stellt mathematische Funktionen bereit, wie sqrt und pow.
3 #include <stdbool.h> Bindet die stdbool-Bibliothek ein. Stellt den Typ bool bereit. In C++ ist bool ohne das Einbinden dieser Bibliothek verfügbar.
6 #define PRECISION 0.000001 Erstellt mit Hilfe des Präprozessors eine Konstante PRECISISION. Sie wird in double_compare benutzt, um die Präzision für Rundungsungenauigkeiten zu setzen.
8 bool double_compare(double x, double y) { ... Stellt eine Funktion double_compare bereit, mit welcher zwei Variablen mit double-Typ verglichen werden können.
20, 21 Rechnet die Werte x1 und x2 entsprechend der Formel aus.
22 - 27 Testet, ob die errechneten Zahlen valide Fließkommazahlen sind und, ob diese die tatsächlichen Nullstellen sind, durch Einsetzen, wenn nicht bricht das Programm mit einer Fehlermeldung ab.

Aufgabe 6 (Tage pro Monat)

Schreiben Sie ein Programm, das eine Jahreszahl und einen Monat (1 für Januar, 2 für Februar, etc.) einliest und die Anzahl der Tage des Monats ausgibt. Denken Sie an Schaltjahre. Verwenden Sie eine switch-Anweisungen.

Lösung

#include <stdio.h>

int main(void) {
  printf("Monat: ");
  unsigned char monat;
  scanf("%hhu", &monat);
  if (monat > 12) {
    fprintf(stderr, "Ungültiger Monat: %u\n", monat);
    return 1;
  }
  printf("Jahr: ");
  int jahr;
  scanf("%i", &jahr);

  unsigned char tage;
  switch (monat) {
  case 1:
    tage = 31;
    break;
  case 2:
    tage = ((jahr % 4 == 0 && jahr % 100 != 0) || jahr % 400 == 0) ? 29 : 28;
    break;
  case 3:
    tage = 31;
    break;
  case 4:
    tage = 30;
    break;
  case 5:
    tage = 31;
    break;
  case 6:
    tage = 30;
    break;
  case 7:
  case 8:
    tage = 31;
    break;
  case 9:
    tage = 30;
    break;
  case 10:
    tage = 31;
    break;
  case 11:
    tage = 30;
    break;
  case 12:
    tage = 31;
    break;
  }
  printf("Tage: %u\n", tage);

  return 0;
}

Praktikum 4

Aufgabe 1 (Fibonacci-Zahlen)

Berechnen Sie die ersten 20 Fibonacci-Zahlen, wobei die Fibonacci-Funktion wie folgt definiert ist:

$$ \begin{aligned} & \mathrm{fib}(n) \coloneqq 1 && \quad \text{mit } n \in \left{ 0, 1 \right} \ & \mathrm{fib}(n) \coloneqq \mathrm{fib}(n - 1) + \mathrm{fib}(n - 2) && \quad \text{mit } n > 1. \end{aligned} $$

Berechnen Sie darüber hinaus den Quotienten von $\frac{\mathrm{fib}(n)}{\mathrm{fib}(n - 1)}$ für $1 \leq n < 20$.

Fib(0) = 1
Fib(1) = 1				1.000000000000000
Fib(2) = 2				2.000000000000000
Fib(3) = 3				1.500000000000000
Fib(4) = 5				1.666666666666667
Fib(5) = 8				   1.600000000000000
Fib(6) = 13				1.625000000000000
Fib(7) = 21				1.615384615384615
Fib(8) = 34				1.619047619047619
Fib(9) = 55				1.617647058823529
Fib(10) = 89				1.618181818181818
Fib(11) = 144				1.617977528089888
Fib(12) = 233				1.618055555555556
Fib(13) = 377				1.618025751072961
Fib(14) = 610				1.618037135278515
Fib(15) = 987				1.618032786885246
Fib(16) = 1597			1.618034447821682
Fib(17) = 2584			1.618033813400125
Fib(18) = 4181			1.618034055727554
Fib(19) = 6765			1.618033963166706
Fib(20) = 10946			1.618033998521803

Lösung

#include <stdio.h>

int main(void) {
  unsigned int vorletztes_ergenis = 1;
  unsigned int letztes_ergebnis = 1;
  printf("fib(0) = 1\n");
  printf("fib(1) = 1\t\t%f\n", (float)letztes_ergebnis / vorletztes_ergenis);
  for (unsigned char i = 2; i <= 20; i++) {
    const unsigned int ergebnis = letztes_ergebnis + vorletztes_ergenis;
    vorletztes_ergenis = letztes_ergebnis;
    letztes_ergebnis = ergebnis;

    printf("fib(%u) = %u\t\t%f\n", i, ergebnis,
           (float)letztes_ergebnis / vorletztes_ergenis);
  }

  return 0;
}

Aufgabe 2 (Wiederholungsanweisungen)

Betrachten Sie das folgende Iterationsverfahren zur Berechnung der Quadratwurzel einer Zahl $A$:

$$ x_{i + 1} = \frac{1}{2} * (x_{i} + \frac{A}{x_{i}}) $$

mit $x_{0} = 1$. Für $A = 2$ berechnen sich die Werte $x_{1}$ und $x_{2}$ folgendermaßen:

$$ \begin{aligned} & x_{1} = \frac{1}{2} * (1 + \frac{2}{1}) = 1.5 \ & x_{2} = \frac{1}{2} * (1.5 + \frac{2}{1.5}) = 1.41\overline{6} \end{aligned} $$

  1. Schreiben Sie ein Programm, das eine Zahl $A$ einliest und mit Hilfe einer for-Schleife die Werte $x_{1}$, $x_{2}$, ..., $x_{10}$ berechnet und ausgibt.
  2. Ersetzen Sie die for-Schleife aus Lösung 1 durch eine do-while-Schleife. Es sollen solange die Werte für $x_{1}$, $x_{2}$, ... berechnet werden, bis der Abstand zweier nachfolgender Werte kleiner $0.000001$ ist.

1. Lösung

#include <stdio.h>

int main(void) {
  printf("a: ");
  int a;
  scanf("%i", &a);
  long double res = 1;
  for (unsigned char i = 1; i <= 10; i++) {
    res = 0.5 * (res + (a / res));
    printf("x%u = %Lf\n", i, res);
  }

  return 0;
}

2. Lösung

#include <math.h>
#include <stdio.h>

int main(void) {
  printf("a: ");
  int a;
  scanf("%i", &a);
  long double prev = 1;
  long double res = prev;
  unsigned int i = 1;
  do {
    prev = res;
    res = 0.5 * (prev + (a / prev));
    printf("x%u = %Lf\n", i, res);
    i++;
  } while (0.000001 < fabsl(res - prev));

  return 0;
}

Aufgabe 3 (for-Schleife)

Geben Sie für die folgenden for-Schleifen an, wie oft diese durchlaufen werden und welche Werte die Zählvariable dabei annimmt.

  1. for (int zaehler = 0; zaehler != 10; zaehler = zaehler + 1)
  2. for (int n = 10; n > 0; n = n - 1)
  3. for (int x = 1; x <= 15; x = x + 3)
  4. for (int x = 1; x != 15; x = x + 3)
  5. for (int x = 1; x == 15; x = x + 3)
  6. for (char c = '5'; c <= '9'; c = c + 2)

Lösung

# Anzahl Werte Erklärung
1 $10$ $\left{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \right}$ Zähler wird so lange inkrementiert, bis er $10$ entspricht.
2 $10$ $\left{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 \right}$ Zähler wird so lange dekrementiert, bis er nicht über $0$ ist.
3 $5$ $\left{ 1, 4, 7, 10, 13 \right}$ Zähler wird jedes Mal um $3$ inkrementiert, bis er über $15$ ist.
4 $\left{ \infty, 1431655770 \right}$ $\text{f}(n) = 1 + 3n$ Zähler wird nach jedem Durchlauf um $3$ erhöht, wird aber nicht innerhalb von normaler Laufzeit $15$ erreichen, deshalb $\infty$ in der Wertemenge. Jedoch wird der Zähler irgendwann $15$ sein.
5 $0$ $\left{\right}$ x ist schon beim ersten Durchlauf nicht $15$, sondern $1$.
6 $3$ $\left{ \mathrm{0x35}, \mathrm{0x37}, \mathrm{0x39} \right}$ Das Textzeichen wird durch eine ASCII-basierte Operation immer um $2$ erhöht, bis es '9' ist.
['7', '7', '9']

Aufgabe 4 (Geschachtelte for-Anweisungen)

Das folgende Programmfragment gibt eine Anzahl von "*"-Zeichen in Form eines Dreiecks aus. Ändern Sie das Programm so, dass dieses Dreieck auf dem Kopf steht.

int zeile, spalte;
for (zeile = 1; zeile <= 20; zeile=zeile+1){
  for (spalte = 1; spalte <= zeile; spalte = spalte+1){
    printf("*");
  }
	printf("\n");
}

Lösung

#include <stdio.h>

int main(void) {
  for (unsigned char zeile = 20; zeile > 0; zeile--) {
    for (unsigned char spalte = 0; spalte < zeile; spalte++) {
      printf("*");
    }
    printf("\n");
  }

  return 0;
}

Aufgabe 5 (Geschachtelte for-Anweisungen)

Schreiben Sie ein Programm, das die folgende Ausgabe erzeugt. Verwenden Sie geschachtelte for-Schleifen.

10 12 14 16 18
20 22 24 26 28
30 32 34 36 38
40 42 44 46 48
50 52 54 56 58
60 62 64 66 68
70 72 74 76 78
80 82 84 86 88
90 92 94 96 98

Lösung

#include <stdio.h>

int main(void) {
  for (unsigned char i = 1; i < 10; i++) {
    for (unsigned char j = 0; j < 5; j++) {
      printf("%u ", i * 10 + j * 2);
    }
    printf("\n");
  }

  return 0;
}

Aufgabe 6 (Binärdarstellung einer Zahl)

Lesen Sie eine ganze Zahl ein. Berechnen Sie die Binärdarstellung der Zahl und geben diese (in umgekehrter Reihenfolge) aus.

Lösung

#include <stdio.h>

int main(void) {
  printf("Enter number: ");
  int x;
  if (scanf("%i", &x) != 1) {
    fprintf(stderr, "Input not valid!\n");
    return 1;
  }
  for (unsigned char i = 0; i < sizeof(x) * 8; i++) {
    printf("%u", x & 1);
    x >>= 1;
  }
  printf("\n");

  return 0;
}

Praktikum 5

Aufgabe 1 (Array)

Legen Sie ein Integer-Array der Länge 20 an und füllen Sie dieses mit Zufallszahlen (vgl. rand()-Funktion von Blatt 1; um nicht immer die "gleichen Zufallszahlen" zu bekommen, können Sie mit der Anweisung srand(time(0)) den Zufallszahlengenerator initialisieren - inkludieren Sie time.h). Iterieren Sie über das Array und addieren Sie jeweils die geraden und ungeraden Zahlen auf.

Lösung

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
  srand(time(NULL));

  int uneven = 0, even = 0;
  for (unsigned char i = 0; i < 20; i++) {
    int x = rand();
    if (x % 2 == 0) {
      even += x;
    } else {
      uneven += x;
    }
  }
  printf("Uneven: %i\nEven: %i\n", uneven, even);

  return 0;
}

Aufgabe 2 (Array)

Schreiben Sie ein Programm, das zunächst in einem Feld 100 Zufallszahlen aus dem Werte-bereich von 0 bis 50 einträgt. Danach soll eine Zahl eingelesen und geprüft werden, wie oft diese Zahl in dem Feld vorkommt.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
  srand(time(NULL));

  const int divisor = RAND_MAX / 51;
  unsigned char arr[51] = {};
  for (unsigned char i = 0; i < 100; i++) {
    unsigned char val;
    do {
      val = rand() / divisor;
    } while (val > 50);
    arr[val]++;
  }

  printf("Enter number: ");
  unsigned char x;
  if (scanf("%hhu", &x) != 1) {
    fprintf(stderr, "Expected one number as input!\n");
    return 1;
  } else if (x > 50) {
    fprintf(stderr, "Entered number above limit: %u > 50\n", x);
    return 1;
  }
  printf("Count: %u\n", arr[x]);

  return 0;
}

Aufgabe 3 (Binärdarstellung einer Zahl)

Lesen Sie eine ganze Zahl ein. Berechnen Sie die Binärdarstellung der Zahl und speichern Sie die in der "richtigen" Reihenfolge in einem Array. Ein Element in diesem Array hat entweder den Wert $0$ oder $1$.

Lösung

#include <stdio.h>
#include <stdbool.h>

int main(void) {
  printf("Enter number: ");
  int x;
  if (scanf("%i", &x) != 1) {
    fprintf(stderr, "Expected one number as input!\n");
  }
  bool arr[sizeof(x) * 8];
  for (unsigned char i = sizeof(arr) - 1; i < 0xff; i--) {
    arr[i] = x & 1;
    x >>= 1;
  }
  for (unsigned char i = 0; i < sizeof(arr); i++) {
    printf("%u", arr[i]);
  }
  printf("\n");

  return 0;
}

Aufgabe 4 (Zeichenketten)

Schreiben Sie ein Programm, das die Länge einer gegebenen Zeichenkette ermittelt - einmal mit der Bibliotheksfunktion strlen() und einmal durch selbst geschriebenen Code.

#include <stdio.h>
#include <string.h>

int main(void) {
  char str[0xff];
  printf("Enter string: ");
  fgets(str, sizeof(str), stdin);
  str[strlen(str) - 1] = '\0';

  printf("Length (strlen): %lu\n", strlen(str));

  unsigned char len;
  for (len = 0; len < sizeof(str) && str[len] != '\0'; len++) {
  }
  printf("Length (own implementation): %u\n", len);

  return 0;
}

Aufgabe 5 (Zeichenketten)

Schreiben Sie ein Programm, das zwei Zeichenketten miteinander vergleicht. Es soll $0$ zurück- geliefert werden, wenn beide Zeichenketten gleich sind, ansonsten $1$.

Lösung

#include <stdio.h>
#include <string.h>

int main(void) {
  char input1[0xff];
  printf("Enter first string: ");
  fgets(input1, 0xff, stdin);
  char input2[0xff];
  printf("Enter second string: ");
  fgets(input2, 0xff, stdin);

  return !strcmp(input1, input2);
}

Aufgabe 6 (Zeichenketten)

Schreiben Sie ein Programm, das eine Zeichenkette spiegelt. Beispielsweise soll für die Eingabe "Guten Tag." die Ausgabe ".gaT netuG" berechnet werden.

#include <stdio.h>
#include <string.h>

int main(void) {
  printf("Enter string: ");
  char str[0xff];
  fgets(str, sizeof(str), stdin);
  for (unsigned char i = strlen(str) - 1; i < 0xff; i--) {
    printf("%c", str[i]);
  }

  return 0;
}

Aufgabe 7 (Zeichenketten)

Schreiben Sie ein Programm, das aus einer gegebenen Zeichenkette alle Vokale entfernt. Beispiel: Für "Informatik" ergibt sich die Zeichenfolge "nfrmtk".

Lösung

#include <stdio.h>

int main(void) {
  printf("Enter string: ");
  char str[0xff];
  fgets(str, sizeof(str), stdin);
  char new_str[sizeof(str)];
  unsigned char i = 0;
  for (unsigned char j = 0; j < sizeof(str); j++) {
    if (str[j] == '\0') {
      break;
    }
    char c = str[j];
    if (c != 'a' && c != 'A' && c != 'e' && c != 'E' && c != 'i' && c != 'I' &&
        c != 'o' && c != 'O' && c != 'u' && c != 'U') {
      new_str[i] = str[j];
      i++;
    }
  }
  printf("%s", new_str);

  return 0;
}

Aufgabe 8 (Zeichenketten)

Schreiben Sie ein Programm, das zwei Zeichenketten einliest und die zweite Zeichenkette an die erste anhängt.

Erstellen Sie 2 Lösungen: eine unter Nutzung der Bibliotheksfunktion strcat() sowie eine ohne Verwendung dieser Funktion.

#include <stdio.h>
#include <string.h>

int main(void) {
  printf("Enter first string: ");
  char str1[0xff];
  fgets(str1, sizeof(str1), stdin);
  str1[strlen(str1) - 1] = '\0';
  printf("Enter second string: ");
  char str2[sizeof(str1)];
  fgets(str2, sizeof(str2), stdin);
  str2[strlen(str2) - 1] = '\0';

  char str_concat1[sizeof(str1) + sizeof(str2)];
  strcpy(str_concat1, str1);
  strcat(str_concat1, str2);
  printf("Concat (strcat): %s\n", str_concat1);

  char str_concat2[sizeof(str_concat1)];
  strcpy(str_concat2, str1);
  unsigned char offset = strlen(str_concat2);
  for (unsigned char i = 0; i < strlen(str2) && str2[i] != '\0'; i++) {
    str_concat2[offset + i] = str2[i];
  }
  printf("Concat (own implementation): %s\n", str_concat2);

  return 0;
}

Praktikum 6

Aufgabe 2 (Zeiger)

Gegeben sei das folgende Programmfragment:

int main(){
  int m = 9;
  int n = 10;
  int* pm;
  int* pn;
  ... // Sie können eine Hilfsvariable vom Typ int verwenden
  ... // ???
  ... // ???
  printf("m = %i, n = %i.", m, n);
  return 0;
}

Komplettieren Sie das Programm, sodass am Programmende die Werte der Variablen n und m vertauscht sind. Damit es nicht zu einfach ist, sollen den Variablen n und m nicht direkt (d.h. m = ...) neue Werte zugewiesen werden, sondern mittels Dereferenzierung.

Lösung

#include <stdio.h>

int main(void) {
  int m = 9;
  int n = 10;
  int *pm = &m;
  int *pn = &n;
  int tmp_m = m;
  *pm = n;
  *pn = tmp_m;
  printf("m = %i; n = %i\n", m, n);

  return 0;
}

Aufgabe 3 (Wertzuweisung)

Welche Werte haben die Variablen y, c und d nach Durchführung der folgenden Anweisungen:

int n = 3;
float x = n;
float y = 1;
float *py = &y;
*py = 2 * *py * x;
int a[2] = {10,11};
int *b = a;
int c = a[0] * *(b+1);
int d = c + *b;

Berechnen Sie die Werte zunächst mit Papier und Bleistift und überprüfen Sie nachfolgend Ihre Lösung am Rechner.

Lösung

n = 3
x = n = 3
y = 1
*py = &y
*py = 2 * *py * x = 2 * 1 * 3 = 6
=> y = 6
a = (10, 11)
*b = a = &a[0]
c = a[0] * *(b+1) = 10 * *&a[1] = 10 * 11 = 110
d = c + *b = 110 + *&a[0] = 110 + 10 = 120

===
y = 6
c = 110
d = 120
#include <stdio.h>

int main(void) {
  int n = 3;
  float x = n;
  float y = 1;
  float *py = &y;
  *py = 2 * *py * x;
  int a[2] = {10, 11};
  int *b = a;
  int c = a[0] * *(b + 1);
  int d = c + *b;
  printf("y = %f; c = %i; d = %i\n", y, c, d);

  return 0;
}

Aufgabe 4 (Funktion)

Schreiben Sie eine Funktion hoch2, die für eine ganze Zahl ihre Quadratzahl berechnet. Rufen Sie die Funktion wie folgt auf:

...
for (int i = 0; i < 20; i++;){
	printf("%i\n", hoch2(i));
}
...

Lösung

#include <stdio.h>

int hoch2(int num) { return num * num; }

int main(void) {
  for (int i = 0; i < 20; i++) {
    printf("%i\n", hoch2(i));
  }

  return 0;
}

Aufgabe 5 (Funktion)

Schreiben Sie eine Funktion void dreh(char* s), die die Zeichenkette s in umgedrehter Reihenfolge ausgibt. Testen Sie diese Funktion ausführlich.

Lösung

#include <stdio.h>

void dreh(const char *s) {
  const char *ptr = s;
  while (*++ptr != '\0') {
  }
  ptr--;
  while (ptr >= s) {
    putchar(*ptr);
    ptr--;
  }
}

int main(void) {
  dreh("Hello World!");

  return 0;
}

Aufgabe 6 (Funktion)

Programmieren Sie eine Funktion void zp(int a, int b), die zu zwei gegebenen Zahlen $0 \leq a \leq b$ alle Zweierpotenzen im Intervall $\mathopen[ a, b \mathclose]$ ausgibt. Beispielsweise soll für $a = 10$ und $b = 200$ die folgende Ausgabe erzeugt werden: 16 32 64 128.

Lösung

#include <stdio.h>

void zp(unsigned int a, unsigned int b) {
  unsigned long int res = 2;
  while (res < a) {
    res *= 2;
  }
  if (res < b) {
    printf("%lu", res);
    res *= 2;
    while (res < b) {
      printf(" %lu", res);
      res *= 2;
    }
    printf("\n");
  }
}

int main(void) {
  unsigned int a, b;
  printf("a: ");
  scanf("%u", &a);
  printf("b: ");
  scanf("%u", &b);

  zp(a, b);

  return 0;
}

Aufgabe 7 (Funktion)

Programmieren Sie eine Funktion int vorkommen(const char* s, const char* m), die zählt, wie oft das Muster m im String s vorkommt.

Beispielsweise sollte der Aufruf vorkommen("Dies ist ein Beispieltext", "ie") den Wert $2$ liefern.

Lösung

#include <stdio.h>
#include <string.h>

const char INPUT_ERROR[] = "Receiving input resulted in an error!\n";

unsigned match_count(const char *s, const char *p) {
  unsigned int count = 0;
  unsigned long int i = 0;
  while (s[i] != '\0') {
    if (s[i] == p[0]) {
      i++;
      unsigned long int j;
      for (j = 1; p[j] != '\0' && s[i] == p[j]; i++, j++) {
      }
      if (p[j] == '\0') {
        count++;
      }
    } else {
      i++;
    }
  }

  return count;
}

int main(void) {
  char source[64], pattern[64];
  printf("source: ");
  if (fgets(source, sizeof(source), stdin) == NULL) {
    fprintf(stderr, INPUT_ERROR);
    return 1;
  }
  source[strlen(source) - 1] = '\0';

  printf("pattern: ");
  if (fgets(pattern, sizeof(pattern), stdin) == NULL) {
    fprintf(stderr, INPUT_ERROR);
    return 1;
  }
  pattern[strlen(pattern) - 1] = '\0';

  printf("count: %u\n", match_count(source, pattern));

  return 0;
}

Praktikum 7

Aufgabe 1 (Funktion)

Schreiben Sie eine Funktion int berechne(int v1, int v2, char op), die das Ergebnis des Ausdrucks v1 op v2 zurück liefert. Als gültige Werte für den dritten Parameter op sind zugelassen: +, -, * und /. Aufrufbeispiele:

  • int plus = berechne(17, 35, '+');
  • int mal = berechne(17, 35, '*');

Wird ein ungültiger Operator übergeben, soll der Wert $-999$ geliefert werden. Rufen Sie die Funktion mit unterschiedlichen Parameterwerten auf.

Lösung

#include <stdio.h>

int berechne(int x, int y, char op) {
  switch (op) {
  case '+':
    return x + y;
  case '-':
    return x - y;
  case '*':
    return x * y;
  case '/':
    return x / y;
  default:
    return -999;
  }
}

int main(void) {
  int x, y;
  char op;
  printf("1: ");
  scanf("%i", &x);
  printf("2: ");
  scanf("%i", &y);
  printf("Operator: ");
  scanf(" %c", &op);

  printf("Result: %i\n", berechne(x, y, op));

  return 0;
}

Aufgabe 2 (Kommandozeilenargumente)

Schreiben Sie ein Programm, das Kommandozeilenargumente der folgenden Art entgegen nimmt; beispielhafte Aufrufe:

Aufgabe2 12 13 +
Aufgabe2 42 100 -

Verwenden Sie zur Berechnung des Wertes die Funktion berechne von der vorhergehenden Aufgabe.

Prüfen Sie mögliche Fehlersituationen ab: zu wenige Argumente bzw. inkorrekte Argumente bei dem Aufruf der main-Funktion. Verwenden Sie die Funktion int atoi(char* string) aus der Bibliothek stdlib.h zur Umwandlung einer "String-Zahl" in eine Zahl vom Typ int.

Lösung

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int berechne(int x, int y, char op) {
  switch (op) {
  case '+':
    return x + y;
  case '-':
    return x - y;
  case '*':
    return x * y;
  case '/':
    return x / y;
  default:
    return -999;
  }
}

int main(int argc, char *argv[]) {
  if (argc != 4) {
    fprintf(stderr, "Amount of arguments given is not correct!\n");
    return 1;
  }
  int x = atoi(argv[1]), y = atoi(argv[2]);
  if (strlen(argv[3]) != 1) {
    fprintf(stderr, "Third argument is not a single character!\n");
    return 1;
  }
  char op = argv[3][0];
  printf("%i\n", berechne(x, y, op));

  return 0;
}

Aufgabe 3 (Funktion)

Schreiben Sie eine Funktion long ggt(long x, long y), die den größten gemeinsamen Teiler für zwei natürliche Zahlen x und y nach Euklid berechnet. Die Strategie ist wie folgt:

  • Falls $x = y$, ist das Ergebnis $x$.
  • Falls $x > y$, berechne den größten gemeinsamen Teiler von $x - y$, $y$.
  • Falls $x < y$, berechne den größten gemeinsamen Teiler von $x$, $y - x$.

Erstellen Sie zwei Varianten der Funktion ggt(long x, long y):

  1. Verwenden Sie eine while-Schleife, um die Zahlenwerte x, y zu verkleinern, bis beide den gleichen Wert haben.
  2. Erstellen Sie nun eine Lösung, bei der sich die Funktion ggt(long x, long y) selbst rekursiv aufruft.

Lösung

#include <stdio.h>

long int ggt_while(long int x, long int y) {
  while (x != y) {
    if (x > y) {
      x -= y;
    } else {
      y -= x;
    }
  }

  return x;
}

long int ggt_rec(long int x, long int y) {
  if (x == y) {
    return x;
  } else if (x > y) {
    return ggt_rec(x - y, y);
  } else {
    return ggt_rec(x, y - x);
  }
}

int main(void) {
  long int x, y;
  printf("x: ");
  scanf("%li", &x);
  printf("y: ");
  scanf("%li", &y);

  printf("result (while): %li\n", ggt_while(x, y));
  printf("result (rec): %li\n", ggt_rec(x, y));

  return 0;
}

Aufgabe 4 (Funktion)

Schreiben Sie eine Funktion bool prim(int x), die überprüft, ob die Zahl x eine Primzahl ist. Verwenden Sie folgenden Ansatz: testen Sie, ob die Zahl $x$ ganzzahlig teilbar ist durch eine Zahl $y = 2, 3, ...$ Falls nicht, ist x eine Primzahl. Bis zu welchem Wert $y$ muss die Überprüfung durchgeführt werden?

Lösung

#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>

bool prim(unsigned int x) {
  if (x == 1) {
    return false;
  } else if (x == 2) {
    return true;
  } else {
    unsigned int i, r = sqrt(x);
    for (i = 2; i <= r && x % i != 0; i++) {
    }
    return r == i - 1;
  }
}

int main(void) {
  printf("x: ");
  unsigned int x;
  scanf("%u", &x);

  printf("is prime number: %s\n", prim(x) ? "true" : "false");

  return 0;
}

Aufgabe 5 (Funktion)

Schreiben Sie ein Funktion void stat(const char* s), die eine Statistik für die Zeichekette s erstellt und diese innerhalb der Funktion wie folgt ausgibt:

Anzahl der Zeichen = ...
Anzahl der Worte = ...

Worte sind durch ein oder mehrere Leerzeichen voneinander getrennt.

Lösung

#include <stdio.h>
#include <string.h>

void stat(const char *s) {
  unsigned long int i = 0, chars = 0, words = 0;
  while (s[i] != '\0') {
    if (s[i++] != ' ') {
      words++;
      chars++;
      while (s[i] != ' ' && s[i] != '\0') {
        chars++;
        i++;
      }
    }
  }
  printf("Char count: %lu\n", chars);
  printf("Word count: %lu\n", words);
}

int main(void) {
  char s[64];
  fgets(s, sizeof(s), stdin);
  s[strlen(s) - 1] = '\0';

  stat(s);

  return 0;
}

Aufgabe 6 (Funktion)

Schreiben Sie eine Funktion void addiere(int *arg1, int arg2), die folgendes Aufrufverhalten umsetzt:

int n = 10;
int m = 5;
addiere(&n, m);
// n hat jetzt den Wert 15

Lösung

#include <stdio.h>

void addiere(int *x, int y) { *x += y; }

int main(void) {
  int x, y;
  printf("x: ");
  scanf("%i", &x);
  printf("y: ");
  scanf("%i", &y);

  addiere(&x, y);
  printf("x: %i; y: %i\n", x, y);

  return 0;
}