Programmering C: Lösningar till tentamen 2012-02-25

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.

Uppgift 1 (1 p)

a) 7

b) -4

c) 1

d) 0

Kommentar: På uppgift d är false fel svar, men ger inget poängavdrag.

Uppgift 2 (1 p)

a = 1, b = 3, c = 3, y = 7.0

Uppgift 3 (3 p)

#include <stdio.h>

int main(void) {
    int tal1, tal2;

    printf("Skriv två heltal:\n");
    scanf("%d", &tal1);
    scanf("%d", &tal2);

    if (tal1 == 17 && tal2 == 17)
        printf("Sjutton!\n");
    else
        printf("%d %d\n", tal2, tal1);
    
    return 0;
}

Uppgift 4 (2 p)

int samma_inmatade_tal(int medskickade_talet) {
    int inmatade_talet;
    printf("Ange ett tal: ");
    scanf("%d", &inmatade_talet);
    return inmatade_talet == medskickade_talet;
}

Uppgift 5 (1 p)

int main(void) {
    if (samma_inmatade_tal(42))
        printf("Ja\n");
    else
        printf("Nej\n");
    return 0;
}

Uppgift 6 (6 p)

#include <stdio.h>

int main(void) {
    int raden[7];
    int tillaten = 1;

    printf("Ange en lottorad: ");
    for (int i = 0; i < 7; ++i)
        scanf("%d", &raden[i]);

    // Kolla att alla tal är mellan 1 och 35
    for (int i = 0; i < 7; ++i)
        if (raden[i] < 1 || raden[i] > 35)
            tillaten = 0;

    // Kolla att talen står i nummerordning
    for (int i = 0; i < 6; ++i)
        if (raden[i] >= raden[i + 1])
            tillaten = 0;

    // Kolla att det inte finns några dubbletter
    for (int ena = 0; ena < 6; ++ena)
        for (int andra = ena + 1; andra < 7; ++andra)
            if (raden[ena] == raden[andra])
                tillaten = 0;

    if (tillaten)
        printf("Tillåten.\n");
    else
        printf("Inte tillåten.\n");

    return 0;
}

Kommentar: Kontrollen av att det inte finns några dubbletter är onödig, och kan tas bort ur lösningen. (Övning: Varför?)

Uppgift 7 (1 p)

struct Pixel {
    double red, green, blue;
};

Uppgift 8 (1 p)

struct Pixel p = { 0.5, 0, 0 };

Uppgift 9 (2 p)

int equal_colours(struct Pixel pixel1, struct Pixel pixel2) {
    return pixel1.red == pixel2.red && pixel1.green == pixel2.green && pixel1.blue == pixel2.blue;
}

Uppgift 10 (1 p)

#define CANVAS_HEIGHT 1000
#define CANVAS_WIDTH 1000

struct Canvas {
    struct Pixel matrix[CANVAS_WIDTH][CANVAS_HEIGHT];
};

Uppgift 11 (3 p)

void solid(struct Canvas *canvasp, struct Pixel colour) {
    for (int x = 0; x < CANVAS_WIDTH; ++x)
        for (int y = 0; y < CANVAS_HEIGHT; ++y)
            canvasp->matrix[x][y] = colour;
}

Uppgift 12 (3 p)

void border(struct Canvas *canvasp, struct Pixel colour) {
    for (int x = 0; x < CANVAS_WIDTH; ++x) {
        canvasp->matrix[x][0] = colour;
        canvasp->matrix[x][CANVAS_HEIGHT - 1] = colour;
    }
    for (int y = 0; y < CANVAS_HEIGHT; ++y) {
        canvasp->matrix[0][y] = colour;
        canvasp->matrix[CANVAS_WIDTH - 1][y] = colour;
    }
}

Uppgift 13 (3 p)

int equal_canvases(struct Canvas *canvasp1, struct Canvas *canvasp2) {
    for (int x = 0; x < CANVAS_WIDTH; ++x) 
        for (int y = 0; y < CANVAS_HEIGHT; ++y)
            if (!equal_colours(canvasp1->matrix[x][y], canvasp2->matrix[x][y]))
                return 0;
    return 1;
}
Kommentar: En Canvas-post innehåller en miljon bildpunkter, som var och en innehåller tre flyttal, så den tar ganska stor plats i minnet. Så stora datastrukturer vill man gärna undvika att kopiera, vilket sker vid vanliga "call-by-value"-funktionsanrop i C. Bland annat därför har vi här valt att skicka pekare till posterna, och inte hela posterna.

Uppgift 14 (2 p)

int main(void) {
    struct Canvas canvas1, canvas2;
    struct Pixel red = { 1, 0, 0 }, piano = { 0, 1, 0 };
    solid(&canvas1, red);
    border(&canvas1, piano);
    solid(&canvas2, red);
    border(&canvas2, piano);
    if (!equal_canvases(&canvas1, &canvas2))
        printf("Fel! Olika!\n");

    return 0;
}
Kommentar: En Canvas-post tar som sagt ganska stor plats i minnet. På många system är storleken den så kallade stacken, där lokala variabler placeras, begränsad, och därför kanske den här main-funktionen inte fungerar. Då kan man flytta ut Canvas-variablerna ur funktionen.

Uppgift 15 (10 p)

a)
void save_canvas(char* file_name, struct Canvas *canvasp) {
    FILE* f = fopen(file_name, "wb");
    if (f == NULL) {
        fprintf(stderr, "Filen '%s' gick inte att öppna.\n", file_name);
        exit(EXIT_FAILURE);
    }
    fwrite(canvasp, sizeof(struct Canvas), 1, f);
    fclose(f);
}
Kommentar: Här har vi valt att spara på en binärfil. En textfil går också bra, men blir lite längre kod.

b)

void read_canvas(char* file_name, struct Canvas *canvasp) {
    FILE* f = fopen(file_name, "rb");
    if (f == NULL) {
        fprintf(stderr, "Filen '%s' gick inte att öppna.\n", file_name);
        exit(EXIT_FAILURE);
    }
    fread(canvasp, sizeof(struct Canvas), 1, f);
    fclose(f);
}
c)
int main(void) {
    struct Pixel red = { 1, 0, 0 }, piano = { 0, 1, 0 };
    solid(&canvas1, red);
    border(&canvas1, piano);
    save_canvas("canvas.bin", &canvas1);
    solid(&canvas2, piano);
    border(&canvas2, red);
    read_canvas("canvas.bin", &canvas2);
    if (!equal_canvases(&canvas1, &canvas2))
        printf("Fel! Olika!\n");

    return 0;
}


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 28 februari 2012