Programmering C: Lösningar till tentamen 2012-01-13

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

b) 11

c) 0

d) 1

Kommentar: På uppgift c och d är false och true fel svar, men ger inga poängavdrag.

Uppgift 2 (1 p)

a = 2, b = 2, x = 4.8, y = 4.4

Men provkör nu programmet och se vad resultatet blir! Det är ganska troligt att resultatet i stället blir detta:
a = 2, b = 2, x = 4.2, y = 4.3
Övning: Varför?

Uppgift 3 (3 p)

#include <stdio.h>

int main(void) {
    double x, y;

    printf("Skriv två flyttal:\n");
    scanf("%lf", &x);
    scanf("%lf", &y);

    if (x == y)
        printf("Lika\n");
    else if (x < y)
        printf("%f %f\n", x, y);
    else /* if (x > y) */
        printf("%f %f\n", y, x);
    
    return 0;
}

Uppgift 4 (1 p)

int korrekt_summa(int a, int b, int c) {
    return a + b == c;
}

Uppgift 5 (3 p)

int main(void) {
    srand(time(NULL)); // Ger pseudoslumptalsgeneratorn ett startvärde
    int ena_talet = rand() % 1000; // Ger ett slumptal 0-999
    int andra_talet = rand() % 1000; // Ger ett slumptal 0-999
    printf("Vad blir %d + %d? ", ena_talet, andra_talet);
    int summan;
    scanf("%d", &summan);
    if (korrekt_summa(ena_talet, andra_talet, summan))
        printf("Rätt\n");
    else
        printf("Fel\n");
    return 0;
}

Uppgift 6 (1 p)

#define MAX_NAMNLANGD 80

struct App {
    char namn[MAX_NAMNLANGD + 1];
    double pris;
    int antal;
};

Uppgift 7 (1 p)

struct App sr = { "Satellite Rush", 0, 500 };

Uppgift 8 (2 p)

void visa_app(struct App a) {
    printf("Namn: %s\n", a.namn);
    printf("Pris: %.2f\n", a.pris);
    printf("Antal nerladdningar: %d\n", a.antal);
}

Uppgift 9 (3 p)

void las_app(struct App *ap) {
    printf("Ange appens namn: ");
    fgets(ap->namn, sizeof(ap->namn), stdin);
    // fgets sparar radslutstecknet i variabeln, så nu tar vi bort det.
    int n = strlen(ap->namn);
    if (ap->namn[n - 1] == '\n')
        ap->namn[n - 1] = '\0';
    printf("Ange pris: ");
    scanf("%lf", &ap->pris);
    printf("Ange antalet nerladdningar: ");
    scanf("%d", &ap->antal);
    // 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')
        ;
}

Uppgift 10 (2 p)

void appswap(struct App *ap1, struct App *ap2) {
    struct App temp = *ap1;
    *ap1 = *ap2;
    *ap2 = temp;
}

Uppgift 11 (2 p)

int main(void) {
    struct App app1, app2;

    printf("Mata in två appar:\n");
    las_app(&app1);
    las_app(&app2);

    appswap(&app1, &app2);

    printf("Den dyraste appen:\n");
    if (app1.pris > app2.pris)
        visa_app(app1);
    else
        visa_app(app2);

    return 0;
}

Uppgift 12 (5 p)

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

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

int main(void) {
    FILE* f = fopen("appar.txt", "w");
    if (f == NULL) {
        fprintf(stderr, "Filen 'appar.txt' gick inte att öppna.\n");
        exit(EXIT_FAILURE);
    }
    struct App app;
    las_app(&app);
    while (strcmp(app.namn, "END OF APPS") != 0) {
        fprintf(f, "%s\n", app.namn);
        fprintf(f, "%.2f\n", app.pris);
        fprintf(f, "%d\n", app.antal);
        las_app(&app);
    }
    fclose(f);

    return EXIT_SUCCESS;
}

Uppgift 13 (6 p)

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

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

