Q1
// Written by Angela Finlayson
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
int data;
};
int sum_divisible(struct node *head1, struct node *head2);
struct node *strings_to_list(int len, char *strings[]);
int main(int argc, char *argv[]) {
// create two linked lists from command line arguments
int dash_arg = argc - 1;
while (dash_arg > 0 && strcmp(argv[dash_arg], "-") != 0) {
dash_arg = dash_arg - 1;
}
struct node *head1 = strings_to_list(dash_arg - 1, &argv[1]);
struct node *head2 = strings_to_list(argc - dash_arg - 1, &argv[dash_arg + 1]);
int result = sum_divisible(head1, head2);
printf("%d\n", result);
return 0;
}
// sum the elements in list1 that are divisible by the
// the corresponding element in list2
// if one list is longer than the other, the extra list elements are ignored
int sum_divisible(struct node *head1, struct node *head2) {
if (!head1 || !head2) {
return 0;
} else {
if(head1->data % head2->data == 0)
return head1->data + sum_divisible(head1->next, head2->next);
else
return sum_divisible(head1->next, head2->next);
}
}
// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
struct node *head = NULL;
for (int i = len - 1; i >= 0; i = i - 1) {
struct node *n = malloc(sizeof (struct node));
assert(n != NULL);
n->next = head;
n->data = atoi(strings[i]);
head = n;
}
return head;
}
Q2
#include <stdio.h>
#define MAX_COLS 100
char min_lowercase(int size, char array[MAX_COLS]);
// This is a simple main function which could be used
// to test your min_lowercase function.
// It will not be marked.
// Only your min_lowercase function will be marked.
int main(int argc, char *argv[]) {
char test_array[MAX_COLS] = {'a', 'B', 'c', 'D', '!'};
int result = min_lowercase(5, test_array);
printf("%c\n", result);
return 0;
}
// Returns the lowercase character with the lowest ASCII value from the array.
char min_lowercase(int size, char array[MAX_COLS]) {
char min_letter = 'z';
for (int i = 0; i < size; i++) {
if (array[i] >= 'a' && array[i] <= 'z' && array[i] < min_letter) {
min_letter = array[i];
}
}
return min_letter;
}
Q3
// Written by Tammy Zhong
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
char data;
};
struct node *insert_alphabet_after(char ch, struct node *head);
struct node *strings_to_list(int len, char *strings[]);
void print_list(struct node *head);
struct node *insert_alphabet_after(char ch, struct node *head) {
if (head == NULL) {
struct node *new = malloc(sizeof(struct node));
new->data = ch;
new->next = NULL;
return new;
}
struct node *current = head;
while (current != NULL) {
if (current->data + 1 == ch) {
struct node *new = malloc(sizeof(struct node));
new->data = ch;
new->next = NULL;
new->next = current->next;
current->next = new;
}
current = current->next;
}
return head;
}
int main(int argc, char *argv[]) {
char value;
scanf(" %c", &value);
// create linked list from command line arguments
struct node *head = NULL;
if (argc > 1) {
// list has elements
head = strings_to_list(argc - 1, &argv[1]);
}
struct node *new_head = insert_alphabet_after(value, head);
print_list(new_head);
return 0;
}
// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
struct node *head = NULL;
int i = len - 1;
while (i >= 0) {
struct node *n = malloc(sizeof (struct node));
assert(n != NULL);
n->next = head;
n->data = strings[i][0];
head = n;
i -= 1;
}
return head;
}
// print linked list
void print_list(struct node *head) {
printf("[");
struct node *n = head;
while (n != NULL) {
// If you're getting an error here,
// you have returned an invalid list
printf("%c", n->data);
if (n->next != NULL) {
printf(", ");
}
n = n->next;
}
printf("]\n");
}
Q4
// Written by Jake Renzella
#include <stdio.h>
#define MAX_ROWS 100
int vowels_exactly_balanced(int size, char *array[MAX_ROWS]);
// This is a simple main function which could be used
// to test your vowels_exactly_balanced function.
// It will not be marked.
// Only your count_neutral_rows function will be marked.
int main(int argc, char *argv[]) {
char *test_arrray[MAX_ROWS] = {
"abUUcd",
"abcdUU",
"Abaa",
"asdaa",
};
char *test_arrray_2[MAX_ROWS] = {
"abcdaa",
"abcda",
"babau",
};
char *test_arr_3[MAX_ROWS] = {
"fgh",
"j",
"zxcvbnm",
};
int result = vowels_exactly_balanced(4, test_arrray);
printf("The vowels_exactly_balanced function returned: %d\n", result);
result = vowels_exactly_balanced(3, test_arrray_2);
printf("The vowels_exactly_balanced function returned: %d\n", result);
result = vowels_exactly_balanced(3, test_arr_3);
printf("%d\n", result);
return 0;
}
int vowels_exactly_balanced(int size, char *array[MAX_ROWS]) {
if (size <= 1) {
// 0 or 1 row is always balanced
return 1;
}
if (size > MAX_ROWS) {
// Error: size exceeds MAX_ROWS
return 0;
}
// Will store the first non-zero vowel count
int target_vowels = -1;
for (int row = 0; row < size; row++) {
int vowels = 0;
for (int col = 0; array[row][col] != '\0'; col++) {
char c = array[row][col];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U') {
vowels++;
}
}
if (target_vowels == -1) {
if (vowels > 0) {
target_vowels = vowels;
}
} else if (vowels != target_vowels) {
// Imbalance found, early return
return 0;
}
}
return 1; // No imbalances found
}
Q5
// Written by Sofia De Bellis
// This program scans in an integer representing a month of the year.
// It prints out a message to say what season the month is in Australia.
//
// Unfortunately, this code contains a number of errors. Please help fix it!
#include <stdio.h>
int main(void) {
int month; // BUG #0 - forgot to declare the variable
printf("Enter the month number (1-12): ");
scanf("%d", &month); // Bug #1 - forgot & before month
if (month < 1 || month > 12) { // BUG #1.5 >= 12 instead of > 12
printf("Invalid month entered.\n");
} else if (month >= 3 && month <= 5) { // Bug #2 - use || instead of &&
printf("It's autumn in Australia.\n");
} else if (month >= 6 && month <= 8) {
printf("It's winter in Australia.\n");
} else if (month >= 9 && month <= 11) {
printf("It's spring in Australia.\n");
} else { // Bug #3 - forgot to handle December, January, and February
printf("It's summer in Australia.\n");
}
return 0;
}
Q6
// Written by Sofia De Bellis
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
struct node {
// Bug: Missing semicolon using comma instead
struct node *next;
int data;
};
// compare_tens should return -1 if list1 has more tens than list2
// compare_tens should return 1 if list1 has less tens than list2
// compare_tens should return 0 if list1 has the same tens as list2
int compare_tens(struct node *head1, struct node *head2) {
// Bug: current1 and current2 should be a pointer
struct node *current1 = head1;
struct node *current2 = head2;
int count1 = 0;
int count2 = 0;
// Bug: current->next != NULL instead of current != NULL
while (current1 != NULL) {
// Bug: Using > instead of >= and < instead of <=
if (current1->data >= 10 && current1->data <= 99) {
count1++;
}
// Bug: not moving current correctly
current1 = current1->next;
}
while (current2 != NULL) {
// Bug: Using || instead of &&
if (current2->data >= 10 && current2->data <= 99) {
count2++;
}
current2 = current2->next;
}
if (count1 < count2) {
// Bug: Returning 1 for count1 < count2
return -1;
} else if (count1 > count2) {
// Bug: Returning -1 for count1 > count2
return 1;
}
return 0;
}
// DO NOT MODIFY THE CODE BELOW THIS LINE, THIS CODE ALLOWS YOU TO
// TAKE IN A LIST OF NUMBERS TO TEST WHETHER YOUR FUNCTION IS WORKING
struct node *strings_to_list(int len, char *strings[]);
// DO NOT CHANGE THIS FUNCTION
int main(int argc, char *argv[]) {
// create two linked lists from command line arguments
int dash_arg = argc - 1;
while (dash_arg > 0 && strcmp(argv[dash_arg], "-") != 0) {
dash_arg = dash_arg - 1;
}
struct node *head1 = strings_to_list(dash_arg - 1, &argv[1]);
struct node *head2 = strings_to_list(argc - dash_arg - 1, &argv[dash_arg + 1]);
int result = compare_tens(head1, head2);
printf("%d\n", result);
return 0;
}
// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *strings_to_list(int len, char *strings[]) {
struct node *head = NULL;
for (int i = len - 1; i >= 0; i = i - 1) {
struct node *n = malloc(sizeof (struct node));
assert(n != NULL);
n->next = head;
n->data = atoi(strings[i]);
head = n;
}
return head;
}
Q7
// Written By Sofia De Bellis
// The following code is meant to read in integers and print out the
// factorial of that integer until the user enters Ctrl + D.
// However, it contains a number of errors that you need to fix. Good luck!
// note: the factorial of a number is the product of all positive
// integers less than or equal to that number.
#include <stdio.h>
void compute_factorial(int number, int *factorial);
int main(void) {
int num1;
int factorial;
printf("Enter a number: ");
// Bug: scanf("%d", &num1) > 1 should be scanf("%d", &num1) == 1
while (scanf("%d", &num1) == 1) {
// Bug: *factorial should be &factorial
compute_factorial(num1, &factorial);
// Bug: %c should be %d and %lf should be %d
printf("The factorial of %d is %d\n", num1, factorial);
// Bug: missing prompt
printf("Enter a number: ");
}
return 0;
}
void compute_factorial(int number, int *factorial) {
// Bug: result should be initialised to 1
int res = 1;
// Bug: i++ should be i--
for (int i = number; i > 0; i--) {
res = res * i;
}
// Bug: factorial should be *factorial
*factorial = res;
return;
}
Q8
// Written by Nicole Luong
// This program should create and scan in the elements of a 3x3 2d array,
// then multiply all the odd numbers in the 2d array by 100.
//
// Unfortunately, this code contains a number of errors. Please help fix it!
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
int main(void) {
printf("Enter your numbers:\n");
int array[SIZE][SIZE]; // char instead of int
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) { // loop decrements
scanf("%d", &array[row][col]); // %c instead of $d
}
}
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if (array[row][col] % 2 != 0) { // swapped with the line above and [col] is replaced by another [row], and / instead of %
array[row][col] = array[row][col] * 100;
}
}
}
// ==================== DO NOT NEED TO EDIT BELOW HERE =====================
// There are no bugs in here, this is simply to assist in printing out
// the contents of the 2D array
printf("Converted:\n");
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
printf("%d ", array[row][col]);
}
printf("\n");
}
return 0;
}
Q9
// Written by Sofia De Bellis
#include <stdio.h>
#include <stdlib.h>
int rotation_shift_amount(char *str1, char *str2);
int my_strlen(char *str);
void my_strcat(char *dest, char *src);
char *my_strstr(char *haystack, char *needle);
int main(void) {
// This main function will not be used in testing.
// You may write code for testing your rotation_shift_amount function here.
printf("%d\n", rotation_shift_amount("waterbottle", "erbottlewat"));
return 0;
}
// Returns the shift amount needed to rotate s1 to s2
int rotation_shift_amount(char *str1, char *str2) {
// Get the length of both strings
int len1 = my_strlen(str1);
int len2 = my_strlen(str2);
// If lengths are not equal, s2 cannot be a rotation of s1
if (len1 != len2) {
return -1;
}
if (len1 == 0 && len2 == 0) {
return 0;
}
// Create a new string that is s1 concatenated with itself
char str1_str1[2 * len1 + 1];
for (int i = 0; i < len1; i++) {
str1_str1[i] = str1[i];
}
str1_str1[len1] = '\0';
my_strcat(str1_str1, str1);
// Find the position of s2 in the concatenated string
char *pos = my_strstr(str1_str1, str2);
if (pos != NULL) {
// Calculate the shift amount
int shift_amount = pos - str1_str1;
return shift_amount % len1;
} else {
return -1;
}
}
// Returns the length of a string
int my_strlen(char *str) {
int i = 0;
while (str[i] != '\0') {
i++;
}
return i;
}
// Concatenates src to dest
void my_strcat(char *dest, char *src) {
int i = my_strlen(dest);
int j = 0;
while (src[j] != '\0') {
dest[i] = src[j];
i++;
j++;
}
dest[i] = '\0';
}
// Returns a pointer to the first occurrence of the substring needle in the string haystack
char *my_strstr(char *haystack, char *needle) {
int i = 0;
int j = 0;
while (haystack[i] != '\0') {
if (haystack[i] == needle[j]) {
while (needle[j] != '\0' && haystack[i] == needle[j]) {
i++;
j++;
}
if (needle[j] == '\0') {
return &haystack[i - j];
}
i -= j;
j = 0;
}
i++;
}
return NULL;
}
Q10
// Written by Ben Briant
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 20
enum order_type {
BUY,
SELL
};
struct order {
enum order_type type;
int price;
int quantity;
struct order *next;
};
struct order *read_orders(void);
void match_orders(struct order *a, struct order *b) {
int lower;
if (a->quantity < b->quantity) {
lower = a->quantity;
} else {
lower = b->quantity;
}
a->quantity -= lower;
b->quantity -= lower;
}
void insert(struct order **orders, struct order *ins) {
if (*orders == NULL) {
*orders = ins;
return;
}
struct order *prev = NULL;
struct order *curr = *orders;
while (curr) {
if (ins->price > curr->price) {
if (!prev) {
*orders = ins;
} else {
prev->next = ins;
}
ins->next = curr;
return;
}
prev = curr;
curr = curr->next;
}
prev->next = ins;
ins->next = NULL;
}
void handle_buy(
struct order **bids, struct order **asks, struct order *buy_order) {
assert(buy_order->type == BUY);
struct order *prev = NULL;
struct order *ask = *asks;
while (ask && buy_order->quantity > 0) {
struct order *next = ask->next;
if (ask->price <= buy_order->price) {
match_orders(ask, buy_order);
}
if (ask->quantity <= 0) {
// remove ask
if (prev) {
prev->next = ask->next;
} else {
*asks = ask->next;
}
free(ask);
ask = prev;
}
prev = ask;
ask = next;
}
if (buy_order->quantity > 0) {
insert(bids, buy_order);
}
}
// Yes, this is the same as `handle_buy`, but with a sign flipped.
void handle_ask(
struct order **bids, struct order **asks, struct order *sell_order) {
assert(sell_order->type == SELL);
struct order *prev = NULL;
struct order *bid = *bids;
while (bid && sell_order->quantity > 0) {
struct order *next = bid->next;
if (bid->price >= sell_order->price) {
match_orders(sell_order, bid);
}
if (bid->quantity <= 0) {
// remove bid
if (prev) {
prev->next = bid->next;
} else {
*bids = bid->next;
}
free(bid);
bid = prev;
}
prev = bid;
bid = next;
}
if (sell_order->quantity > 0) {
insert(asks, sell_order);
}
}
void print_side(struct order *asks, char *type) {
if (!asks) {
return;
}
printf("%s %d items for $%d\n", type, asks->quantity, asks->price);
print_side(asks->next, type);
}
void free_orders(struct order *order) {
if (!order) {
return;
}
free_orders(order->next);
free(order);
}
int main(void) {
struct order *order_list = read_orders();
struct order *bids = NULL;
struct order *asks = NULL;
struct order *curr_order = order_list;
while (curr_order) {
struct order *next = curr_order->next;
curr_order->next = NULL;
if (curr_order->type == BUY) {
handle_buy(&bids, &asks, curr_order);
} else if (curr_order->type == SELL) {
handle_ask(&bids, &asks, curr_order);
}
curr_order = next;
}
print_side(asks, "SELL");
print_side(bids, "BUY");
free_orders(bids);
free_orders(asks);
return 0;
}
// This function reads in a list of orders, ending with either
// a blank line, or EOF.
// Returns: A pointer to the head of the linked list
struct order *read_orders(void) {
char line[MAX_LEN];
struct order *head = NULL;
struct order *tail = NULL;
while (fgets(line, MAX_LEN, stdin) != NULL && strcmp(line, "\n")) {
struct order *new = malloc(sizeof(struct order));
new->next = NULL;
char order_char;
sscanf(line, "%c %d %d", &order_char, &new->quantity, &new->price);
new->type = (order_char == 'b') ? BUY : SELL;
if (head != NULL) {
tail->next = new;
tail = new;
} else {
head = tail = new;
}
}
return head;
}
Q11
// Written by Sofia De Bellis & Ben Briant
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define MAX_LEN 1000
struct executable {
char executable_name[MAX_LEN];
struct file *files;
struct executable *next;
};
struct file {
char file_name[MAX_LEN];
struct file *next;
};
bool endswith_c(char *str) {
if (strlen(str) < 3) return false;
return strcmp(str + strlen(str) - 2, ".c") == 0;
}
bool startswith(char *str, char *prefix) {
char tmp_str[strlen(str) + 1];
strcpy(tmp_str, str);
char *dot = tmp_str;
while (*dot != '.' && *dot != '\0') {
dot++;
}
if (*dot == '\0') return false;
*dot = '\0';
return strcmp(tmp_str, prefix) == 0 && endswith_c(str);
}
void remove_newline(char *str) {
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}
}
char **tokenize_line(char *line, int *len) {
remove_newline(line);
char **tokens = NULL;
int i = 0;
for (char *token = strtok(line, " "); token != NULL;
token = strtok(NULL, " ")) {
tokens = realloc(tokens, (i + 1) * sizeof(char *));
tokens[i] = token;
i++;
}
*len = i;
return tokens;
}
bool prefix(const char *pre, const char *str) {
return strncmp(pre, str, strlen(pre)) == 0;
}
int main(void) {
char line[MAX_LEN];
struct executable *executables = NULL;
while (printf("# ") && fgets(line, MAX_LEN, stdin)) {
int args_len;
char **args = tokenize_line(line, &args_len);
if (strcmp(args[0], "dcc") == 0) {
// Validate command
// Now, every following argument must be either a `.c` file, or
// '-o' followed by an executable name
char **dcc_argv = &args[1];
int dcc_argc = args_len - 1;
bool found_o = false;
bool valid_command = true;
bool found_exec = false;
char *executable;
for (int i = 0; i < dcc_argc && valid_command; i++) {
if (endswith_c(&dcc_argv[i][0])) {
continue;
} else if (!strcmp(dcc_argv[i], "-o")) {
if (found_o) {
// multiple '-o'
valid_command = false;
}
found_o = true;
if (i + 1 >= dcc_argc) {
// No argument after '-o'
valid_command = false;
}
i++;
executable = dcc_argv[i];
if (endswith_c(executable)) {
// Executable is a c file
valid_command = false;
}
bool executable_matches = false;
for (int j = 0; j < dcc_argc; j++) {
if (startswith(dcc_argv[j], executable)) {
executable_matches = true;
}
}
if (!executable_matches) {
// Executable doesn't match a c file
valid_command = false;
}
found_exec = true;
} else {
// Non-.c file, or executable not preceded by '-o'
valid_command = false;
}
}
if (valid_command && found_exec) {
printf("Executable %s compiled!\n", executable);
struct executable *new = malloc(sizeof(struct executable));
strcpy(new->executable_name, executable);
new->files = NULL;
new->next = NULL;
if (executables) {
struct executable *curr = executables;
while (curr->next) {
curr = curr->next;
}
curr->next = new;
} else {
executables = new;
}
for (int i = 0; i < dcc_argc; i++) {
if (strcmp(dcc_argv[i], "-o") &&
strcmp(dcc_argv[i], executable)) {
struct file *new_file = malloc(sizeof(struct file));
strcpy(new_file->file_name, dcc_argv[i]);
new_file->next = NULL;
if (new->files) {
struct file *curr_file = new->files;
while (curr_file->next) {
curr_file = curr_file->next;
}
curr_file->next = new_file;
} else {
new->files = new_file;
}
}
}
} else {
printf("Invalid command!\n");
}
valid_command = true;
found_o = false;
found_exec = false;
} else if (prefix("./", args[0])) {
// Running executable
char *executable = &args[0][2];
struct executable *curr = executables;
struct executable *to_run = NULL;
while (curr) {
if (strcmp(curr->executable_name, executable) == 0) {
to_run = curr;
}
curr = curr->next;
}
if (!to_run) {
continue;
}
printf("Executable '%s' was compiled with the following files:\n",
executable);
struct file *curr_file = to_run->files;
while (curr_file) {
printf(" - %s\n", curr_file->file_name);
curr_file = curr_file->next;
}
} else {
// should never reach this tbh
printf("Unknown Error occured\n");
}
}
}