INE1 – Informatik für Ingenieure 1 Praktikum 11: Bit-Operationen, 2D-Arrays Aufgabe 1: Bit-Operationen In den Unterlagen finden Sie eine Funktion, die eine Zahl Binär auf die Konsole ausgibt. Entwikkeln Sie eine Funktion byte2binary mit folgendem Prototyp (der Prototyp wird oft auch als Signatur bezeichnet): void byte2binary (int num, char * result); Die Funktion bekommt eine Zahl, deren niederwertigste acht Bit sie in Binärdarstellung umwandelt. Die Binärdarstellung wird in einen Zeichenpuffer (*result) geschrieben, der als zweites Argument übergeben wird (ähnlich wie bei scanf erfolgt die Rückgabe hier also nicht über den return-Wert der Funktion, sondern über einen zuvor bereitgestellten Speicherbereich). Hinweise Die Zeile *result = (mask & num) ? '1' : '0'; ist auf den ersten Blick etwas unübersichtlich, da sie den ternären Operator "?:" verwendet. Die Zeile könnte man durch eine einfache Auswahlanweisung ersetzen: if (mask & num) { *result = '1'; } else { *result = '0'; } Die Anweisung mask >>= 1 könnte man schreiben als mask = mask >> 1. Aufgaben • Machen Sie sich klar, wie byte2binary funktioniert. Testen Sie das Programm mit ein paar Eingabewerten. • Erweitern Sie das Hauptprogramm so, dass zwei int-Zahlen m und n eingelesen werden. Diese sollen dann wieder im Binärformat ausgegeben werden und ausserdem die Ergebnisse der Operationen a & b, a | b, a >> 1, b << 2 und ~a. Gerrit Burkert, Karl Rege 26.11.15 1 INE1 – Informatik für Ingenieure 1 Aufgabe2: Parity Wenn auf einer Kommunikationsleitung Bytes mit 7-Bit-ASCII-Code übertragen werden, ist es üblich, die einzelnen Bytes mit einem sogenannten achten Paritäts- Bit zu versehen; damit soll die Übertragungssicherheit verbessert werden. Das Parity-Bit “sagt“, ob die Anzahl der Bits (in einem Byte), die auf Eins gesetzt sind, gerade oder ungerade ist. Der Sender zählt somit die “Einer“-Bits im zu übertragenden Byte und ergänzt das Byte mit dem berechneten Paritäts- Bit so, dass die Gesamtanzahl der Einser gerade oder ungerade ist. Der Empfänger berechnet auf die gleiche Weise die Parität des empfangen Bytes und vergleicht diesen mit dem übertragenen Paritäts-Bit. Aufgabe • • • • • • Bei der seriellen Übertragung werden manchmal nur 7 Bits für Nutzdaten (Bits 0..6) und ein Parity-Bit (Bit 7) verwendet (vorderstes Bit = Parity) Lesen Sie ein Byte als Dezimalzahl (0..127) ein: verwenden Sie den Datentyp unsigned char (=unsigned Integer der Grösse eines Bytes). Hinweis: Sie können mit scanf("%d",x) nur in eine Variable x von Typ Integer einlesen. Mit scanf eine Zahl in eine Integer-Variable y einlesen und anschliessend einer char var input zuweisen: input = (unsigned char) x; Berechnung der Parität: gerade Anzahl Einser in Bits 0..6 -> Parität-Bit =0, ungerade Anzahl > Parität-Bit =1. Schreiben Sie dafür eine Funktion addParity(unsigned char* input).Diese Parität wird in der obigen Funktion als vorderstes Bit des übergebenen Byte gesetzt. Schreiben Sie eine weitere Funktion bool checkParity(unsigned char input) das die Parität überprüft Testen Sie Ihre beiden Funktionen. Sie können dafür auch die Funktion aus der ersten Aufgabe verwenden. Beispiel (even parity): 7 (Parity) 6 5 4 3 2 1 0 1 0 0 0 0 1 1 1 Gerrit Burkert, Karl Rege 26.11.15 2 INE1 – Informatik für Ingenieure 1 Aufgabe 3: Spaltensumme im Array Für ein zweidimensionales Array soll in jeder Spalte die Summe berechnet werden. Das Ergebnis ist also ein eindimensionales Array. Beispiel: 1 2 3 5 6 4 sum7 8 9 10 11 15 18 21 24 12 In der ersten Variante des Programms wird das zweidimensionale Array an die Funktion summeSpalten übergeben. Dafür nehmen wir an, dass die zweite Dimension („Breite“ des zweidimensionalen Arrays) fest auf 4 gesetzt ist. Das Ergebnis soll ein ein Array erg geschrieben werden, das bereits in der passenden Grösse vorbereitet ist und ebenfalls als Parameter übergeben wird. Das Hauptprogramm sieht dann folgendermassen aus: int main (void) { int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }}; int erg[4]; summeSpalten(erg, a, 3); druckeIntArray(erg, 4); return 0; } Implementieren Sie die Funktion summeSpalten. Damit Sie nicht soviel Zeit verlieren, finden Sie die Funktion druckeIntArray unten im Anhang zu dem Praktikum. Dass die Funktion summeSpalten nur mit einer festen zweiten Dimension von 4 verwendet werden kann, ist unpraktisch. In der zweiten Variante summeSpalten2 soll das zweidimensionale Array daher als eindimensionales Array übergeben werden. Nun müssen Sie auch die Zeilen und Spalten als separate Parameter der Funktion übergeben. Der Prototyp der Funktion ist jetzt: void summeSpalten2 (int *erg, int *a, int rows, int cols); Wie muss die Funktion jetzt aufgerufen werden? Das Ergebnis-Array haben wir bereits vor Aufruf der Funktion summeSpalten angelegt und als Parameter übergeben. Könnten wir das Array auch in der Funktion anlegen mit int erg[4]; und als return-Wert an das Hauptprogramm zurückgeben. In der dritten Variante soll das Ergebnis-Array nun in der Funktion summe_spalten_3 selbst angelegt werden, aber nicht auf dem Stack, sondern dynamisch auf dem Heap. Die Funktion gibt dann einen Zeiger auf das Array zurück. Implementieren Sie auch diese Variante. Vergessen Sie nicht, den dynamischen Speicher nach Benutzung wieder freizugeben. Der Funktionsprototyp ist nun: int * summeSpalten3 (int * a, int rows, int cols); Gerrit Burkert, Karl Rege 26.11.15 3 INE1 – Informatik für Ingenieure 1 /** * Ausgabe des int-Arrays */ void druckeIntArray (int zahlen[], int anz) { int i; printf("{ "); if (anz>0) { printf("%d", zahlen[0]); } for (i=1; i<anz; i+=1) { printf(", %d", zahlen[i]); } printf(" }\n"); } /** * Hauptprogramm mit Testdaten */ int main (void) { int i; int a[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }}; int erg[4]; int * ergdyn; int * b; int * c; b = a; c = a; //printf("a: %p\n", a); //printf("c: %p\n", c); //summe_spalten_1(erg, a, 3); //drucke_int_array(erg, 4); return 0; } Gerrit Burkert, Karl Rege 26.11.15 4