Programmering C: Lösningar till tentamen 2016-03-17

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

b) 1

c) 1

d) 0

Uppgift 2 (2 p)

Hej!
a = 1000000
d = odefinierat värde

Kommentarer:

Uppgift 3 (4 p)

Alternativ 1, med en while-loop:
#include <stdio.h>
#include <math.h>

int main(void) {
    double x = 0.0;
    while (x <= 10.0) {
        double radicand1 = x - 1;
        if (radicand1 >= 0) {
            double divisor = sqrt(radicand1);
            if (divisor != 0) {
                double radicand2 = 3 - x*x;
                if (radicand2 >= 0) {
                    double result = 1 / sqrt(radicand1) *
                        pow(sqrt(radicand2) - sqrt(radicand1), 3);
                    printf("%.1f blir %f\n", x, result);
                }
            }
        }
        x += 0.1;
    }

    return 0;
}

Alternativ 2, med en for-loop:

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

int main(void) {
    for (double x = 0.0; x <= 10.0; x += 0.1) {
        double radicand1 = x - 1;
        if (radicand1 >= 0) {
            double divisor = sqrt(radicand1);
            if (divisor != 0) {
                double radicand2 = 3 - x*x;
                if (radicand2 >= 0) {
                    double result = 1 / sqrt(radicand1) *
                        pow(sqrt(radicand2) - sqrt(radicand1), 3);
                    printf("%.1f blir %f\n", x, result);
                }
            }
        }
    }

    return 0;
}

Kommentarer:
I båda förslagen räknar vi med flyttal, som inte alltid ger exakta värden. Till exempel kan vi tänka oss att loopen kommer till ett x som borde bli exakt 10.0, men i stället lagras som 10.000000000000003552713678800500929355621337890625. I så fall kommer det sista varvet i loopen inte att köras. Det bryr vi oss inte om i den här uppgiften. Ska man vara noga borde man räkna ut antalet varv som loopen ska köras, och sedan ha en heltalsvariabel som styrvariabel i loopen. Exempel:

    int antal_varv = 10.0 / 0.1 + 0.5;
    for (int i = 0; i < antal_varv; ++i) {
        double x = i * 0.1;
        // ....
    }

Uppgift 4 (3 p)

#include <stdio.h>

int main(void) {
    printf("Skriv en textrad: ");
    char textraden[100 + 1 + 1]; // '\n' och '\0'
    fgets(textraden, sizeof textraden, stdin);
    printf("Hur många gånger ska den skrivas? ");
    int antalet;
    scanf("%d", &antalet);
    for (int i = 0; i < antalet; ++i)
        fputs(textraden, stdout);
    return 0;
}

Uppgift 5 (1 p)

#define MAX_NAMN 30

struct Stjarna {
    char namn[MAX_NAMN + 1]; // + 1 för '\0'
    double skenbar_magnitud;
    double absolut_magnitud;
};
typedef struct Stjarna Stjarna;

Uppgift 6 (1 p)

Stjarna sirius = { "Sirius", -1.46, 1.42 };

Uppgift 7 (2 p)

void visa_stjarna(Stjarna s) {
    printf("Namn: %s\n", s.namn);
    printf("Skenbar magnitud: %f\n", s.skenbar_magnitud);
    printf("Absolut magnitud: %f\n", s.absolut_magnitud);
}

Uppgift 8 (3 p)

Stjarna las_stjarna(void) {
    Stjarna s;
    char namn[MAX_NAMN + 1 + 1]; // + 1 för '\0' och + 1 för '\n'
    printf("Ange stjärnans namn: ");
    fgets(namn, sizeof namn, stdin);
    if (namn[strlen(namn) - 1] == '\n')
        namn[strlen(namn) - 1] = '\0';
    strcpy(s.namn, namn);
    printf("Ange den skenbara magnituden: ");
    scanf("%lf", &s.skenbar_magnitud);
    printf("Ange den absoluta magnituden: ");
    scanf("%lf", &s.absolut_magnitud);
    while (getchar() != '\n')
        ;
    return s;
}

Uppgift 9 (1 p)

Stjarna ljusast(Stjarna stjarna1, Stjarna stjarna2) {
    if (stjarna1.skenbar_magnitud < stjarna2.skenbar_magnitud)
        return stjarna1;
    else
        return stjarna2;
}

Uppgift 10 (2 p)

int main(void) {
    printf("Mata in data om två stjärnor!\n");
    Stjarna ena_stjarnan = las_stjarna();
    Stjarna andra_stjarnan = las_stjarna();
    printf("Tack! Det här är den ljusaste stjärnan:\n");
    visa_stjarna(ljusast(ena_stjarnan, andra_stjarnan));

    return 0;
}

Uppgift 11 (5 p)

#include <stdio.h>

