Programmering C: Lösningar till tentamen 2006-06-07

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)

Alternativ 1:
z = x + y / sqrt(pow(x, 2) + z);
Alternativ 2:
z = x + y / sqrt(x*x + z);

Uppgift 2 (1 p)

a) 1

b) 1.67

c) 1.67

d) 1.00

Lägg märke till att värdet av uttrycket i (a) är ett heltal, medan värdet av de övriga uttrycken är flyttal.

Uppgift 3 (1 p)

8

Uppgift 4 (1 p)

struct Bok {
  int nummer;
  char efternamn[20 + 1];
  char fornamn[10 + 1];
  char titel[100 + 1];
  float vikt;
};

För att få plats med strängavslutningstecknet ´\0' måste man ha en extra plats i varje strängfält.

Uppgift 5 (1 p)

struct Bok boken = { 138, "Guillou", "Jan", "I nationens intresse", 0.3 };

Uppgift 6 (2 p)

void visa_bok(struct Bok boken) {
  printf("Nummer: %d\n", boken.nummer);
  printf("Författare: %s, %s\n", boken.efternamn, boken.fornamn);
  printf("Titel: %s\n", boken.titel);
  printf("Vikt: %.2f kg\n", boken.vikt);
}

Uppgift 7 (3 p)

int i_ordning(struct Bok bok1, struct Bok bok2) {
  int resultat;

  resultat = strcmp(bok1.efternamn, bok2.efternamn);
  if (resultat < 0)
    return 1;
  else if (resultat > 0)
    return 0;
  resultat = strcmp(bok1.fornamn, bok2.fornamn);
  if (resultat < 0)
    return 1;
  else if (resultat > 0)
    return 0;
  resultat = strcmp(bok1.titel, bok2.titel);
  if (resultat <= 0)
    return 1;
  else
    return 0;
}

Uppgift 8 (2 p)

Alternativ 1:
struct Bok las_bok() {
  struct Bok boken;
  printf("Författarens förnamn: ");
  gets(boken.fornamn);
  printf("Författarens efternamn: ");
  gets(boken.efternamn);
  printf("Bokens titel: ");
  gets(boken.titel);
  printf("Bokens vikt: ");
  scanf("%f", &boken.vikt);
  printf("Bokens nummer: ");
  scanf("%d", &boken.nummer);
  while (getchar() != '\n')
    ;
  return boken;
}
Alternativ 2:
void las_bok(struct Bok* p) {
  printf("Författarens förnamn: ");
  gets(p->fornamn);
  printf("Författarens efternamn: ");
  gets(p->efternamn);
  printf("Bokens titel: ");
  gets(p->titel);
  printf("Bokens vikt: ");
  scanf("%f", &p->vikt);
  printf("Bokens nummer: ");
  scanf("%d", &p->nummer);
  while (getchar() != '\n')
    ;
}

getchar-loopen på slutet tar bort radslutstecknet efter boknumret ur inmatningsbufferten. Annars kommer inläsningen med gets av förnamnet i nästa bok att returnera resten av den inmatade raden med boknumret, och det är förmodligen inte vad man vill.

Uppgift 9 (1 p)

int hela_miljoner(int talet) {
  return talet / 1000000;
}

Uppgift 10 (2 p)

int cirka_miljoner(int talet) {
  int resultat;
  resultat = talet / 1000000;
  if (talet % 1000000 > 500000)
    resultat += 1;
  else if (talet % 1000000 == 500000 && resultat % 2 == 1)
    resultat += 1;
  return resultat;
}

Uppgift 11 (5 p)

#include <stdio.h>

extern int cirka_miljoner(int talet);

int main(void) {
  int arsinkomst;
  int formogenhet;

  printf("Ange årsinkomst: ");
  scanf("%d", &arsinkomst);

  while (arsinkomst != 0) {
    printf("Ange förmögenhet: ");
    scanf("%d", &formogenhet);

    printf("Du tjänar ungefär %d miljoner om året,\n", cirka_miljoner(arsinkomst));
    printf("och äger ungefär %d miljoner.\n", cirka_miljoner(formogenhet));

    printf("Ange årsinkomst: ");
    scanf("%d", &arsinkomst);
  }

  return 0;
}
Kommentarer:
  1. Kursmaterialet använder void main, trots att C-standarden (i de flesta sammanhang) egentligen kräver int main. Jag använder int main i mina lösningar, men ger inga poängavdrag för void main.
  2. Man behöver inte upprepa definitionen av funktionen cirka_miljoner. I programmet ovan har jag extern-deklarerat den, men det ger inga poängavdrag om man inte har med den alls.

Uppgift 12 (4 p)

#include <stdio.h>

