COMP1511 18s2

Week-07 Laboratory Sample Solution

Objectives

  • Introduction to struct, array of struct and pointers to struct
  • Introduction string operations

Topics

Exercise-01: How many Orca Pods (pair)

Sample solution for orca.c
#include <stdio.h>
#include <string.h>

#define MAX_SPECIES_NAME_LENGTH 128
#define MAX_SIGHTINGS 10000

// a struct to represent the date
// a whale pod sighting was made

struct date {
    int year;
    int month;
    int day;
};

// a struct to represent a sighting
// of a pod (group) of whales

struct pod {
    struct date when;
    int         how_many;
    char        species[MAX_SPECIES_NAME_LENGTH];
};


int read_sightings_file(char filename[], int len, struct pod sightings[len]);
int read_sighting(FILE *f, struct pod *w);
int read_date(FILE *f, struct date *d);

int count_orca_sightings(int n_sightings, struct pod sightings[n_sightings]);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file>\n", argv[0]);
        return 1;
    }

    struct pod whale_sightings[MAX_SIGHTINGS] = {{{0}}};
    int n_sightings = read_sightings_file(argv[1], MAX_SIGHTINGS, whale_sightings);

    if (n_sightings > 0) {
        int n_orca_pods = count_orca_sightings(n_sightings, whale_sightings);
        printf("%d Orca sightings in %s\n", n_orca_pods, argv[1]);
    }
    return 0;
}

// return the number of sightings of Orca
int count_orca_sightings(int n_sightings, struct pod sightings[n_sightings]) {
    int orca_count = 0;
    int i = 0;
    while (i < n_sightings) {
        if (strcmp(sightings[i].species, "Orca") == 0) {
            orca_count = orca_count + 1;
        }
        i = i + 1;
    }
    return orca_count;
}


//
// DO NOT CHANGE THE FUNCTION BELOW HERE
//

// return number of sightings read from filename
// -1 is returned if there is an error

int read_sightings_file(char filename[], int len, struct pod sightings[len]) {
    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", filename);
        return -1;
    }

    int n_sightings = 0;
    while (read_sighting(f, &sightings[n_sightings]) == 1 && n_sightings < len) {
        n_sightings = n_sightings + 1;
    }

    fclose(f);
    return n_sightings;
}


// return 1 if a sighting can be read, 0 otherwise

int read_sighting(FILE *f, struct pod *s) {
    if (read_date(f, &(s->when)) != 1) {
        return 0;
    }
    if (fscanf(f, "%d", &(s->how_many)) != 1) {
        return 0;
    }
    fgetc(f);
    if (fgets(s->species, MAX_SPECIES_NAME_LENGTH, f) == NULL) {
        return 0;
    }

    // finish string at '\n' if there is one
    char *newline_ptr = strchr(s->species, '\n');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }

    // also finish string at '\r' if there is one - files from Windows  will
    newline_ptr = strchr(s->species, '\r');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }
    return 1;
}


// return 1 if a date can be read, 0 otherwise

int read_date(FILE *f, struct date *d) {
    int n_scanned = fscanf(f, "%d/%d/%d", &(d->year), &(d->month), &(d->day));
    return n_scanned == 3;
}

Exercise-02: Counting A Whale Species (pair)

Sample solution for species_count.c
#include <stdio.h>
#include <string.h>

#define MAX_SPECIES_NAME_LENGTH 128
#define MAX_SIGHTINGS 10000

// a struct to represent the date
// a whale pod sighting was made

struct date {
    int year;
    int month;
    int day;
};

// a struct to represent a sighting
// of a pod (group) of whales

struct pod {
    struct date when;
    int         how_many;
    char        species[MAX_SPECIES_NAME_LENGTH];
};


int read_sightings_file(char filename[], int len, struct pod sightings[len]);
int read_sighting(FILE *f, struct pod *w);
int read_date(FILE *f, struct date *d);

void species_count(char species[], int n_sightings, struct pod sightings[n_sightings],
                   int *n_pods, int *n_whales);

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <file> <species>\n", argv[0]);
        return 1;
    }
    char *filename = argv[1];
    char *species = argv[2];

    struct pod whale_sightings[MAX_SIGHTINGS];
    int n_sightings = read_sightings_file(filename, MAX_SIGHTINGS, whale_sightings);

    if (n_sightings < 1) {
        return 1;
    }

    int pod_count;
    int whale_count;
    species_count(species, n_sightings, whale_sightings, &pod_count, &whale_count);
    printf("%d %s pods containing %d whales in %s\n", pod_count, species, whale_count, filename);

    return 0;
}

