# Textdatei einlesen in C *Die Funktionen sind gelb markiert.* </br> 1. ++Pointer++ erstellen: ```c= FILE *fp; ``` </br> 2. Textdatei öffnen mit Funktion ==fopen()==; ```c= fp = fopen("ABC.txt", "r"); //"r" steht für read. //Mit "w" kann man was reinschreiben ``` </br> 3. Prüfe ob Datei nicht leer ist: ```c= fp == NULL; //Nutze eine if Abfrage ``` </br> 4. Mit ==fgetc()==; einzelne char aufrufen. (fgetc = file get char) ```c= char c = fgetc(fp); ``` Um den zweiten Character aufzurufen, führe die Funktion fgetc(); einfach ein zweites mal aus. Bei jedem Aufruf der Funktion wird der nächste Character aufgerufen. </br>6. Mit ++EOF++ schauen, ob wir am Ende der Datei angekommen sind. (EOF = EndOfFile) ```c= fgetc(fp) != EOF; //Dies können wir mit einer while() Schleife nutzen. ``` </br> 7. Textdatei schließen mit ==fclose()==; ```c= fclose(fp); ``` </br></br> # Anzahl von unbekannten Elementen in Array bestimmen In c sind die Elemente von einem Array immer vom gleichen Typ. Gegeben ist: ```c= int a[] = { 1, 2, 3, 4, 5 }; ``` </br> 1. Teile die Gesamt-Byte-Größe durch die Byte-Größe vom ersten Element mit ==sizeof()==; ```c= int n = sizeof(a) / sizeof(a[0]); //Anzahl der Elemente = 5 ``` Beachte: Das Ende vom Array wird nicht angezeigt. Du musst mit einer Schleife über das Array iterieren und als Parameter die Anzahl der Elemente vom Array nehmen. </br> </br> </br> </br> # Bäume - **Traversierung** heißt das Durchwandern von Knoten in einem Baum in einer bestimmten Reihenfolge. :::info - **pre-order** Suche bedeutet erst wird (bei pre-order fangen wir oben an) 1. der Elternknoten aufgerufen, 2. dann der linke Kindknoten, 3. dann der rechte Kindknoten. - **in-order** (wir fangen unten an, linker Knoten) 1. linker Kindknoten 2. Elternknoten 3. rechter Kindknoten - **post-order** (wir fangen unten an, linker Knoten) 1. linker Kindknoten 2. rechter Kindknoten 3. Elternknoten - level-order 1. Zeilenweise von links nach rechts ::: Tip: Wenn du Knoten rekursiv durchläufst und zB int zurückgeben willst, dann musst du bei return die Rekursion einsetzen. Kleines Beispiel: ```c= int equal_nodes(Node *node) { int count = 0; if (node == NULL) //Leerer Baum return 0; if (node->left != NULL) //Note left nicht null { if (node->value == node->left->value) //Elternknoten gleich linker Kindknoten? count++; } if (node->right != NULL) //note right nicht null { if (node->value == node->right->value) //Elternknoten gleich rechter Kindknoten? count++; } return count + equal_nodes(node->left) + equal_nodes(node->right); //rekursiver Aufruf, Addition } ``` Tip: Mit einer If-Abfrage prüfen, ob pointer nicht null ist, bevor man auf den Inhalt zugreift. Nicht einfach node->value, sondern if(node != NULL) {node->value}; bzw. nicht node->left->value, sondern if(node->left != NULL){node->left->value}; sonst gibt es evtl. ++Segmentation fault (core dumped) </br> # Fehlermeldungen und co - Fehlermeldung ++Segmentation fault (core dumped) -> tritt meistens bei int Arrays auf -> zB existiert der Index des Arrays nicht und wird trotzdem aufgerufen ```c= int test[4] = {1, 2, 3, 4}; //es existiert Index 0 bis 3 test[8] = 6; //funktioniert nicht ``` **Prog I lib** - ==require()==; -> steht im Rumpf der Funktion als erstes -> Vorbedingung, damit Funktion ausgeführt wird -> überprüft zB ob Parameter nicht leer ist ```c= void rotate(int* a, int n, int r) { require_not_null(a); //Überprüfung, ob a nicht leer ist require("not negative", n >= 0); //Überprüfung, ob n nicht negativ ist ... } ``` - ==ensure()==; -> steht am Ende des Rumpfes -> überprüft zB ob Ergebnis eine bestimmte Bedingung erfüllt -> bricht Funktion ab, wenn Bedingung nicht erfüllt ist # Purpose Statement / Code kommentieren Purpose Statement: Nur der erste Satz, der beschreibt, was die Funktion leistet. 1. Variablen und Funktionsnamen nur mit Kleinbuchstaben Wenn ein Variablen- oder Funktionsname aus 2 Wörtern besteht Unterstrich _ benutzen. Beispiel: ```c= int count_positive_digits() { .... int result = 0; } ``` 2. Konstanten (Variablen mit Werten, die immer gleich bleiben) werden nur mit Großbuchstaben geschrieben. Beispiel: ```c= int SALARY_MANAGER_EURO = 39; ``` 3. Bei type names wie zB: - struct typedef zB Nodes - usw. Erster Buchstabe wird großgeschrieben, kein Unterstrich, neues Wort direkt dahinter mit ersten Buchstaben groß schreiben. 4. Bei Addition und Subtraktion einen Leerschritt jeweils setzen. Beispiel: ```c= if(x + 2) { ... } ``` 5. In Loops als Variablennamen für Index einer der folgenden Buchstaben verwenden: - i - j - k 6. Bei Variablennamen nicht den Typ der Variable mit im Namen verstecken. Beispiel: ```c= int count_int = 0; //Nicht schön char name_char = ''; //Auch nicht schön //Besser: int count = 0; char name = ''; ``` 7. Verwende den Plural wenn es mehrere Elemente zB in einem Array gibt. Beispiel: ```c= char names[3] = ...; ``` 8. l und o nicht als Variablennamen verwenden. -> l wird mit groß-i verwechselt. -> o wird mit Null verwechselt. # char Arrays ```c= char hello[] = {"Hallo Welt\n"}; char names[] = {'R', 'e', 'm', 'e', 'm', 'b', 'e', 'r'}; printf("%c", names[0]); //output ist R ``` - require_not_null(hello); //fragt ab, ob zB array nicht leer ist. # Dokumantationskommentar in Doxygen-Syntax (nicht in Klausur notwendig) - Purpose Statement + @param, @return etc # Formated output - %d decimal integer - %6d decimal integer, at least 6 characters wide, right-justified - %f floating-point number - %.2f float, 2 characters after decimal point - %6.2f float, at least 6 characters wide, of which 2 are after the decimal point - %e [“-”] d “.” dddddd ”e” (“+”|“-”) xx - %x hexadecimal integer (base 16) - %#x hexadecimal integer (base 16), preceded by “0x” - %c character - %s character string - %8.4s print 8 characters wide, first 4 characters of string, left-pad with space - %% the % itself # Pointers :::info little-endian - größte Wert wird an niedrigster Adresse gespeichert </br> big endian - größter Wert wird in höchster Adresse gespeichert ::: # Listen 1. Um zu überprüfen, ob das Ende der Liste erreicht wurde: ```c= list != NULL; //nicht list->value oder list->next oder list->next-value; ``` 2. Kopie von Listen erstellen: ```c= IntList *list; //*list ist Pointer vom Typ IntList IntList *list2 = list; //list ist Pointer vom Typ IntList //Um zB auf Werte von List2 zuzugreifen und wir nicht den Pointer //haben wollen, müssen wir *list oder list-value schreiben. ``` 3. Bei Listen muss man grundsätzlich eine Kopie anfertigen, damit wir zB die Länge bestimmen ohne die Liste zu zerstören. Der Pointer auf den ersten Wert der Liste geht verloren, wenn wir mit list = list->next; iterieren. Also: Kopie erstellen! # Characters wichtige Funtkionen char c[] = "Hello 123 duda."; :::info isalpha(c[0]) non-zero if c is alphabeti isupper(c[0]) non-zero if c is upper case islower(c[0]) non-zero if c is lower case isdigit(c[0]) non-zero if c is a digit isalnum(c[0]) non-zero if c is alphabetic or a digit isspace(c[0]) non-zero if c is whitespace (blank, tab, newline, etc.) toupper(c[0]) convert c to upper case tolower(c[0]) convert c to lower case :::