Programmering C: Lösningar till tentamen 2013-06-05

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. En del av lösningarna kanske använder en modernare C-dialekt än vad Visual Studio klarar av.

Uppgift 1 (1 p)

a) 13

b) 11

c) 2

Uppgift 2 (1 p)

x = 5*y*z / 5 + sqrt(2*y*y) - 5;

Uppgift 3 (3 p)

x = 3, x + 0 = 3
*x = 3, x + 1 = 4
**x = 3, x + 2 = 5

Uppgift 4 (4 p)

Ett alternativ:
#include <stdio.h>

int main(void) {
    double tal, summa = 0, min, max;
    int tal_lasta = 0;
    scanf("%lf", &tal);
    while (tal != 0) {
        if (!tal_lasta || tal < min)
            min = tal;
        if (!tal_lasta || tal > max)
            max = tal;
        tal_lasta = 1;
        summa += tal;
        scanf("%lf", &tal);
    }
    printf("Summan: %f, minsta: %f, största: %f\n", summa, min, max);
    return 0;
}
Ett annat alternativ:
#include <stdio.h>

int main(void) {
    double tal, summa = 0, min, max;
    int tal_lasta = 0;
    scanf("%lf", &tal);
    while (tal != 0) {
        if (!tal_lasta || tal < min)
            min = tal;
        if (!tal_lasta || tal > max)
            max = tal;
        tal_lasta = 1;
        summa += tal;
        scanf("%lf", &tal);
    }
    printf("Summan: %f, minsta: %f, största: %f\n", summa, min, max);
    return 0;
}
Ännu ett alternativ:
#include <stdio.h>

int main(void) {
    double tal, summa = 0, min, max;
    scanf("%lf", &tal);
    min = max = tal;
    while (tal != 0) {
        if (tal < min)
            min = tal;
        if (tal > max)
            max = tal;
        summa += tal;
        scanf("%lf", &tal);
    }
    printf("Summan: %f, minsta: %f, största: %f\n", summa, min, max);
    return 0;
}
Ännu ett alternativ:
#include <stdio.h>
#include <float.h>

int main(void) {
    float tal, summa = 0, min = DBL_MAX, max = DBL_MIN;
    scanf("%f", &tal);
    while (tal != 0) {
        if (tal < min)
            min = tal;
        if (tal > max)
            max = tal;
        summa += tal;
        scanf("%f", &tal);
    }
    printf("Summan: %f, minsta: %f, största: %f\n", summa, min, max);
    return 0;
}
Bägge dessa lösningar förutsätter att användaren matat in minst ett tal. Annars blir utskrifterna av minsta och största talen konstiga och meningslösa.

Uppgift 5 (2 p)

a)
#define MAX_STRANGLANGD 20

struct Djur {
    char namn[MAX_STRANGLANGD + 1];
    char art[MAX_STRANGLANGD + 1];
    double vikt;
};
b)
struct Djur djuret = { "Richard Parker", "bengalisk tiger", 221.2 };

Uppgift 6 (3 p)

double total_vikt(struct Djur djuren[], int antal_djur) {
    double summa = 0;
    for (int i = 0; i < antal_djur; ++i) {
        if (djuren[i].vikt >= 0)
            summa += djuren[i].vikt;
    }
    return summa;
}

Uppgift 7 (3 p)

int main(void) {
    struct Djur fem_djur[] = {
        { "Kalle", "anka", 0.25 }, // En liten vikt
        { "Anti-Knatte", "anka", -0.167 }, // En negativ vikt som inte ska räknas med
        { "Noll-Fnatte", "anka", 0 }, // Vikten noll ska inte ge något konstigt
        { "Tjock-Tjatte", "anka", 100.25 }, // En stor vikt, med decimaler
        { "Gorillan Går Illa", "bergsgorilla", 100 }, // En stor vikt till, utan decimaler
    };
    double viktsumman = total_vikt(fem_djur, 5);
    if (viktsumman != 200.5)
        printf("Fel! Viktsumman blev %f, borde blivit 200.5.\n", viktsumman);

    return 0;
}

Kommentarer: Vi har varierade data i våra testdata: små och stora vikter, vikter med och utan decimaler, vikten noll, en negativ vikt som inte ska räknas med. Resultatet är inte ett heltal, för att kontrollera att decimalerna inte försvinner. Även om man ska se upp med likhetsjämförelser av flyttal, fungerar det normalt bra med jämna negativa tvåpotenser, till exempel halva och fjärdedelar.

Uppgift 8 (2 p)