// number of pods of the specified species assigned to *n_pods
// total number of whales of the specified species assigned to *n_whales

void species_count(char species[], int n_sightings, struct pod sightings[n_sightings],
                   int *n_pods, int *n_whales) {
    int pods = 0;
    int whales = 0;
    int i = 0;
    while (i < n_sightings) {
        if (strcmp(sightings[i].species, species) == 0) {
            pods = pods + 1;
            whales = whales + sightings[i].how_many;
        }
        i = i + 1;
    }
    *n_pods = pods;
    *n_whales = whales;
}


//
// DO NOT CHANGE THE FUNCTION BELOW HERE
//

// return number of sightings read from filename
// -1 is returned if there is an error

int read_sightings_file(char filename[], int len, struct pod sightings[len]) {
    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", filename);
        return -1;
    }

    int n_sightings = 0;
    while (read_sighting(f, &sightings[n_sightings]) == 1 && n_sightings < len) {
        n_sightings = n_sightings + 1;
    }

    fclose(f);
    return n_sightings;
}


// return 1 if a sighting can be read, 0 otherwise

int read_sighting(FILE *f, struct pod *s) {
    if (read_date(f, &(s->when)) != 1) {
        return 0;
    }
    if (fscanf(f, "%d", &(s->how_many)) != 1) {
        return 0;
    }
    fgetc(f);
    if (fgets(s->species, MAX_SPECIES_NAME_LENGTH, f) == NULL) {
        return 0;
    }

    // finish string at '\n' if there is one
    char *newline_ptr = strchr(s->species, '\n');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }

    // also finish string at '\r' if there is one - files from Windows  will
    newline_ptr = strchr(s->species, '\r');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }
    return 1;
}


// return 1 if a date can be read, 0 otherwise

int read_date(FILE *f, struct date *d) {
    int n_scanned = fscanf(f, "%d/%d/%d", &(d->year), &(d->month), &(d->day));
    return n_scanned == 3;
}

Exercise-03: Printing A summary of All Whale Species (pair)

Sample solution for whale_summary.c
#include <stdio.h>
#include <string.h>

#define MAX_SPECIES_NAME_LENGTH  128
#define MAX_SIGHTINGS           10000
#define MAX_WHALE_SPECIES         256

// a struct to represent the date
// a whale pod sighting was made

struct date {
    int year;
    int month;
    int day;
};

// a struct to represent a sighting
// of a pod (group) of whales

struct pod {
    struct date when;
    int         how_many;
    char        species[MAX_SPECIES_NAME_LENGTH];
};


int read_sightings_file(char filename[], int len, struct pod sightings[len]);
int read_sighting(FILE *f, struct pod *w);
int read_date(FILE *f, struct date *d);

void whale_summary(int n_sightings, struct pod sightings[n_sightings]);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file> <species>\n", argv[0]);
        return 1;
    }

    struct pod whale_sightings[MAX_SIGHTINGS];
    int n_sightings = read_sightings_file(argv[1], MAX_SIGHTINGS, whale_sightings);

    if (n_sightings < 1) {
        return 1;
    }

    whale_summary(n_sightings, whale_sightings);

    return 0;
}

// a struct to store summary information for each whale species

struct tally {
    int  pods;
    int  whales;
    char species[MAX_SPECIES_NAME_LENGTH];
};

//
// print a summary of all whale sightings
//

void whale_summary(int n_sightings, struct pod sightings[n_sightings]) {
    struct tally summary[MAX_WHALE_SPECIES];

    int i = 0;
    int n_species_seen = 0;
    while (i < n_sightings) {
        int j = 0;
        char *species = sightings[i].species;
        while (j < n_species_seen && strcmp(species, summary[j].species) != 0) {
            j = j + 1;
        }

        if (j < n_species_seen) {
            summary[j].pods = summary[j].pods + 1;
            summary[j].whales = summary[j].whales + sightings[i].how_many;
        } else if (n_species_seen < MAX_WHALE_SPECIES) {
            strcpy(summary[n_species_seen].species, species);
            summary[n_species_seen].pods = 1;
            summary[n_species_seen].whales = sightings[i].how_many;;
            n_species_seen = n_species_seen + 1;
        } else {
            fprintf(stderr, "maximum number of whale species(%d) exceeded\n", MAX_WHALE_SPECIES);
            return;
        }

        i = i + 1;
    }

    i = 0;
    while (i < n_species_seen) {
        printf("%d %s pods containing %d whales\n", summary[i].pods, summary[i].species, summary[i].whales);
        i = i + 1;
    }
}


