Week 08 Laboratory Sample Solutions
Objectives
- working with strings
- simple pointers
Activities To Be Completed
The following is a list of all the activities available to complete this week...
Worth 0.7 mark(s) in total:
- string_match
- print_address
- debug_increment
Worth 0.7 mark(s) in total:
- string_reverse
- swap_case
- substitution
For your interest, but not for marks:
- punctuated_palindrome
- frequency_analysis
Lab Exercises are capped at 15 marks. Marks may be deducted from your weekly lab scores at the end of term if you have not actively participated in the group presentations during Lab sessions.
For more details, see the course outline.
Exercise
(●◌◌)
:
String Match
Your job is to write a program called string_match.c
which lets us count the
number of times we see our "search term" in a list of strings.
TASK 1 Scan in the "search term"
TASK 2: Scan in strings from standard input until Ctrl-D is pressed.
TASK 3: Count the number of times the "search term" appear in the input.
Examples
dcc string_match.c -o string_match ./string_match Enter the search term: same Enter the list of strings: same sand same send shade same shadow There was 3 occurrence(s) of the search term in the input. ./string_match Enter the search term: An ostrich's eye is bigger than its brain. Enter the list of strings: That is a cool fact. I never knew that! An ostrich's eye is bigger than its brain. ostrich? Why the random facts? There was 1 occurrence(s) of the search term in the input. ./string_match Enter the search term: 42 is the meaning of life, the universe, and everything Enter the list of strings: The ascii for * is 42 42 is the meaning of life, the universe, and everything!!! 42 = everything There was 0 occurrence(s) of the search term in the input.
Assumptions/Restrictions/Clarifications
- You can assume that each string will be no longer than 128 characters long
- You may find the
strcmp()
function useful
1091 style string_match.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest string_match
When you are finished working on this exercise,
you must
submit your work by running give
:
give dp1091 lab08_string_match string_match.c
You must run give
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
Note that this is an individual exercise,
the work you submit with give
must be entirely your own.
string_match.c
// string_match.c
// Searches for words in standard input until ctrl + d is pressed
// that match any of the given search term
// Written by Sofia De Bellis, z5418801, on July 2023
#include <stdio.h>
#include <string.h>
#define MAX_WORD_LEN 128
int main(void) {
printf("Enter the search term: ");
char search_term[MAX_WORD_LEN];
fgets(search_term, MAX_WORD_LEN, stdin);
printf("Enter the list of strings:\n");
int total = 0;
char buf[MAX_WORD_LEN];
while (fgets(buf, MAX_WORD_LEN, stdin) != NULL) {
if (strcmp(buf, search_term) == 0) {
total++;
}
}
printf("There was %d occurrence(s) of the search term in the input.\n",
total);
return 0;
}
Exercise
(●◌◌)
:
Print Address
Download print_address.c here
Or, copy these file(s) to your CSE account using the following command:
1091 fetch-activity print_addressIn this activity, you will complete the C program
print_address.c
which attempts to print a memory address and value at that address, using pointers.
In main
, you are provided with a variable number
of type int
and a supposed pointer to number
called number_pointer
.
Your main
should do the following;
- Correctly initialise the pointer
number_pointer
to point to the address ofnumber
. In the provided code, the pointer is declared incorrectly, you will need to fix this before you can initialise it. - Print the memory address stored in
number_pointer
. - Call the function
print_at_address
and pass the memory address stored innumber_pointer
to it.
The print_at_address
will need to be implemented by you and it should;
- Print the memory address passed to it.
- Print the value at that memory address.
You must not change the function signature of print_at_address
.
Examples
dcc print_address.c -o print_address ./print_address Passing the memory address 0x16b44b028 to the function The memory address passed to this function is 0x16b44b028 The value at the memory address is 42
Assumptions/Restrictions/Clarifications
- You must not change the function signature of
print_at_address
. - You must use the function
print_at_address
to print the second and third lines of the output.
1091 style print_address.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest print_address
When you are finished working on this exercise,
you and your lab partner must both
submit your work by running give
:
give dp1091 lab08_print_address print_address.c
Note, even though this is a pair exercise,
you both must run give
from your own account
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
print_address.c
// Print the memory address of a variable
// Created by: Ibrahim Ghoneim z5470570 03/2024
// print_at_address.c
#include <stdio.h>
void print_at_address(int *memory_address);
int main(void) {
int number = 42;
////////////////////////////////////////////////////////////////////////////
////////////////////////// ONLY MODIFY CODE BELOW //////////////////////////
////////////////////////////////////////////////////////////////////////////
int *number_pointer = &number;
printf("Passing the memory address %p to the function\n", number_pointer);
print_at_address(number_pointer);
return 0;
}
/*
param: memory_address - is an integer pointer that points to a memory address
return: void
Prints the memory address and the value at the memory address
*/
void print_at_address(int *memory_address) {
printf("The memory address passed to this function is %p\n", memory_address);
printf("The value at the memory address is %d\n", *memory_address);
return;
}
Exercise
(●◌◌)
:
Debugging - increment
Download debug_increment.c here
Or, copy these file(s) to your CSE account using the following command:
1091 fetch-activity debug_increment
Debugging Tips!
Some debugging tips for you:
- dcc output - as you run into issues, dcc will point you to where the errors are. Remember that dcc gives you the line number the issue is on, and will give some sort of explanation. Make sure you read everything dcc gives you. Sometimes we get “errors carried forward”, so find your first error, fix that, then recompile.
- print statements - sometimes it can be handy to see if the flow of your code puts you in the spot you expect it to be (ie. inside the right if statement, or going through a loop the correct amount of times). A quick way you can check this is by putting print statements in your code for testing purposes, like
"the value of x is %d and y is %d"
. This lets you check that you got against what you expected. - DPST1091 debugging guide
The Task
This exercise takes in a number and intends to increment the value of the number using a function increment()
, which takes a pointer to an integer as its parameter.
Currently it has some issues - it is your job to figure them out and fix the code.
Examples
dcc debug_increment.c -o debug_increment ./debug_increment Please enter a number: 1 Before increment: 1 After increment: 2 ./debug_increment Please enter a number: -8 Before increment: -8 After increment: -7 ./debug_increment Please enter a number: 100 Before increment: 100 After increment: 101
1091 style debug_increment.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest debug_increment
When you are finished working on this exercise,
you must
submit your work by running give
:
give dp1091 lab08_debug_increment debug_increment.c
You must run give
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
Note that this is an individual exercise,
the work you submit with give
must be entirely your own.
debug_increment.c
// debug_pointers.c
// This program given a number, incraments it using pointers
// Written by Sofia De Bellis, z5418801 on July 2023
#include <stdio.h>
void increment(int *ptr);
int main() {
int num;
printf("Please enter a number: ");
scanf("%d", &num);
int *ptr = #
printf("Before increment: %d\n", *ptr);
increment(ptr);
printf("After increment: %d\n", *ptr);
return 0;
}
void increment(int *ptr) {
(*ptr)++;
}
Exercise
(●●◌)
:
Reverse the contents of a string
string_reverse
.
It takes a string and reverses it in place.
Download string_reverse.c here, or copy it to your CSE account using the following command:
cp -n /import/reed/A/dp1091/public_html/25T2/activities/string_reverse/string_reverse.c .
Your task is to add code to this function in string_reverse.c:
// Takes a string in `buffer`, and reverses it in-place.
void string_reverse(char *buffer) {
// YOUR CODE GOES HERE!
}
int main(int argc, char *argv[]) {
// NOTE: THIS WON'T WORK:
// char *str = "Hello!"
// string_reverse(str)
//
// str only points to a string literal, which it is not legal to change.
// If you attempt to modify it on Linux you will get a runtime error.
// Instead, you need to create an array to store the string in, e.g.:
//
// char str[] = "Hello!"
// string_reverse(str)
char str[] = ".'neetneves' :egassem terces A";
string_reverse(str);
printf("%s\n", str);
return 0;
}
Your string_reverse function will be called directly in marking. The main function is only to let you test your string_reverse function
Here is how string_reverse.c should behave after you add the correct code to the function string_reverse:
dcc string_reverse.c -o string_reverse ./string_reverse A secret message: 'seventeen'.
1091 style string_reverse.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest string_reverse
When you are finished working on this exercise,
you must
submit your work by running give
:
give dp1091 lab08_string_reverse string_reverse.c
You must run give
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
Note that this is an individual exercise,
the work you submit with give
must be entirely your own.
string_reverse.c
// gnirts a esreveR (Reverse a string)
// A sample solution.
#include <stdio.h>
void string_reverse(char *buffer);
int string_length(char *string);
int main(int argc, char *argv[]) {
// NOTE: THIS WON'T WORK:
// char *str = "Hello!"
// string_reverse(str)
//
// str only points to a string literal, which it is not legal to change.
// If you attempt to modify it on Linux you will get a runtime error.
// Instead, you need to create an array to store the string in, e.g.:
//
// char str[] = "Hello!"
// string_reverse(str)
char str[] = ".'neetneves' :egassem terces A";
string_reverse(str);
printf("%s\n", str);
return 0;
}
// Takes a string in `buffer`, and reverses it in-place.
void string_reverse(char *buffer) {
int length = string_length(buffer);
int i = 0;
while (i < length/2) {
// swap array elements
char tmp = buffer[i];
buffer[i] = buffer[length - i - 1];
buffer[length - i - 1] = tmp;
i = i + 1;
}
}
// Takes a string and finds its length, excluding the null-terminator.
int string_length(char *string) {
int i = 0;
while (string[i] != '\0') {
i = i + 1;
}
return i;
}
Exercise
(●●◌)
:
Swap the case of letters in a string.
Download swap_case.c here
Or, copy these file(s) to your CSE account using the following command:
1091 fetch-activity swap_case
Your task is to add code to this function in swap_case.c:
int swap_case(int character) {
// TODO: Write this function, which should:
// - return character in lower case if it is an upper case letter
// - return character in upper case if it is an lower case letter
// - return the character unchanged otherwise
return 'x';
}
Edit the C program swap_case.c
(linked above) which reads characters from its
input and writes the same characters to its output with lower case letters
converted to upper case and upper case letters converted to lower case.
Your program should stop only at the end of input.
which:
- returns the character in lowercase if it is an uppercase letter
- returns the character in uppercase if it is a lowercase letter
- returns the character unchanged otherwise
Note: Your program will not pass autotests if it does not contain this function.
Examples
dcc swap_case.c -o swap_case ./swap_case Are you saying 'Boo' or 'Boo-Urns'? aRE YOU SAYING 'bOO' OR 'bOO-uRNS'? In this house, we obey the laws of thermodynamics! iN THIS HOUSE, WE OBEY THE LAWS OF THERMODYNAMICS! UPPER !@#$% lower upper !@#$% LOWER
Assumptions/Restrictions/Clarifications
- You need only a single int variable. Don't use an array.
- Make sure you understand this example program which reads characters until end of input.
- Make sure you understand this example program which reads characters, printing them with lower case letters converted to uppercase.
1091 style swap_case.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest swap_case
When you are finished working on this exercise,
you must
submit your work by running give
:
give dp1091 lab08_swap_case swap_case.c
You must run give
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
Note that this is an individual exercise,
the work you submit with give
must be entirely your own.
swap_case.c
// Written 3/3/2018 by Andrew Taylor (andrewt@unsw.edu.au)
// Write stdin to stdout with upper case letters converted to lower case
// and lower case converted to upper case
//
#include <stdio.h>
#include <stdlib.h>
int swap_case(int character);
int main(int argc, char *argv[]) {
int character = getchar();
while (character != EOF) {
int swapped_character = swap_case(character);
putchar(swapped_character);
character = getchar();
}
return 0;
}
int swap_case(int character) {
if (character >= 'A' && character <= 'Z') {
return 'a' + character - 'A';
} else if (character >= 'a' && character <= 'z') {
return 'A' + character - 'a';
} else {
return character;
}
}
Exercise
(●●◌)
:
Encrypting Text with a Substitution Cipher
Write a C program substitution.c
which reads characters from its input and
writes the characters to its output encrypted with a
Substitution cipher.
A Substitution cipher maps each letter to another letter.
The mapping will be given to your program via the command line as a command line argument
(no spaces between any characters). This is all on one line. This input will contain 26
characters: an ordering of the letters 'a'..'z'
.
Characters other than letters should not be encrypted.
Your program should stop only at the end of input.
Your program should contain at least one function other than main.
Examples
dcc substitution.c -o substitution ./substitution qwertyuiopasdfghjklzxcvbnm Enter text: I was scared of dentists and the dark O vql leqktr gy rtfzolzl qfr zit rqka I was scared of pretty girls and starting conversations O vql leqktr gy hktzzn uoksl qfr lzqkzofu egfctklqzogfl ./substitution abcdefghijklmnopqrstuvwxyz Enter text: The identity cipher!!! The identity cipher!!! ./substitution bcdefghijklmnopqrstuvwxyza Enter text: The Caesar cipher is a subset of the substitution cipher! Uif Dbftbs djqifs jt b tvctfu pg uif tvctujuvujpo djqifs!
Your program will only be tested with an appropriate and valid mapping input for marking - but a good programmer would check the input is present and appropriate.
1091 style substitution.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest substitution
When you are finished working on this exercise,
you must
submit your work by running give
:
give dp1091 lab08_substitution substitution.c
You must run give
before Monday 07 July 09:00
to obtain the marks for this lab exercise.
Note that this is an individual exercise,
the work you submit with give
must be entirely your own.
substitution.c
// Substitution.c
// Write stdin to stdout encrypted with a Substitution cipher
// https://en.wikipedia.org/wiki/Substitution_cipher
//
// The mapping will be supplied as a command-line argument containing 26 characters:
// These will be an an ordering of the letters 'a'..'z'.
//
// Written 3/3/2018 by Andrew Taylor (andrewt@unsw.edu.au)
// and adapted for 23T2 by Sofia De Bellis, z5418801 on July 2023
#include <stdio.h>
#include <string.h>
#define ALPHABET_SIZE 26
int encrypt(char character, char mapping[ALPHABET_SIZE]);
int main(int argc, char *argv[]) {
char mapping[ALPHABET_SIZE + 1];
for (int i = 0; i < ALPHABET_SIZE; i++) {
mapping[i] = argv[1][i];
}
mapping[ALPHABET_SIZE] = '\0';
// Error checking - not necessary in student solution or tested
if (mapping[0] == '\0') {
printf("Usage: ./substitution <mapping>\n");
return 1;
}
if (strlen(mapping) != ALPHABET_SIZE) {
printf("./substitution: mapping must contain %d letters\n", ALPHABET_SIZE);
return 1;
}
printf("Enter text:\n");
char character;
while (scanf("%c", &character) == 1) {
int encrypted_character = encrypt(character, mapping);
printf("%c", encrypted_character);
}
return 0;
}
// encrypt letters with a substitution cipher with the specified mapping
int encrypt(char character, char mapping[ALPHABET_SIZE]) {
if (character >= 'A' && character <= 'Z') {
return mapping[character - 'A'] - 'a' + 'A';
} else if (character >= 'a' && character <= 'z') {
return mapping[character - 'a'];
} else {
return character;
}
}
Exercise
(●●●)
:
Is it a Palindrome - the Sequel
punctuated_palindrome.c
, which reads a string and tests if
it is a palindrome.
Characters which are not letters should be ignored .
Differences between upper case and lower case are ignored. For example:
./punctuated_palindrome Enter a string: Do geese see God? String is a palindrome ./punctuated_palindrome Enter a string: Do ducks see God? String is not a palindrome ./punctuated_palindrome Enter a string: Madam, I'm Adam String is a palindrome ./punctuated_palindrome Enter a string: Madam, I'm Andrew String is not a palindromeHint: you might find C library functions in
#include <ctype.h>
useful.
You can assume lines contain at most 4096 characters.
1091 style punctuated_palindrome.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest punctuated_palindrome
punctuated_palindrome.c
// Read a string and then print the letters one per line
// written by Andrew Taylor andrewt@cse.unsw.edu.au
// April 2018 as a COMP1511 lab exercise
//
#include <stdio.h>
#include <ctype.h>
#define MAXLINE 5000
int is_palindrome(char line[]);
int main(void) {
char line[MAXLINE] = {0};
printf("Enter a string: ");
fgets(line, MAXLINE, stdin);
if (is_palindrome(line)) {
printf("String is a palindrome\n");
} else{
printf("String is not a palindrome\n");
}
return 0;
}
// return 1 is line is palindromic, 0 otherwise
// line is terminated by either '\n' or '\0'
// case and non-alphabetic characters are ignored
// an empty line is considered a palindrome
int is_palindrome(char line[]) {
int right = 0;
while (line[right] != '\0' && line[right] != '\n') {
right = right + 1;
}
right = right - 1;
int left = 0;
while (left < right) {
int left_char = tolower(line[left]);
int right_char = tolower(line[right]);
if (!isalpha(left_char)) {
left = left + 1;
} else if (!isalpha(right_char)) {
right = right - 1;
} else if (left_char != right_char) {
return 0;
} else {
left = left + 1;
right = right - 1;
}
}
return 1;
}
Exercise
(●●●)
:
Frequency Analysis
Write a C program frequency_analysis.c
which reads characters from its input
until end of input.
It should then print the occurrence frequency for each of the 26 letters
'a'..'z'
.
The frequency should be printed as a decimal value and an absolute number in exactly the format below.
Note upper and lower case letters are counted together.
Examples
dcc frequency_analysis.c -o frequency_analysis ./frequency_analysis Hello and goodbye. 'a' 0.066667 1 'b' 0.066667 1 'c' 0.000000 0 'd' 0.133333 2 'e' 0.133333 2 'f' 0.000000 0 'g' 0.066667 1 'h' 0.066667 1 'i' 0.000000 0 'j' 0.000000 0 'k' 0.000000 0 'l' 0.133333 2 'm' 0.000000 0 'n' 0.066667 1 'o' 0.200000 3 'p' 0.000000 0 'q' 0.000000 0 'r' 0.000000 0 's' 0.000000 0 't' 0.000000 0 'u' 0.000000 0 'v' 0.000000 0 'w' 0.000000 0 'x' 0.000000 0 'y' 0.066667 1 'z' 0.000000 0 ./frequency_analysis Hey! Hey! Hey! I don't like walking around this old and empty house So hold my hand, I'll walk with you my dear 'a' 0.072289 6 'b' 0.000000 0 'c' 0.000000 0 'd' 0.084337 7 'e' 0.084337 7 'f' 0.000000 0 'g' 0.012048 1 'h' 0.096386 8 'i' 0.072289 6 'j' 0.000000 0 'k' 0.036145 3 'l' 0.084337 7 'm' 0.036145 3 'n' 0.060241 5 'o' 0.084337 7 'p' 0.012048 1 'q' 0.000000 0 'r' 0.024096 2 's' 0.036145 3 't' 0.048193 4 'u' 0.036145 3 'v' 0.000000 0 'w' 0.036145 3 'x' 0.000000 0 'y' 0.084337 7 'z' 0.000000 0
Hint: use an array to store counts of each letter.
Hint: make sure you understand this example program which counts integers from the range 0..99.
Manually Cracking a Substitution Cipher
This English text was encrypted with a substitution cipher.
Di jd, vdl'ht xtqa dh O qn Vdl rdlwk O'ss wdkith htqromu omkd ok O fhdwqwsv xdm'k Styk kd nv dxm rtzoetj Wlk kiqk'j kit royythtmet om dlh dfomodmj Vdl'ht q ndlkiyls Kiqk qndlmkj ydh qmdkith xtta dm nv dxm Mdx O'n q mdzts nqrt htjdlhetyls O jkqhk q eiqom xoki nv kidluik Kqsa oj eitqf, nv rqhsomu Xitm vdl'ht yttsomu houik qk idnt O xqmmq nqat vdl ndzt xoki edmyortmet O xqmmq wt xoki vdl qsdmt
What was the original text?
Mapping: qwertyuiopasnmdfghjklzxcvb
Oh so, you're weak or I am You doubt I'll bother reading into it I probably won't Left to my own devices But that's the difference in our opinions You're a mouthful That amounts for another week on my own Now I'm a novel made resourceful I start a chain with my thought Talk is cheap, my darling When you're feeling right at home I wanna make you move with confidence I wanna be with you alone
1091 style frequency_analysis.c
When you think your program is working,
you can use autotest
to run some simple automated tests:
1091 autotest frequency_analysis
frequency_analysis.c
// Written 3/3/2018 by Andrew Taylor (andrewt@unsw.edu.au)
// Read characters from stdin until of input then print the frequency of letters
#include <stdio.h>
#define NOT_A_LETTER (-1)
#define ALPHABET_SIZE 26
int get_letter_frequencies(int letter_count[ALPHABET_SIZE]);
int letter_index(int character);
void print_frequencies(int letter_count[ALPHABET_SIZE], int n_letters_read);
int main(int argc, char *argv[]) {
int letter_count[ALPHABET_SIZE] = {0}; // 1 array element for each English letter
int n_letters_read = get_letter_frequencies(letter_count);
print_frequencies(letter_count, n_letters_read);
return 0;
}
// read characters from stdin, and for uppercase and lower case letters updating
// accumulating count a letter_count in letter_frequencies
// number of uppercase and lower case letters read is returned
int get_letter_frequencies(int letter_count[ALPHABET_SIZE]) {
char character;
int n_letters_read = 0;
while (scanf(" %c", &character) == 1) {
int index = letter_index(character);
if (index != NOT_A_LETTER) {
letter_count[index] = letter_count[index] + 1;
n_letters_read = n_letters_read + 1;
}
}
return n_letters_read;
}
// return position of letter in English alphabet (0..25)
// for lower case and upper case letter
// return NOT_A_LETTER for other characters
int letter_index(int character) {
if (character >= 'A' && character <= 'Z') {
return character - 'A';
} else if (character >= 'a' && character <= 'z') {
return character - 'a';
} else {
return NOT_A_LETTER;
}
}
void print_frequencies(int letter_count[ALPHABET_SIZE], int n_letters_read) {
if (n_letters_read == 0) {
return;
}
int i = 0;
while (i < ALPHABET_SIZE) {
printf("'%c' %lf %d\n", 'a'+i, letter_count[i]/(double)n_letters_read, letter_count[i]);
i = i + 1;
}
}
Submission
give
.
You only need to do this if the exercise specifies a give command, otherwise - the exercise is not worth marks.
You can run give
multiple times.
Only your last submission will be marked.
Don't submit any exercises you haven't attempted.
If you are working at home, you may find it more convenient to upload your work via give's web interface.
Remember you have until Week 9 Monday 9:00am to submit your work.
You cannot obtain marks by e-mailing your code to tutors or lecturers.
You check the files you have submitted here.
Automarking will be run by the lecturer several days after the submission deadline,
using test cases different to those autotest
runs for you.
(Hint: do your own testing as well as running autotest
.)
After automarking is run by the lecturer you can view your results here. The resulting mark will also be available via give's web interface.
Lab Marks
When all components of a lab are automarked you should be able to view the the marks via give's web interface or by running this command on a CSE machine:
1091 classrun -sturec
Voice of the Student
✨ Help Us Improve Your Learning Experience ✨
Your feedback helps us understand what’s working well and what might need improvement.
This quick, anonymous check-in has just two questions and takes less than a minute to complete.
Please answer honestly — your input makes a real difference.