Umu logo

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


Niklas Frykholm, 9 mars 1999

Gruppövning 4 - svar

Här är några förslag på lösningar till uppgifterna. Kom dock ihåg att det alltid finns mer än ett sätt att lösa en uppgift.

1. Finn sju fel

g4_1.c


#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", beräknar längden och skriver ut den
   på skärmen.

   Om filen innehåller

   1    3    2    5

   Blir utskriften sqrt(1^2 + 3^2 + 2^2 + 5^2) = sqrt(39) ~ 6.245
*/

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

double length(vector x);

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

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

  while (1) {
    a.v = realloc(a.v, (a.n+1)*sizeof(double));
    assert(a.v);

    if (fscanf(f, "%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<x.n; i++)
    sqsum += x.v[i] * x.v[i];
  return sqrt(sqsum);
}

2. Poker igen

Jag använder en vektor för att räkna hur många gånger varje valör förekommer. Ett annat sätt är att börja med att sortera korten efter valör.

Notera speciellt hur vi via structen h kommer åt ett visst korts valör.

g4_2.c


#include <stdio.h>

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

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

int main(void)
{
  hand_t h1 = {0};
  int i;

  printf("Ange fem kort på formen h 2 s 14 r 12: ");

  for (i=0; i<5; i++)
    scanf(" %c %d", &h1.kort[i].farg, &h1.kort[i].valor);

  if (triss(h1))
    printf("Triss!\n");

  if (stege(h1))
    printf("Stege!\n");
}

int triss(hand_t h)
{
  /* Räknar antal kort av varje valör. */
  int val_count[15]={0}, i;

  for (i=0; i<5; i++)
    val_count[h.kort[i].valor]++;

  for (i=1; i<=14; i++)
    if (val_count[i]>=3)
      return 1;
  return 0;
}

int stege(hand_t h)
{
  /* Räknar antal kort av varje valor. */
  int val_count[15] = {0}, i;
  int rad = 0;

  for (i=0; i<5; i++) {
    val_count[h.kort[i].valor]++;

    /* Vi räknar ess både som 1 och 14. */
    if (h.kort[i].valor == 14)
      val_count[1]++;
  }
  
  /* Räkna antal kort i rad. */
  for (i=1; i<=14; i++) {
    rad = val_count[i] > 0 ? rad+1 : 0;
    if (rad==5)
      return 1;
  }
  return 0;
}

3. Filkopiering

g4_3.c


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

int main(int argc, char **argv)
{
  FILE *from, *to;
  int c;

  if (argc!=3) {
    printf("Programmet måste anropas som: a.out source dest\n");
    exit(1);
  }
  
  from = fopen(argv[1],"r");
  if (from == NULL) {
    perror(argv[1]);
    exit(1);
  }


  to = fopen(argv[2],"w");
  if (to == NULL) {
    perror(argv[2]);
    exit(1);
  }

  while ((c = fgetc(from)) != EOF)
    fputc(c, to);

  fclose(from);
  fclose(to);

  return 0;
}

4. Rensa nollor

Den här uppgiften kan lösas rekursivt eller iterativt. Jag har gjort en iterativ lösning för att variera mig litet.

Den huvudsakliga svårigheten är hur p skall flyttas fram så att den pekar på en länk till nästa element.

g4_4.c


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

typedef int DATA;

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

typedef struct list ELEMENT;
typedef ELEMENT *LINK;

void print_list(LINK A);
void strip_zeros(LINK *p);

/* Eftersom det redan finns en remove-funktion i C döper vi vår funktion
   till remove_item. */
void remove_item(LINK *p);

int main(void)
{
  /* Skapa en lista med några element. */
  LINK head;

  head = malloc(sizeof(ELEMENT));
  head->next = malloc(sizeof(ELEMENT));
  head->next->next = malloc(sizeof(ELEMENT));
  head->next->next->next = malloc(sizeof(ELEMENT));
  head->next->next->next->next = NULL;

  head->data = 0;
  head->next->data = 7;
  head->next->next->data = 0;
  head->next->next->next->data = 3;

  /* Skriv ut listan. */
  print_list(head);
  printf("\n");

  /* Ta bort nollor. */
  strip_zeros(&head);

  /* Skriv ut listan igen. */
  print_list(head);
  printf("\n");

  /* Vi slarvar litet och frigör inte minnet eftersom
     programmet ändå avslutas här. */
  return 0;
}

void print_list(LINK A)
{
  if (A) {
    printf("%d", A->data);
    print_list(A->next);
  }
}

void strip_zeros(LINK *p)
{
  while (*p) {
    if ((**p).data == 0)
      remove_item(p);
    else
      p = &(**p).next;
  }
}

void remove_item(LINK *p)
{
  LINK B = *p, C;
  if (B) {
    C = B->next;
    free(B);
    *p = C;
    
  }
}       

5. Betygssortering

g4_5.c


#include <stdio.h>

int main(void)
{
  FILE *f, *f3, *f4, *f5;
  char fnamn[50], enamn[50];
  int betyg;
  
  f = fopen("betyg.txt", "r");

  if (f==NULL) {
    perror("betyg.txt");
    exit(1);
  }

  f3 = fopen("betyg3.txt", "w");
  f4 = fopen("betyg4.txt", "w");
  f5 = fopen("betyg5.txt", "w");

  while (fscanf(f,"%s %s %d",fnamn,enamn,&betyg)==3) {
    if (betyg==3)
      fprintf(f3, "%s %s\n", fnamn, enamn);
    else if (betyg==4)
      fprintf(f4, "%s %s\n", fnamn, enamn);
    else if (betyg==5)
      fprintf(f5, "%s %s\n", fnamn, enamn);
  }

  fclose(f3);
  fclose(f4);
  fclose(f5);

  return 0;
}

6. Cirkulär lista

g4_6.c


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

typedef int DATA;

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

typedef struct list ELEMENT;
typedef ELEMENT *LINK;

int count(LINK A);

int main(void)
{
  /* Konstruera en cirkulär lista med några element. */
  LINK head;

  head = malloc(sizeof(ELEMENT));
  head->next = malloc(sizeof(ELEMENT));
  head->next->next = malloc(sizeof(ELEMENT));
  head->next->next->next = malloc(sizeof(ELEMENT));

  /* Knyt ihop cirkeln. */
  head->next->next->next->next = head;

  printf("%d\n", count(head));

  /* Vi slarvar litet och frigör inte minnet eftersom
     programmet ändå avslutas här. */
  return 0;
}

int count(LINK A)
{
  LINK C = A->next;
  int n=1;

  while (C != A) {
    C = C->next;
    n++;
  }
  return n;
}

7. Strängkopiering

g4_7.c


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

/* Eftersom strdup redan finns får vi döpa vår funktion till my_strdup. */
char *my_strdup(char *s);

int main(void)
{
  char *s = "Hejsan";
  char *p;

  p = my_strdup(s);
  p[0] = 'D';

  printf("%s %s\n", s, p);
}

char *my_strdup(char *s)
{
  char *q;
  q = malloc((strlen(s)+1)*sizeof(char));
  strcpy(q,s);
  return q;
}

  

8. Punkter på linje

Det klurigaste här är algoritmen. Kolla själv att den stämmer.

g4_8.c


#include <stdio.h>

typedef struct {
  int x, y;
} point_t;

int line(point_t p[3]);

int main(void)
{
  point_t points[3] = {1,1,2,2,-5,-5};

  if (line(points))
    printf("På linje!\n");
}

int line(point_t p[3])
{
  return (p[0].x - p[2].x)*(p[0].y - p[1].y) ==
    (p[0].y - p[2].y)*(p[0].x - p[1].x);
}

9. Vectorer i structar i vektorer i structar i vektorer i

Det gäller bara att hålla tungan rätt i mun och använda punktoperatorn för att komma åt underfält i en struct och hakparenteser för att komma åt en viss post i en lista.

g4_9.c


int telnr(ADRESSBOK a, char *smeknamn, char *plats)
{
  int i, j;
  for (i=0; i < a.antal_personer; i++) {
    if (strcmp(a.personer[i].namn.smeknamn, smeknamn)==0) {
      for (j=0; j < a.personer[i].antal_platser; j++) {
    if (strcmp(a.personer[i].platser[j].identitet,plats)==0)
      return a.personer[i].platser[j].telefonnummer.telefonnummer;
      }
    }
  }
  return 0;
}


© Niklas Frykholm, mars 1999