int main(void) {
    int sokt_manad; // Sökt månad
    printf("Vilken månad (1-12): ");
    scanf("%d", &sokt_manad);
    while (getchar() != '\n')
        ;
    int antal = 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 tiotal = personnummerrad[2] - '0';
        int ental = personnummerrad[3] - '0';
        int denna_manad = tiotal * 10 + ental;
        if (denna_manad == sokt_manad)
            ++antal;
        fgets(personnummerrad, sizeof personnummerrad, stdin);
    }    
    printf("Antal personer födda i månad %d: %d\n",
           sokt_manad, antal);
    return 0;
}

Uppgift 12 (5 p)

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

int main(void) {
    char filnamn[1000];
    printf("Det här programmet skapar en fil med framslumpade heltal.\n");
    printf("Vad ska filen heta? ");
    fgets(filnamn, sizeof filnamn, stdin);
    if (filnamn[strlen(filnamn) - 1] == '\n')
        filnamn[strlen(filnamn) - 1] = '\0';

    int antal_tal;
    printf("Hur många tal ska filen innehålla (högst %d)? ", INT_MAX);
    scanf("%d", &antal_tal);

    int min;
    printf("Minsta tillåtna tal? ");
    scanf("%d", &min);
 
    int max;
    printf("Största tillåtna tal? ");
    scanf("%d", &max);

    printf("Skapar filen och slumpar tal...\n");

    FILE *f = fopen(filnamn, "w");
    if (f == NULL) {
        printf("Kunde inte skriva filen '%s'.\n", filnamn);
        exit(EXIT_FAILURE);
    }
    srand(time(NULL));
    for (int i = 0; i < antal_tal; ++i) {
        // max-min ska vara (mycket) mindre än RAND_MAX
        fprintf(f, "%d\n", min + rand() % (max - min + 1));
    }
    fclose(f);
    printf("Klart!\n");

    return EXIT_SUCCESS;
}

Kommentarer:

Uppgift 13 (5 p)

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

int main(void) {
    char filnamn[1000];
    printf("Vad heter filen? ");
    fgets(filnamn, sizeof filnamn, stdin);
    if (filnamn[strlen(filnamn) - 1] == '\n')
        filnamn[strlen(filnamn) - 1] = '\0';

    FILE *f = fopen(filnamn, "r");
    if (f == NULL) {
        printf("Kunde inte läsa filen '%s'.\n", filnamn);
        exit(EXIT_FAILURE);
    }

    int antal_tal = 0;
    int summa = 0; // Se upp med overflow!
    int detta_tal;
    while (fscanf(f, "%d", &detta_tal) == 1) {
        summa += detta_tal;
        ++antal_tal;
    }
    double medel = summa / antal_tal;
    rewind(f); // Eller en ny fopen
    int antal_avvikande = 0;
    while (fscanf(f, "%d", &detta_tal) == 1) {
        if (detta_tal < medel * 0.90 || detta_tal > medel * 1.10)
            ++antal_avvikande;
    }
    fclose(f);
    printf("Antal avvikande: %d\n", antal_avvikande);

    return EXIT_SUCCESS;
}

Kommentarer:

Uppgift 14 (5 p)

// Vi förutsätter att alla talen är mellan 1 och 1000000

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

// Får kanske inte plats på stacken, så lägg utanför main
int antal_tal[1000001];

int main(void) {
    char infilnamn[1000];
    printf("Vad heter indatafilen? ");
    fgets(infilnamn, sizeof infilnamn, stdin);
    if (infilnamn[strlen(infilnamn) - 1] == '\n')
        infilnamn[strlen(infilnamn) - 1] = '\0';

    char utfilnamn[1000];
    printf("Vad heter utdatafilen? ");
    fgets(utfilnamn, sizeof utfilnamn, stdin);
    if (utfilnamn[strlen(utfilnamn) - 1] == '\n')
        utfilnamn[strlen(utfilnamn) - 1] = '\0';

    FILE *tsin = fopen(infilnamn, "r");
    if (tsin == NULL) {
        printf("Kunde inte läsa filen '%s'.\n", infilnamn);
        exit(EXIT_FAILURE);
    }

    FILE *tsut = fopen(utfilnamn, "w");
    if (tsut == NULL) {
        printf("Kunde inte skriva filen '%s'.\n", utfilnamn);
        exit(EXIT_FAILURE);
    }

    int detta_tal;
    while (fscanf(tsin, "%d", &detta_tal) == 1) {
        ++antal_tal[detta_tal];
    }
    fclose(tsin);

    for (int i = 1; i <= 1000000; ++i) {
        if (antal_tal[i] != 0)
            fprintf(tsut, "%d\n", i);
    }
    fclose(tsut);

    return EXIT_SUCCESS;
}

Kommentarer:


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), 19 januari 2016