int las_app_fran_fil(FILE* f, struct App* appp) {
    char* fgets_status = fgets(appp->namn, sizeof(appp->namn), f);
    if (fgets_status == NULL)
        return 0;
    // fgets sparar radslutstecknet i variabeln, så nu tar vi bort det.
    int n = strlen(appp->namn);
    if (appp->namn[n - 1] == '\n')
        appp->namn[n - 1] = '\0';
    fscanf(f, "%lf", &appp->pris);
    fscanf(f, "%d", &appp->antal);
    // 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 (getc(f) != '\n')
        ;
    return 1;
}

int main(void) {
    FILE* f = fopen("appar.txt", "r");
    if (f == NULL) {
        fprintf(stderr, "Filen 'appar.txt' gick inte att öppna.\n");
        exit(EXIT_FAILURE);
    }
    struct App app;
    double summan = 0;
    while (las_app_fran_fil(f, &app) != 0) {
        summan += app.pris * app.antal;
    }
    fclose(f);
    printf("Summan: %.2f\n", summan);

    return EXIT_SUCCESS;
}

Uppgift 14 (4 p)

#include <stdio.h>

int main(void) {
    double maxvikt;
    int antal_set;

    printf("Ange maxvikten: ");
    scanf("%lf", &maxvikt);

    printf("Ange antalet set: ");
    scanf("%d", &antal_set);

    for (int set = 0; set < antal_set; ++set) {
        int reps = antal_set - set;
        double vikt = maxvikt * (set + 1) / antal_set;
        int avrundad_vikt = (int)(vikt + 0.5);
        printf("%d kg x %d", avrundad_vikt, reps);
        if (set != antal_set - 1)
            putchar(',');
        putchar(' ');
    }
    putchar('\n');

    return 0;
}

Uppgift 15 (5 p)

En lösning som lagrar alla de inlästa talen i en array:
#include <stdio.h>

#define MAX_ANTAL_TAL 100

int main(void) {
    int talen[MAX_ANTAL_TAL];
    int antal_tal;
    int talet;

    printf("Mata in naturliga tal. Avsluta med ett negativt tal.\n");

    antal_tal = 0;
    scanf("%d", &talet);
    while (talet >= 0) {
        talen[antal_tal++] = talet;
        scanf("%d", &talet);
    }

    int max_talet = -1;
    int max_antalet = 0;
    for (int i = 0; i < antal_tal; ++i) {
        int antal_av_detta_tal = 1;
        for (int j = i + 1; j < antal_tal; ++j) {
            if (talen[j] == talen[i])
                ++antal_av_detta_tal;
        }
        if (antal_av_detta_tal > max_antalet) {
            max_talet = talen[i];
            max_antalet = antal_av_detta_tal;
        }
    }
    printf("Vanligaste talet: %d\n", max_talet);

    return 0;
}
En bättre lösning, som använder en tabell med unika tal, och hur många gånger varje tal förekommit:
#include <stdio.h>

#define MAX_ANTAL_TAL 100

struct Tabellrad {
    int tal;
    int antal;
};

int hitta_tabellrad(struct Tabellrad tabellen[], int antal_tabellrader, int sokt_tal) {
    for (int i = 0; i < antal_tabellrader; ++i) {
        if (tabellen[i].tal == sokt_tal)
            return i;
    }
    return -1;
}

int main(void) {
    struct Tabellrad tabellen[MAX_ANTAL_TAL];
    int antal_tabellrader;
    int talet;

    printf("Mata in naturliga tal. Avsluta med ett negativt tal.\n");

    antal_tabellrader = 0;
    scanf("%d", &talet);
    while (talet >= 0) {
        int position = hitta_tabellrad(tabellen, antal_tabellrader, talet);
        if (position == -1) {
            position = antal_tabellrader;
            tabellen[position].tal = talet;
            tabellen[position].antal = 1;
            antal_tabellrader++;
        }
        else {
            tabellen[position].antal++;
        }
        scanf("%d", &talet);
    }

    int max_talet = -1;
    int max_antalet = 0;
    for (int i = 0; i < antal_tabellrader; ++i) {
        if (tabellen[i].antal > max_antalet) {
            max_talet = tabellen[i].tal;
            max_antalet = tabellen[i].antal;
        }
    }
    printf("Vanligaste talet: %d\n", max_talet);

    return 0;
}


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