//
// DO NOT CHANGE THE FUNCTION BELOW HERE
//

// return number of sightings read from filename
// -1 is returned if there is an error

int read_sightings_file(char filename[], int len, struct pod sightings[len]) {
    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", filename);
        return -1;
    }

    int n_sightings = 0;
    while (read_sighting(f, &sightings[n_sightings]) == 1 && n_sightings < len) {
        n_sightings = n_sightings + 1;
    }

    fclose(f);
    return n_sightings;
}


// return 1 if a sighting can be read, 0 otherwise

int read_sighting(FILE *f, struct pod *s) {
    if (read_date(f, &(s->when)) != 1) {
        return 0;
    }
    if (fscanf(f, "%d", &(s->how_many)) != 1) {
        return 0;
    }
    fgetc(f);
    if (fgets(s->species, MAX_SPECIES_NAME_LENGTH, f) == NULL) {
        return 0;
    }

    // finish string at '\n' if there is one
    char *newline_ptr = strchr(s->species, '\n');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }

    // also finish string at '\r' if there is one - files from Windows  will
    newline_ptr = strchr(s->species, '\r');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }
    return 1;
}


// return 1 if a date can be read, 0 otherwise

int read_date(FILE *f, struct date *d) {
    int n_scanned = fscanf(f, "%d/%d/%d", &(d->year), &(d->month), &(d->day));
    return n_scanned == 3;
}

Challenge Exercise: Correcting Typos in Whale Names (individual)

Sample solution for sanitize_whales.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#define MAX_SPECIES_NAME_LENGTH  128
#define MAX_SIGHTINGS           10000
#define MAX_WHALE_SPECIES         256

// a struct to represent the date
// a whale pod sighting was made

struct date {
    int year;
    int month;
    int day;
};

// a struct to represent a sighting
// of a pod (group) of whales

struct pod {
    struct date when;
    int         how_many;
    char        species[MAX_SPECIES_NAME_LENGTH];
};


int read_sightings_file(char filename[], int len, struct pod sightings[len]);
int read_sighting(FILE *f, struct pod *p);
int read_date(FILE *f, struct date *d);

void write_sightings_file(char filename[], int n_sightings, struct pod sightings[n_sightings]);
void write_sighting(FILE *f, struct pod *p);
void write_date(FILE *f, struct date *d);

void sanitize_whales(char species_names_file[], int n_sightings, struct pod sightings[n_sightings]);
void fix_whale_name(char whale_name[], int n_species_names, char correct_whale_names[MAX_WHALE_SPECIES][MAX_SPECIES_NAME_LENGTH]);
int same_whale_name(char whale_name1[], char whale_name2[]);
void canonical_copy(char destination[], char source[]);
int read_species_names(char species_names_file[], char whale_names[MAX_WHALE_SPECIES][MAX_SPECIES_NAME_LENGTH]);

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage: %s <species_names_file> <old_file> <new_file>\n", argv[0]);
        return 1;
    }

    char *species_names_file = argv[1];
    char *old_file = argv[2];
    char *new_file = argv[3];

    struct pod whale_sightings[MAX_SIGHTINGS];
    int n_sightings = read_sightings_file(old_file, MAX_SIGHTINGS, whale_sightings);

    if (n_sightings < 1) {
        return 1;
    }

    sanitize_whales(species_names_file, n_sightings, whale_sightings);

    write_sightings_file(new_file, n_sightings, whale_sightings);

    return 0;
}


//
// sanitize whales remove extra non alphabetic characters
//

void sanitize_whales(char species_names_file[], int n_sightings, struct pod sightings[n_sightings]) {
    char correct_whale_names[MAX_WHALE_SPECIES][MAX_SPECIES_NAME_LENGTH];
    int n_species_names = read_species_names(species_names_file, correct_whale_names);
    int i = 0;
    while (i < n_sightings) {
        fix_whale_name(sightings[i].species, n_species_names, correct_whale_names);
        i = i + 1;
    }
}

