CITS2002 Systems Programming  
 

Unit home

Final exam

help2002

Lecture & Workshop
recordings on LMS

Schedule

FAQ

C textbooks

OS textbooks

Information resources


Extra reading

Past projects

Recent feedback


Working effectively

Look after yourself!

Solutions for Labsheet 4 - for the week commencing 18th September 2023

Tasks

  1. Write a function named money that accepts a single integer parameter that represents a total number of cents, and breaks the total down into its numbers of dollars and cents. Your function should calculate the number of dollars, and the number of "left-over" cents, and provide these to its calling function through its parameters. For example, a value of 524 should be "returned" as 5 dollars and 24 cents.

    void money(int total, int *dollars, int *cents) { *dollars = total / 100; *cents = total % 100; }

  2. Write a function named maximum_a() that accepts an integer array and the number of elements in that array as parameters, returning a pointer to the maximum integer in the array.

    int *maximum_a(int values[], int n) { int index_of_max = 0; for(int i=1 ; i<n ; ++i) { if(values[index_of_max] < values[i]) { index_of_max = i; } } return &values[index_of_max]; }

  3. Write a (very similar) version that now accepts the integer array as a pointer.
    Use pointer arithmetic to complete this task.

    int *maximum_p(int *values, int n) { int *address_of_max = values++; for(int i=1 ; i<n ; ++i) { if(*address_of_max < *values) { address_of_max = values; } ++values; } return address_of_max; }

  4. String functions.

    strcat:
    // The strcat() function implemented using arrays char *strcat_a(char dest[], char src[]) { char *orig = dest; int d=0, s=0; while(dest[d] != '\0') { ++d; } while(src[s] != '\0') { dest[d] = src[s]; ++s; ++d; } dest[d] = '\0'; return orig; }
    // The strcat() function re-implemented using pointers char *strcat_p(char *dest, char *src) { char *orig = dest; while(*dest != '\0') { ++dest; } while(*src != '\0') { *dest = *src; ++dest; ++src; } *dest = '\0'; return orig; }

    strcmp:
    // The strcmp() function implemented using arrays int strcmp_a(char s1[], char s2[]) { int i=0; while(s1[i] != '\0' && s1[i] == s2[i]) { ++i; } return (s2[i] - s1[i]); }
    // The strcmp() function re-implemented using pointers int strcmp_p(char *s1, char *s2) { while(*s1 != '\0' && *s1 == *s2) { ++s1; ++s2; } return (*s2 - *s1); }

    strncmp:
    // The strncmp() function implemented using arrays int strncmp_a(char s1[], char s2[], size_t n) { int i=0; while(n > 0 && s1[i] != '\0' && s1[i] == s2[i]) { ++i; --n; } return (s2[i] - s1[i]); }
    // The strncmp() function re-implemented using pointers int strncmp_p(char *s1, char *s2, size_t n) { while(n > 0 && *s1 != '\0' && *s1 == *s2) { ++s1; ++s2; --n; } return (*s2 - *s1); }

    strrchr:
    // The strrchr() function implemented using arrays #define NOTFOUND (-1) char *strrchr_a(char s1[], int ch) { int i=0, found = NOTFOUND; while(s1[i] != '\0') { if(s1[i] == ch) found = i; ++i; } if(found == NOTFOUND) { return NULL; } else { return &s1[found]; } } #undef NOTFOUND
    // The strrchr() function re-implemented using pointers char *strrchr_p(char *s1, int ch) { char *found = NULL; while(*s1 != '\0') { if(*s1 == ch) found = s1; ++s1; } return found; }

  5. A concordance is a list of significant words appearing in a body of text. The word list only includes "true" words, consisting of alphabetic characters, after all whitespace and punctuation have been discarded.

    A sample solution: concordance-basic.c

  6. 🌶 Extend your concordance program to also count and print the frequency with which each word is found. For example, the textfile baseball.txt contains the word 'base' 18 times, and the word 'ball' 31 times.

    The simplest way to implement this task is to employ a structure to manage each word found. The structure will need to store a copy (a duplicate) of each word found, and an integer count of how many times the word is found. While the sample solution employs an array of character pointers to store the words, your extended solution will now need to employ an array of structures.

    These are the required changes (should be no need to change any other code):

    // OUR CONCORDANCE IS AN ARRAY OF STRUCTURES, WITH EACH HOLDING // A COPY/DUPLICATE OF EACH WORD AND THE NUMBER OF TIMES SEEN struct { char *word; int count; } *words = NULL; // initialising to NULL allows us to use realloc() int nwords = 0; // ITERATE THROUGH OUR CONCORDANCE, PRINTING EACH WORD AND ITS COUNT void print_words(void) { for(int w=0 ; w < nwords ; ++w) { printf("%i\t%s\n", words[w].count, words[w].word); } } // ADD A NEW WORD TO CONCORDANCE (PROVIDED THAT WE DON'T ALREADY HAVE IT) void add_word(char newword[]) { for(int w=0 ; w < nwords ; ++w) { if(strcmp(words[w].word, newword) == 0) { // we have it words[w].count += 1; // increment times seen return; } } // GROW/EXTEND OUR CONCORDANCE BY ALLOCATING SPACE FOR ONE MORE STRUCTURE words = realloc(words, (nwords+1)*sizeof(words[0])); // SAVE A POINTER TO NEWLY ALLOCATED MEMORY HOLDING A CLONE/DUPLICATE OF WORD words[nwords].word = strdup(newword); // INITIALISE THIS WORD'S COUNT TO ONE words[nwords].count = 1; ++nwords; }

  7. A sample solution: concordance-counts.c

  8. 🌶🌶 Write a filter program named reverse, which prints out the lines of a text file in reverse order - the last line is printed first, and the first line is printed last. Ensure that your program can operate on files named on the command-line, and from text lines arriving via stdin.

    // A SOLUTION USING DYNAMIC MEMORY ALLOCATION void reverse1(FILE *fp) { char **lines = NULL; // pointer to a vector of lines int nlines = 0; // number of lines in file char line[BUFSIZ]; // holds each line of the file // READ LINES FROM FILE, EXTEND THE VECTOR OF LINES, DUPLICATE CURRENT LINE while(fgets(line, sizeof line, fp) != NULL) { lines = realloc(lines, (nlines+1) * sizeof(lines[0])); if(lines == NULL) { // was allocation successful? fprintf(stderr, "realloc() failed\n"); exit(EXIT_FAILURE); } lines[nlines] = strdup(line); // save copy of current line if(lines[nlines] == NULL) { // was allocation successful? fprintf(stderr, "strdup() failed\n"); exit(EXIT_FAILURE); } ++nlines; } // PRINT THE LINES IN THEIR REVERSE ORDER for(int i=nlines-1 ; i>= 0 ; --i) { printf("%s", lines[i]); } // DEALLOCATE THE MEMORY HOLDING THE LINES for(int i=0 ; i<nlines; ++i) { free(lines[i]); } free(lines); } // A SOLUTION USING RECURSION void reverse2(FILE *fp) { char line[BUFSIZ]; if(fgets(line, sizeof line, fp) != NULL) { reverse2(fp); fputs(line, stdout); } } int main(int argc, char *argv[]) { // ATTEMPT TO OPEN AND READ FROM PROVIDED FILENAME if(argc > 1) { FILE *fp = fopen(filename, "r"); if(fp == NULL) { fprintf(stderr, "cannot open %s\n", filename); exit(EXIT_FAILURE); } reverse1(fp); rewind(fp); // works with files, but not with stdin reverse2(fp); fclose(fp); } // NO FILENAME PROVIDED, READ FROM STANDARD-INPUT else { reverse1(stdin); } return 0; }

The University of Western Australia

Computer Science and Software Engineering

CRICOS Code: 00126G
Presented by [email protected]