Du befindest dich hier: FSI Informatik » Prüfungsfragen und Altklausuren » Prüfungen im Bachelor-Studium (1. - 5. Semester) » Lösungsvorschlag (Übersicht)
Dies ist eine alte Version des Dokuments!
Inhaltsverzeichnis
Lösungsvorschlag
Aufgabe 1.1: Einfachauswahl-Fragen
a) 2 b) 2 c) 3 d) 3 e) 1 f) 2 g) 4 h) 4 i) 2 j) 3 k) 2
Aufgabe 1.2: Mehrfachauswahl-Fragen
a) 3.4.8
b) 2,3,5,6
Aufgabe 2: vsc
#define FRAME_SIZE 640*480 struct data { char frame[FRAME_SIZE]; int eof; }; #include <dirent.h> #include <errno.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/stat.h> #include "jitbuf.h" static void die(const char message[]) { perror(message); exit(EXIT_FAILURE); } // weitere Includes, Konstanten // globale Variablen, Funktionsdeklarationen usw. void *showFrame(void); #include <fnmatch.h> // Funktion main() static int main(int argc, char** argv){ if(jbInit() != 0){ fprintf("Error creating jb"); exit(EXIT_FAILURE); } timeslider#10451 phtread_t tid; errno = pthread_create(&tid, NULL, showFrame, NULL);//show Frame soll nach angabe glaube ich (void) als parameter haben if(errno !== 0){ perror("thread"); exit(EXIT_FAILURE); } // Socket erstellen und Verbindungsannahme vorbereiten int ls, cs; struct addrinfo hints={ .sin6_family = AF_INET6, .sin6_port = htons(2014), .sin6_addr = in6addr_any, } if(ls = socket(AF_INET6, SOCK_STREAM, 0) == -1 || bind(ls, (struct sockaddr*) &hints, sizeof(hints)) == -1 || listen(ls, SOMAXCONN) == -1){ perror("socket, bind or listen"); //sehr witzig exit(EXIT_FAILURE); } // Verbindung annehmen und Verarbeitung vorbereiten // cs wurde noch nicht gesocket() if(cs = accept(ls, NULL,NULL) == -1){ perror("accept"); } while (t){ //wo kommt denn dieses t her? FILE* reader = fdopen(cs, "r"); if(reader == NULL){ perror("openStream"); exit(EXIT_FAILURE); } struct data *video = malloc (sizeof(struct data));//warum mallocen und net aufm stack anlegen struct data video;//genau so hätte ich es auch gemacht knoti^^ // Videobilder einlesen und in den Puffer schreiben size_t bytesRead = 0; while((bytesRead = fread(video->frame, sizeof(byte), 307200, reader)) != 0){ // ich dachte man gibt als Paketgroesse 640 an und dass man 480 pakete lesen will if(bytesRead < 307200){//braucht man hier net eher feof() und kann die byte anzahl einfach untern tisch kehren^^//jo video->eof = 1;//dann brauchst du aber auch noch ein break; oder so }else{ video->eof = 0; } jbPut(video); //wenn mit malloc fehlt free, jbPut/Get kopiert den Inhalt, nicht den pointer video = malloc (sizeof(struct data));//warum?, stack sollte reichen } errno = phtread_join(tid,NULL);//rfür was braucht man pthread_join?//damit wartet man auf die Terminierung des anderen Threads. Das steht so in der Aufgabe "wartet auf dessen Terminierung und beendet sich dann" if(errno != 0){ perror("pthread join"); exit(EXIT_FAILURE); } if(close(ls) != 0 || close(cs) != 0){ die("close sockets"); } if(fclose(reader) == EOF){ die("closing reader"); } exit(EXIT_FAILURE); //warum failure?? muesste es nicht success heissen?) } // Ende Funktion main // Funktion showFrame // Ausgabegeräte suchen void * showFrame(void){//hat übergabeparameter void , verträgt sich also nicht mit der pthread_create funktion weil die erwartet ein void * ->voidpointer als übergabe//aha. also noch mal ne thread-Methode machen, die diese dann aufruft?? DIR *d; if((dir = opendir("/dev") == NULL){ perror("opendir"); exit(EXIT_FAILURE); } struct dirent e; errno = 0; int nFiles = 0; FILE * outFiles[10]; while((e= readdir(d)) != NULL && nFiles < 10 ){ //ich haette hier eher ne for-Schleife gemacht if(fnmatch( "fb*", e->d_name, 0) == 0){ /********edit changed**********/ char path[strlen("/dev/") + strlen(e->d_name)]; //man braucht noch ein Zeichen mehr fuer das \0 zeichen. also noch mal +1 sprintf(path, "/dev/%s", e-d_name); outFiles[nFiles] = fopen(path, "a+");//VORSICHT: du musst schon den kompletten pfad übergeben -> strcat mit /dev/ und e->d_name, oder hab ich des falsch im kopf???? (also könnte schon stimmen, bin mir gerade net ganz sicher)// habs wie er...ohne pfad//FILE *fopen(const char *path, const char *mode); - habs angepasst // das Arbeitsverzeichnis ist ja nicth in /dev von daher muss man denke ich schon den absoluten pfad angeben, weil der relative bezieht sich ja aufs Arbeitsverzeichnis und des kann irgendwo sein, oder? also ich denke du hast recht - hier muss man wohl den gesamten Pfad übergeben. if(outFiles[nFiles] == NULL){ perror("opening File"); continue; } nFiles++; } } // Videobilder aus Puffer entnehmen und ausgeben struct data *video; int eof = 0; while(eof == 0){ jbGet(video); for(int i = 0; i < nFiles; i++){ fwrite(video->frame, sizeof(byte), 307200, outFiles[i]);// ich hab da irgendwas anderes eher sowas: fwrite(datax.frame, FRAME_SIZE, 1, FRAME,fopeners[anz2]); //aber meins kann auch kompletter unsinn sein, kannst du mir mal deine lsg erklären, wie man da drauf kommt?// alsi cih hab fwrite(video->frame,1,FRAME_SIZE,hier muss irgendwie der stream rein^^);//ja schon datax.frame sind meine daten und foperns[anz] mein stream, so aber jetzt geh ich wirklich ins bett gn8 dir } eof = video->eof; free(video)//nachdem du das video geschrieben hast, kannste es ja wieder neubelegen also nen stack-cache davon, dafür brauchst du kein malloc oder free if(fclose(outFiles[i]) == EOF){ die("fclose"); } } } // Ende Funktion showFrame /************************************************************** * Datei jitbuf.c *************************************************************/ #define CACHE_SIZE 100 #define BUFFER_SIZE 20 static volatile size_t readPos; static volatile size_t writePos; static SEM* fullSlots; static SEM* freeSlots; static SEM* waiter; static size_t itemsBuffered; static struct data cache[CACHE_SIZE]; // Funktion jbInit int jbInit(void){ waiter = semCreate(0); freeSlots = semCreate(CACHE_SIZE); fullSlosts = semCreate(0); if(waiter == NULL || fullSlots == NULL || freeSlots == NULL){ frpintf("error creating needed sems");//kann man free auf Null aufrufen, ja stimmt müsste gehen....//hier stimmt das meiner meinung nach nicht,da du jenachdem wiewiet du ohne fehle rkommst verschieden freen musst - das glaub ich nicht . is in dem fall ja egal, weil die nicht ineinander verschachtelt sind//man darf bei sowas normal nur destroy auf was aufrufen, was auch erfolgreich mit create erzeugt wurde, sonst ist das Verhalten undefiniert. Man muss also leider der Reihe nach erzeugen und dann bei spaetren Fehlschlaegen die vorher erfolgreich erzeugten zerstoeren. semDestroy(waiter); semDestroy(fullSlots); semDestroy(freeSlots); return 1; } //Annahme: semDestroy(NULL) tut nichts//Aber gut, mit der Annahme ist es dann denke ich wieder ok. itemsBuffered = readPos = writePos = 0;//ist schon implizit auf 0 return 0; } // Funktion jbPut void jbPut(const struct data *data){//returnen und nicht einfach Blockieren? //war schon ein P, ein P wie Plockieren und ein V wie Vreigeben,asooo meine Eselsbrücke if(itemsBuffered >= CACHE_SIZE) return; //wieso das?//verstehe ich auch nicht P(freeSlots); cache[writePos] = data; //Sollte hier bzw weiter unten nicht stehen: cache[writePos] = *data; ? Das Array speichert Structs und nicht pointer. geht das so, oder braucht man memcpy?. //sollte ohne memcpy gehen. Siehe Rudis kommentar im thread zu der aufgabe im forum//wo steht der kommentar?//sollte eh alles ganz ohne malloc gehen, weil cache ne fixe groesse hat und wie gesagt den dateninhalt statt die pointer speichert XXXXX= *YYYYY holt sich den inhalt von YYYYY und speichert den in XXXXX und das ist sozusgagend ein internes memcpy^^(also das =) //darfst aber den foren link trotzdem noch posten, würde ich mir mal anschauen wollen... //https://fsi.informatik.uni-erlangen.de/forum/thread/12359-vsc-Klausur-s2014 //letzter kommentar in den thread.// ja da steht genau des mit dem = (ich glaube rudi meint, dass das structs kopieren über diese = operation schon seit C89 geht oder aber memcpy????, bin mir da net ganz sicher was er meint, aber = geht aufjedenfall) // = sollte gehen für structs, joa//bei was braucht man eigentlich memcpy überhaupt? realloc implementieren :D ne, memcpy is für zeug aufm heap glaub ich.//naja heap kann ich auch derefernzieren und mit = vollschreiben// eventuell array operationen also wenn ich ganze arrays kopieren will die nicht innerhalb eines structs sind???//das auch, ja. Aber hier liegt ja das ganze array aufm stack, weils im struct ist, ist also hier kein problem. //ja des im struct ist klar, aber würde denke ich auch gehen wenns aufm heap liegen würde (also nicht aufm stack) //hm stimmt, müsste derefenziert werden der pointer, habs zwar jetzt hier nicht getestet, aber sollte schon so sein //ok net ganz richtig für arrays mit variabler länge gilt das nicht da sinds ja nur pointer und da werden pointeradressen einfach kopiert und nicht mehr //writePos++;//geht glaube ich auch infix, da ++ post-inkrement ist, also danach ausgewertet wird cache[writePos++] = data; // writepos wieder auf 0 setzen? // if(writePos >= CACHE_SIZE) writePos = 0; V(fullSlots); itemsBuffered++; if(itemsBuffered == BUFFER_SIZE){//ah cool, glaube da wäre ich wirklich net so schnell drauf gekommen des so zu lösen V(waiter); } //ICH BIN MIR NICHT SICHER ob die Sache mit von Puffer auf Durchzug schalten hier wirklich korrekt ist. Ich habe das so geloest: in der init-Funktion den waiter auf minus 20 setzen, dann muss 20 mal V(waiter) aufgerufen werden, in Flush mache ich auf waiter noch mal semCreate mit 0. Dann ist der Spuk vorbei. [//Ich rufe also immer in put V(waiter) und in get P(waiter) auf also genauso wie fullSlots } // Funktion jbGet void jbGet(struct data *data){ P(waiter); P(fullSlots); data = cache[readPos]; //readPos ++; /* struct data dat = cache[readPos++]; itemsBuffered--; // würde der buffer mit folgendem Szenario: itemsBuffered = Buffer_SIZE => V(waiter) , dann Get, Get, dann Put und dann läuft der Buffer wieder in itemsBuffered = Buffer_SIZE => V(waiter) => V ist jetzt (2) => synch in Get nichtmehr gewährleistet, oder irre ich mich da? //das stimmt, aber in itemsBuffered sollte ja die zahl der Elemente im cache stehen oder nicht? //naja gut, wenn man davon ausgeht, dass man die zahl nie mehr braucht, kann mans auch weglassen. //ansonsten ist mir das problem schon aufgefallen. Man müsste dann noch in der put funktion prüfen, ob das bereits einmal aktiviert wurde. //Das gleiche Problem kriegt man aber auch simpler: 2 mal Flushen.... wobei das hier nicht unser problem wäre. //evtl sollte man dann generell überall wo man V(waiter) macht schauen, ob das schonmal getan wurde. Dann fixt man es für alles gleichzeitig data = &dat;https://wwwcip.cs.fau.de/~ak53efan/sp/ if(readPos >= CACHE_SIZE) readPos = 0; */ V(freeSlots); V(waiter); } // Funktion jbFlush void jbFlush(void){ V(waiter); }