void fix_whale_name(char whale_name[], int n_species_names, char correct_whale_names[MAX_WHALE_SPECIES][MAX_SPECIES_NAME_LENGTH]) {
    int i = 0;
    while (i < n_species_names) {
        if (same_whale_name(whale_name, correct_whale_names[i])) {
            if (strcmp(whale_name, correct_whale_names[i]) != 0) {
                strcpy(whale_name, correct_whale_names[i]);
            }
            return;
        }
        i = i + 1;
    }
    assert(0); //whale name not in list
}

//
// return 1 if these are the same whale name
// after ignoring case and non-alphabetic characters
//
int same_whale_name(char whale_name1[], char whale_name2[]) {
    char filtered_name1[strlen(whale_name1) + 1];
    char filtered_name2[strlen(whale_name2) + 1];
    canonical_copy(whale_name1, filtered_name1);
    canonical_copy(whale_name2, filtered_name2);
    return strcmp(filtered_name1, filtered_name2) == 0;
}

//
// copy alphabetic characters from source to destination
// translating upper case to lower case
//
void canonical_copy(char source[], char destination[]) {
    int i = 0;
    int j = 0;
    while (source[i] != '\0') {
        if (isalpha(source[i])) {
            destination[j] = tolower(source[i]);
            j = j + 1;
        }
        i = i + 1;
    }
    destination[j] = '\0';
}

int read_species_names(char species_names_file[], char whale_names[MAX_WHALE_SPECIES][MAX_SPECIES_NAME_LENGTH]) {
    FILE *f = fopen(species_names_file, "r");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", species_names_file);
        exit(1);
    }

    int n_species_names = 0;
    while (fgets(whale_names[n_species_names], MAX_SPECIES_NAME_LENGTH, f) &&
           n_species_names < MAX_WHALE_SPECIES) {
        char *newline_ptr = strchr(whale_names[n_species_names], '\n');
        if (newline_ptr != NULL) {
            *newline_ptr = '\0';
        }
        n_species_names = n_species_names + 1;
    }
    fclose(f);

    return n_species_names;
}

//
// DO NOT CHANGE THE FUNCTION BELOW HERE
//

// return number of sightings read from filename
// -1 is returned if there is an error

int read_sightings_file(char filename[], int len, struct pod sightings[len]) {
    FILE *f = fopen(filename, "r");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", filename);
        return -1;
    }

    int n_sightings = 0;
    while (read_sighting(f, &sightings[n_sightings]) == 1 && n_sightings < len) {
        n_sightings = n_sightings + 1;
    }
    fclose(f);

    return n_sightings;
}


// return 1 if a sighting can be read, 0 otherwise

int read_sighting(FILE *f, struct pod *s) {
    if (read_date(f, &(s->when)) != 1) {
        return 0;
    }
    if (fscanf(f, "%d", &(s->how_many)) != 1) {
        return 0;
    }
    fgetc(f);
    if (fgets(s->species, MAX_SPECIES_NAME_LENGTH, f) == NULL) {
        return 0;
    }

    // finish string at '\n' if there is one
    char *newline_ptr = strchr(s->species, '\n');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }

    // also finish string at '\r' if there is one - files from Windows  will
    newline_ptr = strchr(s->species, '\r');
    if (newline_ptr != NULL) {
        *newline_ptr = '\0';
    }
    return 1;
}


// print array of sightings to filename

void write_sightings_file(char filename[], int n_sightings, struct pod sightings[n_sightings]) {
    FILE *f = fopen(filename, "w");
    if (f == NULL) {
        fprintf(stderr,"error: file '%s' can not open\n", filename);
        exit(1);
    }
    int i = 0;
    while (i < n_sightings) {
        write_sighting(f, &sightings[i]);
        i = i + 1;
    }
    fclose(f);
}


// print pod details to stream f

void write_sighting(FILE *f, struct pod *s) {
    write_date(f, &(s->when));
    fprintf(f, " %2d %s\n", s->how_many, s->species);
}


// return 1 if a date can be read, 0 otherwise

int read_date(FILE *f, struct date *d) {
    int n_scanned = fscanf(f, "%d/%d/%d", &(d->year), &(d->month), &(d->day));
    return n_scanned == 3;
}


// print date to  stream f

void write_date(FILE *f, struct date *d) {
    fprintf(f, "%02d/%02d/%02d", d->year, d->month, d->day);
}