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!


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);
 
}