Umu logo

Umeå Universitet
Institutionen för datavetenskap
Programmeringsteknik för tekniska fysiker


Niklas Frykholm, 5 mars 1999

Gruppövning 4 - Strukturer, listor, filer

1. Finn sju fel

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

/* Detta program läser in en vektor med godtyckligt antal element
   från filen "vector.txt", och skriver ut vektorns längd på skärmen

   Om vector.txt innehåller: 1    3    2    5
   blir utskriften sqrt(1^2 + 3^2 + 2^2 + 5^2) = sqrt(39) ~ 6.245
*/

struct vector {
  double *v;    /* Pekare till element. */
  int n;        /* Antal element i vektorn. */  
};

double length(vector x);

int main(void)
{
  FILE *f;
  vector a = {0};

  f = fopen("vector.txt", "w");
  assert(f==NULL);

  while (1) {
    a.v = realloc(a.v, a.n*sizeof(double));
    assert(a.v);
    if (scanf("%lf", &a.v[a.n])!=1)
      break;
    a.n++;
  }

  printf("%lf\n", length(a));
  return 0;
}

double length(vector x)
{
  int i;
  double sqsum = 0;

  for (i=0; i<n; i++)
    sqsum += vector.v[i] * vector.v[i];
  return sqrt(sqsum);
}

2. Poker igen

Antag att följande typdefinition används för att representera en pokerhand

typedef struct {
  char farg;   /* 'h', 'r', 's', 'k' */
  int  valor;  /* 2-14 */
} kort_t;

typedef struct {
  kort_t kort[5];
} hand_t;

Skriv funktionen triss som returnerar sant om handen innehåller en triss:

int triss(hand_t h)

Vill ni ha en liten klurigare uppgift kan ni prova att skriva int stege(hand_t h);

3. Filkopiering

Skriv ett program som kopierar filer. Programmet skall kunna köras från kommandoraden, t ex som

peppar% a.out source.txt destination.txt

Där source.txt är namnet på filen som skall kopieras och destination.txt är namnet på den nya filen.

Se till att ditt program hanterar alla fel som kan uppstå.

Tips: använd funktionerna fgetc och fputc för att läsa ett tecken i taget (motsvarigheter till getchar och putchar).

4. Rensa nollor

Antag att följande typdefintion används för en länkad lista

typedef int DATA;

struct list {
  DATA d;
  struct list *next;
};

typedef struct list ELEMENT;
typedef ELEMENT *LINK;

Skriv funktionen

void strip_zeros(LINK *p)

Funktionen skall ta en pekare till listhuvudet som argument och ta bort alla element i listan som är nollor. Antag att du har tillgång till hjälpfunktionen remove (som skissades på lektionen). Den tar bort det element som p pekar på länken till

void remove(LINK *p)

5. Betygssortering

På filen betyg.txt finns ett antal personer och deras betyg upplagda. Det kan t ex se ut som

Anders Andersson 3
Carina Carlsson 5
Eva Ersson 4
Paul Paulsson 5

Skriv ett program som utifrån filen betyg.txt skapar tre nya filer: betyg5.txt, betyg4.txt och betyg3.txt. betyg5.txt skall innehålla namnet på alla som har fått betyg 5. betyg4.txt namnet på alla som har fått betyg 4 och betyg3.txt namnet på alla som har fått betyg 3.

I exemplet ovan skall betyg5.txt efter körningen av programmet innehålla texten

Carina Carlsson
Paul Paulsson

Alla namn i filen består av förnamn (ett ord) + efternamn (ett ord).

Ditt program bör innehålla en kontroll av att filen betyg.txt finns och skriva ut ett lämpligt felmeddelande om den inte gör det. Inga andra felkontroller behövs.

6. Cirkulär lista

En cirkulär lista fungerar som en länkad lista, men det sista elementets next-pekare är inte NULL, i stället pekar den tillbaka på det första elementet så att elementen bildar en cirkel.

Skriv funktionen

int count(LINK A)

som tar som argument ett pekare till något av elementen i listan och returnerar antalet element i listan.

Tips: Samma data-värde kan förekomma flera gånger i listan, men varje element ligger på en unik adress.

7. Strängkopiering

Skriv funktionen

char *strdup(char *s)

Funktionen skall ta en sträng som argument - allokera ett minnesutrymme som är tillräckligt stort för att rymma strängen, kopiera strängen dit och returnera en pekare till det nya minnesutrymmet. Om någonting går fel skall funktionen returnera NULL.

8. Punkter på linje

Skriv en funktion som tar en vektor med tre punkter som argument och returnerar sant om punkterna ligger på en linje och falskt i annat fall. Antag att följande typdefinition används för att representera punkter

typedef struct {
    int x, y;
} point_t;

Exempel på ett anrop av funktionen ges nedan

point_t points[3] = {1,1,2,2,3,3};

if (line(points)) {
  ...
}

Kan du lösa uppgiften utan att jämföra flyttal? (Som vi har sett kan sådana jämförelser ge problem pga avrundning.)

9. Vektorer i structar i vektorer i structar i vektorer i...

En programmerare håller på att skissa på det ultimata adressboksprogrammet. Hon har kommit fram till följande skiss över hur datastrukturerna skall hänga ihop

De tjocka pilarna betyder här "en eller flera". En adressbok kan alltså innehålla en eller flera personer. Varje person har ett enda namn, men flera möjliga "vistelseorter". Var och en av dessa platser indentifieras med en unik sträng (t ex "hem", "arbete", "mobil", "föräldrar"). För varje plats finns en adress och ett telefonnummer.

Utifrån denna skiss skapar programmeraren följande typdeklarationer:

typedef struct {
    char *fornamn;
    char *efternamn;
    char *smeknamn;
} NAMN;

typedef struct {
    int riktnummer;
    int telefonnummer;
} TELEFONNUMMER;

typedef struct {
    char *gatuadress;
    char *postort;
    int postnummer;
} ADRESS;

typedef struct {
    char *identitet;
    ADRESS adress;
    TELEFONNUMMER telefonnummer;
} PLATS;

typedef struct {
    NAMN namn;
    PLATS *platser;
    int antal_platser;
} PERSON;

typedef struct {
    PERSON *personer;
    int antal_personer;
} ADRESSBOK;

Pekarna personer och platser pekar på ett minnesutrymme som är tillräckligt stort för att rymma antal_personer respektive antal_platser.

Skriv funktionen

int telnr(ADRESSBOK a, char *smeknamn, char *plats);

Den tar en adressbok, ett smeknamn och en platsidentitet (t ex "hem") som argument och skall returnera vilket telefonnummer personen med det angivna smeknamnet har på den angivna platsen.


© Niklas Frykholm, mars 1999