void visa_djur(struct Djur d) {
    printf("Namn: %s\n", d.namn);
    printf("Art: %s\n", d.art);
    printf("Vikt: %.2f\n", d.vikt);
}

Uppgift 9 (3 p)

void las_djur(struct Djur *dp) {
    char rad[MAX_STRANGLANGD + 1 + 1]; // + 1 för '\n', + 1 för '\0'
    printf("Ange djurets namn: ");
    fgets(rad, sizeof rad, stdin);
    // fgets sparar radslutstecknet i variabeln, så nu tar vi bort det.
    int n = strlen(rad);
    if (rad[n - 1] == '\n')
        rad[n - 1] = '\0';
    strcpy(dp->namn, rad);
    printf("Ange arten: ");
    fgets(rad, sizeof rad, stdin);
    // fgets sparar radslutstecknet i variabeln, så nu tar vi bort det.
    n = strlen(rad);
    if (rad[n - 1] == '\n')
        rad[n - 1] = '\0';
    strcpy(dp->art, rad);
    printf("Ange vikten: ");
    scanf("%lf", &dp->vikt);
    // Nu finns ett radslutstecken kvar i inmatningsbufferten.
    // Vi måste läsa förbi det, annars tolkar nästa fgets det som en rad att läsa in.
    while (getchar() != '\n')
        ;
}
Kommentarer: Lösningen blir mycket kortare och enklare om man använder gets i stället för fgets. På riktigt ska man aldrig använda gets (övning: varför?) men jag drar inga poäng för det i den här upppgiften.

Uppgift 10 (3 p)

    struct Djur djur1, djur2, djur3, tre_djur[3];

    printf("Mata in tre djur!\n");
    las_djur(&djur1);
    las_djur(&djur2);
    las_djur(&djur3);
    tre_djur[0] = djur1;
    tre_djur[1] = djur2;
    tre_djur[2] = djur3;
    printf("Sammanlagd vikt: %f\n", total_vikt(tre_djur, 3));

    return 0;
}

Uppgift 11 (4 p)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// Definitioner av MAX_STRANGLANGD, struct Djur och las_djur

int main(void) {
    struct Djur djur;
    FILE* f = fopen("djur.bin", "wb");
    if (f == NULL) {
        fprintf(stderr, "Filen 'djur.bin' gick inte att öppna för skrivning.\n");
        exit(EXIT_FAILURE);
    }
    printf("Mata in djur. Avsluta med ett djur med vikten noll.\n");
    las_djur(&djur);
    while (djur.vikt != 0) {
        fwrite(&djur, sizeof djur, 1, f);
        las_djur(&djur);
    }
    fclose(f);
    return EXIT_SUCCESS;
}
Inmatningen avslutas genom att användaren matar in ett djur med vikten noll. Filen är en binärfil.

Uppgift 12 (5 p)

#include <stdlib.h>
#include <stdio.h>

// Definitioner av MAX_STRANGLANGD och struct Djur

int main(void) {
    struct Djur detta_djur, tyngsta_djuret_hittills;
    FILE* f = fopen("djur.bin", "rb");
    if (f == NULL) {
        fprintf(stderr, "Filen 'djur.bin' gick inte att öppna för läsning.\n");
        exit(EXIT_FAILURE);
    }
    tyngsta_djuret_hittills.vikt = 0;
    while (fread(&detta_djur, sizeof detta_djur, 1, f) == 1) {
        if (detta_djur.vikt > tyngsta_djuret_hittills.vikt)
            tyngsta_djuret_hittills = detta_djur;
    }
    fclose(f);
    printf("Tyngsta djurets art: %s\n", tyngsta_djuret_hittills.art);
    return EXIT_SUCCESS;
}
Lösningen förutsätter att det finns minst ett djur med känd vikt på filen. Annars blir utskrifterna konstiga och meningslösa.

Uppgift 13 (6 p)

#include <stdio.h>

int main(void) {
    int antal, hojd, bredd;

    printf("Hur många trappsteg? ");
    scanf("%d", &antal);
    printf("Hur högt är ett trappsteg? ");
    scanf("%d", &hojd);
    printf("Hur brett är ett trappsteg? ");
    scanf("%d", &bredd);

    for (int trappsteg = 0; trappsteg < antal; ++trappsteg) {
        for (int rad = 0; rad < hojd; ++rad) {
            // Även första trappsteget har en bredd, så vi använder trappsteg + 1
            for (int kolumn = 0; kolumn < bredd * (trappsteg + 1); ++kolumn) {
                printf("*");
            }
            printf("\n");
        }
    }

    return 0;
}


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 13 juni 2013