Programmering C: Lösningar till tentamen 2016-06-01

Observera att detta är förslag på lösningar. Det kan finnas andra lösningar som också är korrekta, och det kan hända att en del av lösningarna är mer omfattande än vad som krävs för full poäng på uppgiften. En del av lösningarna är kanske inte fullständiga, utan hänvisar bara till var man kan läsa svaret. Dessutom har det inträffat i världshistorien att lärare skrivit fel i lösningsförslagen.

Uppgift 1 (1 p)

a) 0

b) 6

c) 7

d) 7

Uppgift 2 (3 p)

a) a = 0, b = 0, c = 0

b) a = 5, b = 1, c = 4

c) a = 1000, b = 1, c = 999

Uppgift 3 (2 p)

#include <stdio.h>
#include <math.h>

int main(void) {
    for (int i = 1; i <= 100; ++i) {
        printf("%d %d %f\n", i, i*i, sqrt(i));
    }

    return 0;
}

Uppgift 4 (3 p)

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "pi.h"

int main(void) {
    double x;
    printf("Ange x: \n");
    scanf("%lf", &x);
    double y;
    printf("Ange y: \n");
    scanf("%lf", &y);

    double divisor = 1 - PI * x;
    if (divisor == 0) {
        fprintf(stderr, "Division med noll. Går inte att beräkna.\n");
        exit(EXIT_FAILURE);
    }
    double result = 1 / divisor * (sqrt(PI * x*x) - sqrt(PI * y*y) - 1);
    printf("Resultat: %f\n", result);

    return 0;
}

Uppgift 5 (7 p)

a) (2p)

float maxabs(float x, float y) {
    float absx = fabsf(x);
    float absy = fabsf(y);
    if (absx > absy)
        return x;
    else
        return y;
}
Alternativt, om man vill använda double i stället:
double maxabs(double x, double y) {
    double absx = fabs(x);
    double absy = fabs(y);
    if (absx > absy)
        return x;
    else
        return y;
}
Alternativt, om man inte kommer ihåg funktionen fabs, eller dess float-version fabsf:
float maxabs(float x, float y) {
    float absx;
    if (x >= 0)
        absx = x;
    else
        absx = -x;
    float absy;
    if (y >= 0)
        absy = y;
    else
        absy = -y;
    if (absx > absy)
        return x;
    else
        return y;
}
Och ett lite kompaktare alternativ:
float maxabs(float x, float y) {
    float absx = x < 0 ? -x : x;
    float absy = y < 0 ? -y : y;
    if (absx > absy)
        return x;
    else
        return y;
}
Ännu kompaktare, men inte att rekommendera:
float maxabs(float x, float y) {
    return ((x < 0 ? -x : x) > (y < 0 ? -y : y)) ? x : y;
}

b) (2p)

void maxabs_array(float a[], float b[], float c[], int n) {
    for (int i = 0; i < n; ++i) {
        c[i] = maxabs(a[i], b[i]);
    }
}

c) (3p)

#define MAX_LENGTH 100

int main(void) {
    float a1[MAX_LENGTH], a2[MAX_LENGTH], resultat[MAX_LENGTH];
    int antal;
    printf("Ange arraystorleken: ");
    scanf("%d", &antal);
    if (antal < 0 || antal > MAX_LENGTH) {
        fprintf(stderr, "Otillåten storlek: %d. Ska vara 0..%d.\n",
                antal, MAX_LENGTH);
        exit(EXIT_FAILURE);
    }
    printf("Mata in %d reella tal till ena arrayen:\n", antal);
    for (int i = 0; i < antal; ++i)
        scanf("%f", &a1[i]);
    printf("Mata in %d reella tal till den andra arrayen:\n", antal);
    for (int i = 0; i < antal; ++i)
        scanf("%f", &a2[i]);
    maxabs_array(a1, a2, resultat, antal);
    printf("Resultat:\n");
    for (int i = 0; i < antal; ++i)
        printf("    %f\n", resultat[i]);
}
I nyare C-dialekter kan man göra så här:
#define MAX_LENGTH 100

int main(void) {
    int antal;
    printf("Ange arraystorleken: ");
    scanf("%d", &antal);
    if (antal < 0 || antal > MAX_LENGTH) {
        fprintf(stderr, "Otillåten storlek: %d. Ska vara 0..%d.\n",
                antal, MAX_LENGTH);
        exit(EXIT_FAILURE);
    }
    float a1[antal], a2[antal], resultat[antal];
    printf("Mata in %d reella tal till ena arrayen:\n", antal);
    for (int i = 0; i < antal; ++i)
        scanf("%f", &a1[i]);
    printf("Mata in %d reella tal till den andra arrayen:\n", antal);
    for (int i = 0; i < antal; ++i)
        scanf("%f", &a2[i]);
    maxabs_array(a1, a2, resultat, antal);
    printf("Resultat:\n");
    for (int i = 0; i < antal; ++i)
        printf("    %f\n", resultat[i]);
}

Uppgift 6 (11 p)

a) (1p)

