4. Rechnerübung Informatik 1 – Programmieren in C Datentypen in C In C existieren zwei Grunddatentypen: • Ganzzahlige Datentypen • Gleitkomma-Datentypen => Alle anderen Datentypen bauen auf diesen auf. Beispiel: Zeichenketten sind nur ein Feld des Datentyps “unsigned char“ (=8bit ohne VZ). Die Elemente sind dann die ASCII bzw. ANSICodes der jeweiligen Zeichen (z.B. 65 für „A“) Ganzzahlige Datentypen Die ganzzahligen Datentypen unterscheiden sich lediglich in ihrer Länge und im Vorhandensein eines Vorzeichenbits. Datentyp int unsigned int (= unsigned) long unsigned long short unsigned short char unsigned char Länge 32bit(*) 32bit(*) 32bit 32bit 16bit 16bit 8bit 8bit Vorzeichen ja nein ja nein ja nein ja nein Format-String %i %u %i, %li %u, %lu %i %u %c %c (*) Die Länge des Datentyps “int“ ist plattformabhängig und entspricht immer der Wortbreite des Prozessors. Auf heutigen PCs beträgt sie 32bit. Gleitkomma-Datentypen Die Gleitkomma-Datentypen unterscheiden sich nur durch ihre Länge und damit in ihrer Genauigkeit. Datentyp Länge Vorzeichen Format-String float double (= long float) long double 32bit 64bit 64/80bit(*) ja ja ja %f %lf, %e, %g %lf(*) Die Datentypen “float“ und “double“ sind auch als „single-precision“ bzw. “double-precision“ bekannt. Man kann sich ungefähr merken, dass “float“ 6-7 signifikante Dezimalstellen besitzt, bei “double“ sind es 14-15. (*) compiler-abhängig, mit MS VC++ mit “double“ identisch Die wichtigsten Datentypen Symbol Zahlen Menge printfAnweisung scanfAnweisung natürliche Zahlen (engl. unsigned) 0,1,2,3,… printf(“%u“,u) scanf(“%u“,&u); ganze Zahlen (engl. integer) -1,-2,0,1,2,… printf(“%i“,i) scanf(“%i“,&i); reelle Zahlen (engl. float) rationale und irrationale Zahlen printf(“%f“,f) scanf(“%f“,&f); => Von allen möglichen Datentypen werden im wesentlichen nur int, float, unsigned und char benutzt. float vs double Für Variablen vom Typ float werden im Speicher 4 Byte reserviert und sie können Werte von ~ 1.2*10-38 bis 3.4*1038 annehmen. Ein weitere Datentyp in C ist double (Formatstring: „%lf“(„long float“)). Für diesen Typ werden 8 Byte im Speicher reserviert und es sind Zahlen zwischen ~ 2.22*10-308 und 1.79*10308 erlaubt. -> Werte vom Typ double haben eine doppelte Genauigkeit! float vs double #include <stdio.h> #include <stdio.h> int main () { int main () { float a = 0.12345678901234567890; float b = 10; double a = 0.12345678901234567890; double b = 10; printf("%f+%f=%.17f\n", a,b,a+b); printf("%lf+%lf=%.17lf\n", a,b,a+b); return 0; return 0; } } Ergebnis: 0.12345678901234567890+10= 10.12345679104328200 Ergebnis: 0.12345678901234567890+10= 10.12345678901234600 „%.17f“ -> Die Angabe .17 legt fest, dass die Zahl mit 17 Nachkommastellen ausgegeben wird!!! Aufgabe 1 Erstelle ein C-Programm, welches zunächst eine nicht negative Zahl einliest (und überprüft, ob es sich tatsächlich um eine solche handelt) und anschließend die Wurzel dieser Zahl berechnet und das Ergebnis mit 9 Stellen hinter dem Komma am Bildschrim ausgibt! Hinweis: in der Headerdatei „math.h“ ist die Wurzelfunktion durch double sqrt(double) definiert Lösung #include <stdio.h> #include<math.h> main () { double zahl; printf("Bitte eine Zahl >= 0 eingeben:\n"); scanf("%lf",&zahl); if(zahl>=0){ printf("Die Wurzel von %lf lautet %.9lf\n", zahl, sqrt (zahl)); }else{ printf("Die Zahl ist kleiner als 0!\n"); } return 0; } Typ-Umwandlungen Da oft mit unterschiedlichen Datentypen gearbeitet wird ist es oft notwendig verschiedene Datentypen ineinander umzuwandeln. In C/C++ stehen dazu zwei Mechanismen zur Verfügung: - implizite Typumwandlung - explizite Typumwandlung (Type-Cast) Implizite Typ-Umwandlung Die implizite Typ-Umwandlung findet immer dann statt, wenn ein binärer Operator zwei Operanden unterschiedlichen Datentyps erhält. Beispiele: int i = 7; long l = i; float f = i; /*=> implizite Umwandlung von int nach long*/ /*=> implizite Umwandlung von int nach float*/ Implizite Typ-Umwandlung Achtung: Die implizite Typ-Umwandlung ist nur dann möglich, wenn der Zieltyp die Daten des Quelltyps ohne Informationsverlust aufnehmen kann. Folgende Umwandlung sind beispielsweise nicht erlaubt: float f = 2.71; long int li = f; int i = 1000000; short s = i; int i2 = -7; unsigned u = i; /*Fehler: int kann nur ganze Zahlen aufnehmen*/ /*Fehler: short kann nur Zahlen von -32768..32767*/ /*aufnehmen (16bit)*/ /*Fehler: unsigned kann kein Vorzeichen speichern*/ Implizite Typ-Umwandlung Hinweis: Ist eine implizite Typ-Umwandlung nicht erlaubt, so endet dies in der Regel in einer Warnung oder Fehlermeldung beim kompilieren. An dieser Stelle sollte man einen anderen Zieldatentyp, eine geeignete Funktion zur Umwandlung oder einen Type-Cast verwenden. Explizite Typ-Umwandlung Die explizite Typumwandlung ermöglicht eine gewollte Umwandlung eines Datentyps in einen anderen. Dazu existiert der so genannte “cast“-Operator: Syntax: (<Typ>) <Ausdurck> Explizite Typ-Umwandlung Achtung: Auch die explizite Typumwandlung kann verlustbehaftet sein. Da sie jedoch „explizit“, also gewollt, ist, wird keine Warnung ausgegeben. Beispiel: float f = 2.71; int i = (int)f; /*Umwandlung von float nach int. Die Nachkomma-*/ /*stellen werden „abgeschnitten“ => i = 2 */ Anwendung des Type-Casts #include <stdio.h> main () { int zahl1 = 5, zahl2 = 3; printf("5 : 3 =\n"); printf("ohne casten: %i\n", zahl1/zahl2); printf("mit casten: %f\n", (float)zahl1 /zahl2); return 0; } Format-Strings, die Zweite… Neben der bereits kennen gelernten, unformatierten Benutzung der Format-Strings können neben dem auszugebenden Datentyp noch weitere Felder angegeben werden: - Gesamtbreite der Ausgabe - Genauigkeit (bei Gleitkommazahlen) - Wissenschaftliche Notation (bei Gleitkommazahlen) Format-Strings, die Zweite… Die allgemeine Syntax eines Format-Strings lautet: %<len>.<prec><type> => Das Feld „len“ bezeichnet die Gesamtlänge der Ausgabe in Zeichen => Das Feld „prec“ gibt die Anzahl der auszugebenen Nachkommastellen an => Das Feld „type“ entspricht dem bekannten Zeichen für den Datentyp Beispiele: printf(“%4i“, 2); printf(“%7.3f“, 3.141592); => => 2 3.141 Format-Strings, die Zweite… Wichtig: „Passt“ die Ausgabe nicht in die vorgegebene Breite, so wird diese ignoriert. Man sollte daher auf ausreichende Dimensionierung der Ausgabebreite achten Beispiele: printf(“%3i“, 2048); printf(“%5.3f“, 13.75); => 2048 => 13.750 Aufgabe 2 Erstelle ein C-Programm, welches zunächst einen Bruch (Zähler und Nenner) einliest (und überprüft, ob der Nenner ungleich 0 ist) und diesen dann in eine Dezimalzahl umwandelt und diese am Bildschrim ausgibt. Eine Genauigkeit auf 7 Stellen hinter dem Komma ist diesmal ausreichend! Lösung #include <stdio.h> main () { int zaehler, nenner; printf("Bitte Zaehler eingeben:\n"); scanf("%i",&zaehler); printf("Bitte Nenner eingeben:\n"); scanf("%i",&nenner); if(nenner!=0){ printf("Der Bruch %i/%i laesst sich durch Casten in eine \ Dezimalzahl umwandeln\n", zaehler, nenner); printf("%.7f\n", (float) zaehler/nenner); }else{ printf("Der Nenner darf nicht 0 sein!\n"); } return 0; }