Answered additional questions
This commit is contained in:
parent
835d928e5e
commit
4035654f41
1 changed files with 79 additions and 0 deletions
|
@ -183,3 +183,82 @@ int main() {
|
|||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
*** Welche Probleme können bei einer rekursiven Implementation einer Funktion auftreten?
|
||||
Rekursive Implementation können verschiedene Probleme aufweisen. Ein häufiges Problem ist eine extrem lange Laufzeit (große Zeitkomplexität). in gutes Beispiel hierfür ist eine rekursive Berechnung einer Zahl aus der Fibonacci Reihe (ohne caching). Hierbei werden häufig immer wieder die gleichen Zahlen als Zwischenschritt berechnet, weshalb die Laufzeit für die Berechnung vom 100sten Element viele Jahre dauert. Dadurch sind rekursive Ansätze für große Berechnungen meist aus Performance gründen nicht sinnvoll. Ein anderes Problem wäre unendliche Laufzeit, wenn ein bestimmte Bedingung gar nicht erfüllt werden kann, in welchem Fall sich die Funktion selbst immer wieder aufruft und dadurch nie endent. So etwas kann in der Implementation verhindert werden.
|
||||
|
||||
*** Was ist der Unterschied zwischen einer Call-by-Reference und einer Call-by-Value Funktion? Nennen Sie für beide Arten Beispielfunktionen aus der C-Standardbibliothek.
|
||||
Bei einer Call-by-Value funktion, wird direkt ein Wert in die Funktion gegeben. Dieser wird dann kopiert und alle Modifikationen dieses Wertes passieren in der Kopie, statt in dem Wert (z. B. einer Variable), die der Funktion direkt gegeben wurde. Eine Call-By-Reference Funktion bekommt stattdesssen einen pointer zu einer Variable. Dadurch das statt einem Wert eine Speicheradresse gegeben wird, wird der Wert der Variable direkt modifiziert. Dementsprechend sind call-by-reference Funktionen genau dann sinnvoll, wenn der Wert der Variable in der Funktion selbst modifiziert werden soll.
|
||||
Ein Besispiel für eine Call-By-Reference Funktion wäre zum Beispiel ~scanf()~ auf ~stdio.h~, welche eine Speicheradresse zu dem Buffer bekommt, in den geschrieben werden soll.
|
||||
Ein Beispiel für eine Call-By-Value Funktion ist z. B. ~strcmp()~ aus ~string.h~, in der zwei Strings verglichen werden. Da die strings hier selbst nicht bearbeitet werden müssen, sondern nur die Werte verglichen werden, ist dieser Ansatz hier sinnvoller.
|
||||
|
||||
*** Aus welchem Grund sollte die ~goto~-Anweisung bei der Programmierung grundsätzlich vermieden werden?
|
||||
Code, der über ~goto~ strukturiert ist, neigt dazu sehr unleserlich, unübersichtlich und schwer verständlich zu werden. Es gibt allerdings Ausnahmefälle, in denen ~goto~ die Leserlichkeit verbessern kann, diese sind jedoch selten. ~goto~ Kann außerdem dazu genutzt werden, um die Struktur des C codes ähnlicher zu der von Assembly code zu machen, was in seltenen Niechenfällen nützlich sein kann.
|
||||
|
||||
*** Wodurch wird ein Character-Array zu einem String?
|
||||
Strings sind ~char~ arrays, die mit einem Besondern byte, also ~char~, dem sogenannten Null-Terminator (~'\0'~), beendet werden. Dadurch können Funktionen, die mit den strings arbeiten, erkennen, das a) der gegebene Array tatsächlich ein String ist und b) der String am Ende tatsächlich beendet ist.
|
||||
|
||||
*** Welche Informationen befinden sich in einer Deklarationsdatei (Header)?
|
||||
Ein Header enthält hauptsächlich leere Implementation von Funktionen (Nur die Kopfzeile wo Name, typ und Parameter spezifiziert werden), ~structs~, aber keine Implementationen von structs, d. H. in dem struct werden keine Werte zugeordnet, und außerdem Deklarationen von globalen Variablen (aber nur namentlich, ohne Wertzuweisung), Makros und typedefs. Zudem findet in headern oft das inkludieren von Bibliotheken statt, die dann in dem Progran genutzt werden. Die Funktionen werden dann in Dateien mit dem gleichen Namen (Mit der Dateiendung .c) implementiert. Diese Datei inkludiert den Header. Ferner gibt es in header Dateien oft sogenannte /include guards/, welche dazu dienen, redundaten imports zu vermeiden. Ein Beispiel für eine Header Datei wäre zum Beispiel:
|
||||
#+BEGIN_SRC C
|
||||
// Code aus library.h
|
||||
#ifndef LIBRARY_H_ // Überprüft, ob LIBRARY_H_ definiert ist. Wenn nicht geht es weiter, wenn doch wird der include direkt beendet.
|
||||
#define LIBRARY_H_ // Macro als Teil des Include guards definiert
|
||||
|
||||
#include <stdio.h> // Importiert stdio.h, damit es später benutzt werden kann.
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARR_SIZE 1024 // "Magische Zahl", wird hier benutzt um eine konstante größe von Arrays festzulegen.
|
||||
typedef unsigned char uchar; // Definiert den typ uchar, der gleichbedeutend mit unsigned char ist. Nützlich für 8-bit Zahlen von 0-8
|
||||
|
||||
struct Tier {
|
||||
int alter;
|
||||
char spezies[ARR_SIZE];
|
||||
uchar sprunghöhe;
|
||||
};
|
||||
|
||||
struct Tier* erschaffe_tier(int alter, char* spezies, uchar sprunghöhe);
|
||||
void springe (struct Tier tier);
|
||||
|
||||
int Tieranzahl;
|
||||
|
||||
|
||||
#endif // LIBRARY_H_
|
||||
#+END_SRC
|
||||
|
||||
Das hier wäre die Header Datei. Sie könnte zum Beispiel so benutzt werden:
|
||||
#+BEGIN_SRC C
|
||||
// Code in library.c
|
||||
#include "library.h"
|
||||
|
||||
struct Tier* erschaffe_tier(int alter, char* spezies, uchar sprunghöhe) {
|
||||
struct Tier* neues_tier = (struct Tier*) malloc(sizeof(struct tier));
|
||||
neues_tier->alter = alter;
|
||||
neues_tier->spezies = spezies;
|
||||
neues_tier->sprunghöhe = sprunghöhe;
|
||||
tieranzahl++;
|
||||
return neues_tier;
|
||||
}
|
||||
|
||||
void springe(struct Tier tier) {
|
||||
printf("Das tier ist %d meter hoch gesprungen.", tier.sprunghöhe);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
Das könnte dann in einer anderen Datei benutzt werden:
|
||||
#+BEGIN_SRC C
|
||||
// code in main.c
|
||||
#include "library.h"
|
||||
|
||||
int main(){
|
||||
struct Tier* graues_riesenkänguru = erschaffe_tier(5, "Känguru", 3);
|
||||
springe(*graues_riesenkänguru);
|
||||
printf("Das tier ist %d Jahre alt.\n", graues_riesenkänguru->alter);
|
||||
printf("Das tier hat die Spezies %s\n", graues_riesenkänguru->spezies);
|
||||
printf("Insgesamt wurden %d Tiere erschaffen", tieranzahl);
|
||||
return 0;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
*** Preprocessor Erklärung
|
||||
Der Präprozessor in C ist ein Teil des Kompilierungsvorgangs
|
||||
|
|
Loading…
Reference in a new issue