|
Solutions for Labsheet 4 - for the week commencing 18th September 2023
Tasks
- 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;
}
- 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];
}
- 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;
}
- 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;
}
|
-
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
- 🌶
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;
}
|
A sample solution: concordance-counts.c
- 🌶🌶
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;
}
|
|