#define MAX_TEXT 30

struct Filmklipp {
    char text[MAX_TEXT + 1]; // + 1 för '\0'
    int minuter;
    double sekunder;
};
typedef struct Filmklipp Filmklipp;

b) (1p)

Filmklipp thomas_pratar = { "Thomas pratar", 2, 16.4 };

c) (1p)

void visa_filmklipp(Filmklipp k) {
    printf("Text: %s\n", k.text);
    printf("Tid: %d min %.1f s\n", k.minuter, k.sekunder);
}

d) (3p)

Filmklipp las_filmklipp(void) {
    Filmklipp k;
    char text[MAX_TEXT + 1 + 1]; // + 1 för '\0' och + 1 för '\n'
    printf("Beskriv filmklippets innehåll: ");
    fgets(text, sizeof text, stdin);
    if (text[strlen(text) - 1] == '\n')
        text[strlen(text) - 1] = '\0';
    strcpy(k.text, text);
    printf("Ange antal hela minuter: ");
    scanf("%d", &k.minuter);
    printf("Ange antal sekunder: ");
    scanf("%lf", &k.sekunder);
    // Kasta resten av raden, inför nästa fgets
    while (getchar() != '\n')
        ;
    return k;
}

e) (3p)

Filmklipp klipp_ihop(Filmklipp klipp1, Filmklipp klipp2) {
    Filmklipp resultat;
    strcpy(resultat.text, "Hopklippt film");
    resultat.minuter = klipp1.minuter + klipp2.minuter;
    resultat.sekunder = klipp1.sekunder + klipp2.sekunder;
    while (resultat.sekunder >= 60) {
        resultat.sekunder -= 60;
        resultat.minuter += 1;
    }
    return resultat;
}

f) (2p)

int main(void) {
    printf("Mata in data om två filmklipp!\n");
    Filmklipp ena_filmklippet = las_filmklipp();
    Filmklipp andra_filmklippet = las_filmklipp();
    printf("Tack!\n");
    visa_filmklipp(klipp_ihop(ena_filmklippet, andra_filmklippet));

    return 0;
}

Uppgift 7 (8 p)

a)

// Postdefinition med mera enligt uppgift 6

int main(void) {
    FILE *tsut = fopen("filmklipp.txt", "w");
    if (tsut == NULL) {
        printf("Kunde inte skriva filen 'filmklipp.txt'.\n");
        exit(EXIT_FAILURE);
    }
    printf("Mata in filmklipp. Avsluta med ett klipp med längden 0.\n");
    Filmklipp klipp;
    klipp = las_filmklipp();
    while (klipp.minuter != 0 || klipp.sekunder != 0) {
        fprintf(tsut, "%s\n%d\n%f\n", klipp.text, klipp.minuter, klipp.sekunder);
        klipp = las_filmklipp();
    }
    fclose(tsut);

    return 0;
}

b)

// Postdefinition med mera enligt uppgift 6

int las_filmklipp_fran_fil(FILE *tsin, struct Filmklipp *klipp_p) {
    char text[MAX_TEXT + 1 + 1]; // + 1 för '\0' och + 1 för '\n'
    if (fgets(text, sizeof text, tsin) == NULL)
        return 0;
    if (text[strlen(text) - 1] == '\n')
        text[strlen(text) - 1] = '\0';
    strcpy(klipp_p->text, text);
    fscanf(tsin, "%d", &klipp_p->minuter);
    fscanf(tsin, "%lf", &klipp_p->sekunder);
    // Kasta resten av raden, inför nästa fgets
    while (getc(tsin) != '\n')
        ;
    return 1;
}

int main(void) {
    FILE *tsin = fopen("filmklipp.txt", "r");
    if (tsin == NULL) {
        printf("Kunde inte läsa filen 'filmklipp.txt'.\n");
        exit(EXIT_FAILURE);
    }
    Filmklipp ett_klipp, hopklippt_film = { "", 0, 0 };
    while (las_filmklipp_fran_fil(tsin, &ett_klipp)) {
        hopklippt_film = klipp_ihop(hopklippt_film, ett_klipp);
    }
    fclose(tsin);
    visa_filmklipp(hopklippt_film);

    return 0;
}

Uppgift 8 (5 p)

#include <stdio.h>

int main(void) {
    int antal_man = 0;
    int antal_kvinnor = 0;

    printf("Ange personnummer (ett per rad, avsluta med tom rad):\n");
    char personnummerrad[11 + 1 + 1]; // '\n' och '\0'
    fgets(personnummerrad, sizeof personnummerrad, stdin);
    while (personnummerrad[0] != '\n') {
        int nast_sista_siffran = personnummerrad[9] - '0';
        if (nast_sista_siffran % 2 == 0)
            ++antal_kvinnor;
        else
            ++antal_man;
        fgets(personnummerrad, sizeof personnummerrad, stdin);
    }

    printf("Antal kvinnor: %d\n", antal_kvinnor);
    printf("Antal män: %d\n", antal_man);

    return 0;
}


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 7 juni 2016