Programmering C: Lösningar till tentamen 2011-01-14

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) 14

b) 11

c) 3

Uppgift 2 (1 p)

a = 4, b = 3, c = 3, d = 4

Uppgift 3 (3 p)

#include <stdio.h>

int main(void) {
    int a, b, c;

    printf("a: ");
    scanf("%d", &a);
    printf("b: ");
    scanf("%d", &b);
    printf("c: ");
    scanf("%d", &c);

    for (int i = a; i <= b; ++i) {
        if (i != c)
            printf("%d\n", i);
    }

    return 0;
}

Uppgift 4 (2 p)

int korrekt_ordning(double x, double y, double z) {
    return x < y && y < z;
}

Uppgift 5 (2 p)

int main(void) {
    double a, b, c;

    printf("a: ");
    scanf("%lf", &a);
    printf("b: ");
    scanf("%lf", &b);
    printf("c: ");
    scanf("%lf", &c);

    if (korrekt_ordning(a, b, c))
        printf("I storleksordning.\n");
    else
        printf("Inte i storleksordning.\n");

    return 0;
}

Uppgift 6 (2 p)

#define MAX_ADRESS_LANGD 60

struct Postpropp {
    double volym; // Volym mätt i kubikdecimeter
    int antal; // Antalet reklamförsändelser i postproppen
    char adress[MAX_ADRESS_LANGD + 1]; // Adressen till brevlådan
};

Uppgift 7 (1 p)

struct Postpropp p = { 14.7, 198, "Granvägen 6A, 702 21 Örebro" };

Uppgift 8 (2 p)

void visa_postpropp(struct Postpropp pp) {
    printf("Volym: %.2f kubikdecimeter\n", pp.volym);
    printf("Antal reklamförsändelser: %d\n", pp.antal);
    printf("Adress: %s\n", pp.adress);
}

Uppgift 9 (3 p)

void las_postpropp(struct Postpropp *ppp) {
    printf("Ange postproppns volym: ");
    scanf("%lf", &ppp->volym);
    printf("Ange antalet reklamförsändelser: ");
    scanf("%d", &ppp->antal);
    // Nu finns ett radslutstecken kvar i inmatningsbufferten.
    // Vi måste läsa förbi det, annars tolkar fgets det som en rad att läsa in.
    while (getchar() != '\n')
        ;
    printf("Ange adressen till brevlådan: ");
    fgets(ppp->adress, sizeof(ppp->adress), stdin);
    // fgets sparar radslutstecknet i variabeln, så nu tar vi bort det.
    int n = strlen(ppp->adress);
    if (ppp->adress[n - 1] == '\n')
        ppp->adress[n - 1] = '\0';
}
Kommentar: Ja, det är lite lurt det där med att fgets tar med radslutstecknet, samtidigt som det inte finns någon extra plats i adressfältet för något radslutstecken. Blir den längsta adress som kan läsas in bara 59 tecken, och inte 60? Övning: Prova själv vad som händer, och föreslå eventuella förbättringar.

Uppgift 10 (1 p)

int mindre_postpropp(struct Postpropp pp1, struct Postpropp pp2) {
    return pp1.volym < pp2.volym;
}

Uppgift 11 (2 p)

int main(void) {
    struct Postpropp pp1, pp2;

    printf("Mata in två postproppar:\n");
    las_postpropp(&pp1);
    las_postpropp(&pp2);

    printf("\n");
    printf("Den största postproppen:\n");
    if (mindre_postpropp(pp1, pp2))
        visa_postpropp(pp2);
    else
        visa_postpropp(pp1);

    return 0;
}

Uppgift 12 (3 p)

struct Postpropp biggest_propp(struct Postpropp proppar[], int antal_proppar) {
    struct Postpropp biggest_so_far = proppar[0];
    for (int i = 1; i < antal_proppar; ++i) {
        if (mindre_postpropp(biggest_so_far, proppar[i]))
            biggest_so_far = proppar[i];
    }
    return biggest_so_far;
}

Uppgift 13 (5 p)

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

#define MAX_ADRESS_LANGD 60
#define MAX_ANTAL_POSTPROPPAR 2000

/* Definitioner av funktioner mm enligt tidgare... */

struct Postpropp alla_proppar[MAX_ANTAL_POSTPROPPAR];
int antal_postproppar = 0;

int main(void) {
    struct Postpropp pp;

    printf("Mata in postproppar. Avsluta med en postpropp med volymen 0.\n");
    las_postpropp(&pp);
    while (pp.volym != 0) {
        alla_proppar[antal_postproppar++] = pp;
        las_postpropp(&pp);
    }        

    struct Postpropp bossen = biggest_propp(alla_proppar, antal_postproppar);

    printf("\n");
    printf("Största proppen:\n");
    visa_postpropp(bossen);

    return 0;
}

Uppgift 14 (4 p)

Här väljer vi en binärfil, eftersom det blir minst och enklast kod. En textfil går också bra, men blir lite krångligare.

a)

void spara_proppar(struct Postpropp proppar[], int antal_proppar, char* filnamn) {
    FILE* f = fopen(filnamn, "w");
    for (int i = 1; i < antal_proppar; ++i) {
        fwrite(&proppar[i], sizeof(proppar[0]), 1, f);
    }
    fclose(f);
}
En annan, ännu enklare, lösning:
void spara_proppar(struct Postpropp proppar[], int antal_proppar, char* filnamn) {
    FILE* f = fopen(filnamn, "w");
    fwrite(proppar, sizeof(proppar[0]), antal_proppar, f);
    fclose(f);
}
Kommentar: I ett riktigt program bör man kontrollera att filen faktiskt gick att öppna, men det stod ju i tentan att det inte behövdes någon felhantering.

b)

Stoppa in i slutet av main, före return:

    spara_proppar(alla_proppar, antal_postproppar, "postproppar.bin");

Uppgift 15 (5 p)

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

#define MAX_ADRESS_LANGD 60

struct Postpropp {
    double volym; // Volym mätt i kubikdecimeter
    int antal; // Antalet reklamförsändelser i postproppen
    char adress[MAX_ADRESS_LANGD + 1]; // Adressen till brevlådan
};

int main(void) {
    double volymgrans;
    printf("Ange volymgränsen: ");
    scanf("%lf", &volymgrans);

    FILE* bsin = fopen("postproppar.bin", "r");
    FILE* bsut = fopen("kvalitetsproppar.bin", "w");

    struct Postpropp pp;
    while (fread(&pp, sizeof pp, 1, bsin) == 1) {
        if (pp.volym > volymgrans)
            fwrite(&pp, sizeof pp, 1, bsut);
    }

    fclose(bsin);
    fclose(bsut);

    return 0;
}
Kommentar: I ett riktigt program bör man kontrollera att filerna gick att öppna, och att det går att skriva på utfilen (till exempel kan disken bli full) men det stod ju i tentan att det inte behövdes någon felhantering.


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 2 februari 2011