int main(void) {
  float l, b, h;

  printf("Ange rummets bredd: ");
  scanf("%f", &b);
  printf("Ange rummets längd: ");
  scanf("%f", &l);
  printf("Ange rummets höjd: ");
  scanf("%f", &h);

  printf("\n");

  printf("Liter målarfärg: %.2f\n", h*l + h*l + h*b + h*b);
  printf("Kvadratmeter golvmatta: %.2f\n", b*l);
  printf("Meter golvlister: %.2f\n", b+b+l+l);

  return 0;
}

Uppgift 13 (4 p)

Alternativ 1:
#include <stdio.h>

int main(void) {
  struct Bok boken;
  FILE* f;

  printf("Mata in böcker. Avsluta med en bok med nummer 0.\n");
  f = fopen("bocker.bin", "wb");

  boken = las_bok();
  while (boken.nummer != 0) {
    fwrite(&boken, sizeof(boken), 1, f);
    boken = las_bok();
  }

  fclose(f);
  return 0;
}
Alternativ 2:
#include <stdio.h>

int main(void) {
  struct Bok boken;
  FILE* f;

  printf("Mata in böcker. Avsluta med en bok med nummer 0.\n");
  f = fopen("bocker.bin", "wb");

  las_bok(&boken);
  while (boken.nummer != 0) {
    fwrite(&boken, sizeof(boken), 1, f);
    las_bok(&boken);
  }

  fclose(f);
  return 0;
}

Man behöver inte upprepa definitionen av funktionen las_bok eller av typen struct Bok.

Uppgift 14 (5 p)

#include <stdio.h>

#define MAX_ANTAL_BOCKER 1000

int main(void) {
  struct Bok boken;
  struct Bok bocker[MAX_ANTAL_BOCKER];
  int antal_bocker;
  struct Bok minsta_boken;
  int minsta_positionen;
  struct Bok temp;

  FILE *fin = fopen("bocker.bin", "rb");
  while (fread(&boken, sizeof(boken), 1, fin) == 1)
    bocker[antal_bocker++] = boken;
  fclose(fin);

  for (int i = 0; i < antal_bocker - 2; ++i) {
    minsta_positionen = i;
    minsta_boken = bocker[i];
    for (int j = i + 1; j < antal_bocker; ++j) {
      if (i_ordning(minsta_boken, bocker[j]) == 0) {
	minsta_positionen = j;
	minsta_boken = bocker[j];
      }
    }
    temp = bocker[i];
    bocker[i] = bocker[minsta_positionen];
    bocker[minsta_positionen] = temp;
  }

  FILE *fut = fopen("sorterat.bin", "wb");
  for (int i = 0; i < antal_bocker; ++i)
    fwrite(&bocker[i], sizeof(bocker[i]), 1, fut);
  fclose(fut);

  return 0;
}

Uppgift 15 (7 p)

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

#define MAX_ANTAL_VIKTER 30

int main(void) {
  FILE *f = fopen("vikter.txt", "r");
  if (f == NULL) {
    fprintf(stderr, "Kunde inte öppna filen 'vikter.txt'.\n");
    return EXIT_FAILURE;
  }

  float vikterna[MAX_ANTAL_VIKTER];
  int antal_vikter = 0;

  float vikten;

  while (fscanf(f, "%f", &vikten) == 1) {
    if (antal_vikter == MAX_ANTAL_VIKTER) {
      // Fullt i arrayen. Gör plats, och stoppa in den nya vikten sist.
      for (int i = 0; i < antal_vikter - 1; ++i)
	vikterna[i] = vikterna[i + 1];
      vikterna[antal_vikter - 1] = vikten;
    }
    else {
      // Inte fullt i arrayen. Stoppa in den nya vikten sist.
      vikterna[antal_vikter++] = vikten;
    }
  } //while

  // Om filen inte var slut, så slutade while-loopen inte pga EOF, utan
  // pga av att det fanns något i filen som inte gick att tolka som ett flyttal
  if (! feof(f)) {
    fprintf(stderr, "Det fanns något skräp i filen 'vikter.txt'.\n");
    return EXIT_FAILURE;
  }

  fclose(f);

  if (antal_vikter == 0) {
    fprintf(stderr, "Det fanns inga vikter i filen 'vikter.txt'.\n");
    return EXIT_FAILURE;
  }

  float summan = 0;
  for (int i = 0; i < antal_vikter; ++i)
    summan += vikterna[i];

  printf("Glidande medelvärdet över %d dagar: %f\n", antal_vikter, summan / antal_vikter);

  return 0;
}


Thomas Padron-McCarthy (Thomas.Padron-McCarthy@tech.oru.se) 9 juni 2006