Programming Fundamentals
Q1
// Written by Sasha Vassar
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
int data;
};
// count_in_range should return the count of how many nodes in the list have a value
// strictly between the values of the first and last node
int count_in_range(struct node *head) {
if (head == NULL || head->next == NULL || head->next->next == NULL) {
return 0;
}
int first_val = head->data;
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
int last_val = curr->data;
int count = 0;
curr = head;
while (curr != NULL) {
if (curr->data > first_val && curr->data < last_val) {
count++;
}
curr = curr->next;
}
return count;
}
////////////////////////////////////////////////////////////////////////
// DO NOT CHANGE THE CODE BELOW //
////////////////////////////////////////////////////////////////////////
struct node *strings_to_list(int len, char *strings[]);
// DO NOT CHANGE THIS MAIN FUNCTION
int main(int argc, char *argv[]) {
// create linked list from command line arguments
struct node *head = strings_to_list(argc - 1, &argv[1]);
// If you're getting an error here,
// you have returned an uninitialized value
printf("%d\n", count_in_range(head));
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;
}
Q2
// Written by Sasha Vassar
#include <stdio.h>
#include <stdlib.h>
#define NUM_COLS 5
// sum_after_even should return the total sum of the values
// in each row of the 2D array, after the first even number.
int sum_after_even(int num_rows, int array[][NUM_COLS]) {
int total = 0;
for (int i = 0; i < num_rows; i++) {
int found_even = 0;
for (int j = 0; j < NUM_COLS; j++) {
if (found_even == 1) {
total += array[i][j];
} else if (array[i][j] % 2 == 0) {
found_even = 1;
}
}
}
return total;
}
// This is a simple main function which could be used
// to test your sum_after_even function.
// It will not be marked.
// Only your sum_after_even function will be marked.
int main(void) {
int test_array[][NUM_COLS] = {
{16, 12, 8, 3, 1},
{2, 0, 10, 1, 4},
{1, 1, 1, 13, 1},
{5, 5, 5, 8, 2},
{5, 5, 5, 5, 5}
};
int result = sum_after_even(5, test_array);
// Example Explanation:
// {16, 12, 8, 3, 1}, | 12 + 8 + 3 + 1 = 24
// {2, 0, 10, 1, 4}, | 0 + 10 + 1 + 4 = 15
// {1, 1, 1, 13, 1}, | 0
// {5, 5, 5, 8, 2}, | 2
// {5, 5, 5, 5, 5} | 0
// --------------------------------------
// TOTAL = 24 + 15 + 0 + 2 + 0 = 41
printf("%d\n", result);
return 0;
}
Q3
// Written by Sasha Vassar
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// DO NOT MODIFY THIS STRUCT
struct node {
int data;
struct node *next;
};
////////////////////////////////////////////////////////////////////////////////
// DO NOT CHANGE THESE FUNCTION PROTOTYPES
////////////////////////////////////////////////////////////////////////////////
struct node *insert_between_diff(int value, struct node *head);
struct node *strings_to_list(int len, char *strings[]);
void print_list(struct node *head);
void free_list(struct node *head);
//##############################################################################
// TODO: IMPLEMENT THIS FUNCTION
//##############################################################################
// Insert the given 'value' node between the first occurence of
// two consecutive nodes whose absolute difference is 6 or 7
struct node *insert_between_diff(int value, struct node *head) {
struct node *new_node = malloc(sizeof(struct node));
assert(new_node != NULL);
new_node->data = value;
new_node->next = NULL;
if (head == NULL) {
return new_node;
}
struct node *curr = head;
while (curr->next != NULL) {
int diff = abs(curr->data - curr->next->data);
if (diff == 6 || diff == 7) {
new_node->next = curr->next;
curr->next = new_node;
return head;
}
curr = curr->next;
}
curr->next = new_node;
return head;
}
///////////////////////////////////////////////////////////////////////////////
// DO NOT EDIT MAIN
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
int value;
scanf("%d", &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_between_diff(value, head);
print_list(new_head);
free_list(new_head);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// DO NOT CHANGE BELOW HERE INCLUDING THIS FUNCTION OR THE FUNCTIONS BELOW
////////////////////////////////////////////////////////////////////////////////
// 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 = atoi(strings[i]);
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("%d", n->data);
if (n->next != NULL) {
printf(", ");
}
n = n->next;
}
printf("]\n");
}
// free linked list
void free_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
struct node *temp = curr;
curr = curr->next;
free(temp);
}
}
Q4
// Written by Sasha Vassar
#include <stdio.h>
#include <stdlib.h>
#define NUM_COLS 5
// Return the index of the first row where every element is strictly greater than the element to its left.
// If no such row exists, return -1.
int first_sorted_row(int num_rows, int array[][NUM_COLS]) {
for (int i = 0; i < num_rows; i++) {
int is_sorted = 1;
for (int j = 1; j < NUM_COLS; j++) {
if (array[i][j] <= array[i][j - 1]) {
is_sorted = 0;
}
}
if (is_sorted == 1) {
return i;
}
}
return -1;
}
// This is a simple main function which could be used
// to test your first_sorted_row function.
// It will not be marked.
// Only your first_sorted_row function will be marked.
int main(void) {
int test_array[4][NUM_COLS] = {
{16, 12, 8, 4, 1}, // Row 0: Decreasing
{2, 4, 10, 15, 20}, // Row 1: Strictly Increasing!
{3, 6, 12, 11, 20}, // Row 2: Not sorted (11 < 12)
{5, 5, 5, 5, 5} // Row 3: Not strictly increasing
};
int result = first_sorted_row(4, test_array);
printf("%d\n", result);
return 0;
}
Q5
// Written by Grace Murray
// This program should scan in 3 buses with their bus number, maximum passenger
// capacity and current number of passengers on the bus and store it in struct
// array. The program should then scan in the number of passengers waiting for
// a bus and determine which buses have enough space for all the passengers.
//
// Unfortunately, this code contains a number of errors.
// It's your job to fix them, good luck!
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
struct bus {
int bus_number;
int max_capacity;
int current_passengers;
};
// BUG: Missing index on all array accesses
int main(void) {
printf("Enter 3 buses and their information: \n");
struct bus buses[SIZE];
for (int i = 0; i < SIZE; i++) {
printf("Bus %d: \n", i + 1);
printf("Bus number: ");
scanf("%d", &buses[i].bus_number);
printf("Maximum capacity: ");
scanf("%d", &buses[i].max_capacity);
printf("Current number of passengers: ");
scanf("%d", &buses[i].current_passengers);
}
printf("How many passengers are waiting for the bus: ");
int passengers_waiting;
scanf("%d", &passengers_waiting);
printf("Checking bus capacity...\n");
int has_space = 0;
int j = 0;
// BUG: Using > instead of <
while (j < SIZE) {
// BUG: Incorrect calculation, using + not -
int space_on_bus = buses[j].max_capacity - buses[j].current_passengers;
// BUG: Missing = in the >=
if (space_on_bus >= passengers_waiting) {
has_space++;
}
// BUG: Missing increment
j++;
}
if (has_space == SIZE) {
printf("Excellent! All 3 buses have enough space!\n");
} else if (has_space == 0) {
printf("Oh no! None of the 3 buses have enough space!\n");
} else {
// BUG: Initialise k to 1 instead of 0
int k = 0;
printf("Buses that have enough space:\n");
while (k < SIZE) {
// BUG: Incorrect calculation, using + not -
int space_on_bus = buses[k].max_capacity - buses[k].current_passengers;
// BUG: Missing = in the >=
if (space_on_bus >= passengers_waiting) {
// BUG: Printing current_passengers instead of .bus_number
printf("%d\n", buses[k].bus_number);
}
k++;
}
}
return 0;
}
Q6
// Written by Sofia De Bellis
// The following code is meant to convert a given temperature in Kelvin into
// degrees Celsius according to the provided formula.
// However, it has some issues that you need to fix. Good luck!
// Note: You cannot change the function prototype of `kelvin_to_celsius`
#include <stdio.h>
void kelvin_to_celsius(double kelvin, double *celsius);
int main(void) {
double kelvin;
double celsius; // BUG: 4: Incorrect type
printf("Enter temperature in Kelvin: ");
scanf("%lf", &kelvin); // BUG 2: %d instead of %lf and missing &
kelvin_to_celsius(kelvin, &celsius); // BUG 0: missing entire function call
printf("%.2lf Kelvin is equal to %.2lf Celsius.\n", kelvin, celsius); // BUG 3: no .2 precision and incorrect format specifier
return 0;
}
void kelvin_to_celsius(double kelvin, double *celsius) {
*celsius = kelvin - 273.15; // BUG 1: missing * dereference
}
Q7
// Written by Sofia De Bellis
// The following code is meant to prompt the user to enter a string and a
// position, then remove the character at that position from the string. The
// updated string, with the character deleted, is then printed to the screen.
//
// Unfortunately, this code contains a number of errors.
// It's your job to fix them, good luck!
#include <stdio.h>
#include <string.h>
#define SIZE 50
void delete_char_from_string(char input[SIZE], int position);
void strip_newline(char *string);
int main(void) {
printf("Enter a string: "); // BUG: missing semicolon
char input[SIZE];
fgets(input, SIZE, stdin); // BUG: missing 'stdin' from arguments
strip_newline(input);
printf("Enter a position to remove: ");
int position; // BUG: missing declaration
scanf("%d", &position);
delete_char_from_string(input, position); // BUG: called with 'input[]', extra '0' arg
printf("Result: %s\n", input);
return 0;
}
void delete_char_from_string(char string[SIZE], int position) {
int i = position - 1; // LOGIC BUG: missing "- 1" from initialisation
while (i < strlen(string)) {
string[i] = string[i + 1];
i++; // LOGIC BUG: missing increment
}
}
////////////////////////////////////////////////////////////////////////////////
// DO NOT CHANGE ANY OF THE CODE BELOW HERE //
// The code below is correct as given. You do NOT need to modify it //
////////////////////////////////////////////////////////////////////////////////
// Removes a newline character from end of the given string, if it exists.
void strip_newline(char *string) {
int length = strlen(string);
if (length != 0 && string[length - 1] == '\n') {
string[length - 1] = '\0';
}
}
Q8
// Written by Grace Murrary
#include <stdio.h>
#include <stdlib.h>
// Do not change this struct
struct node {
struct node *next;
int data;
};
// MODIFY THIS FUNCTION
// list_delete_min takes in the head of a linked list and deletes (and frees)
// all instances of the minimum value in the list
struct node *list_delete_min(struct node *head) {
struct node *curr = head;
struct node *prev = NULL;
if (curr == NULL || curr->next == NULL) {
free(curr);
return NULL;
}
// Find the minimum
int minimum = curr->data; // BUG: Initialise minimum to 0
while (curr != NULL) {
// BUG: Using == minimum instead of <
if (curr->data < minimum) {
minimum = curr->data;
}
curr = curr->next;
}
// Delete minimum
curr = head;
while (curr != NULL) {
// BUG: Using < minimum instead of ==
if (curr->data == minimum) {
struct node *to_delete = curr;
// BUG: Missing below if statement
if (prev == NULL) {
head = curr->next;
} else {
prev->next = curr->next;
}
// BUG: No curr = curr->next
curr = curr->next;
free(to_delete);
} else {
// BUG: Missing putting this into it's own if statement so misses a node
prev = curr;
curr = curr->next;
}
}
return head;
}
struct node *args_to_list(int argc, char *argv[]);
void print_list(struct node *head);
void free_list(struct node *head);
// DO NOT CHANGE THIS FUNCTION
int main(int argc, char *argv[]) {
struct node *head = args_to_list(argc, argv);
printf("BEFORE: ");
print_list(head);
head = list_delete_min(head);
printf("AFTER : ");
print_list(head);
free_list(head);
return 0;
}
// DO NOT CHANGE THIS FUNCTION
// Converts command-line args to a linked list of characters
struct node *args_to_list(int argc, char *argv[]) {
struct node *head = NULL;
for (int i = argc - 1; i >= 1; i--) {
struct node *new = malloc(sizeof(struct node));
new->data = atoi(argv[i]);
new->next = head;
head = new;
}
return head;
}
// DO NOT CHANGE THIS FUNCTION
// Prints a linked list of integers
void print_list(struct node *head) {
struct node *curr = head;
if (curr == NULL) {
printf("NULL\n");
return;
}
while (curr != NULL) {
printf("%d", curr->data);
if (curr->next != NULL) {
printf(" -> ");
}
curr = curr->next;
}
printf(" -> NULL\n");
}
void free_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
struct node *to_free = curr;
curr = curr->next;
free(to_free);
}
}
Q9
// Written by Sofia De Bellis
#include <stdio.h>
#include <stdlib.h>
int is_space(char c);
int words_match(char *word1, int len1, char *word2, int len2);
char *remove_target_word(char *target, char *text);
int main(void) {
char target[4096];
char input[4096];
fgets(target, 4096, stdin);
fgets(input, 4096, stdin);
char *output = remove_target_word(target, input);
printf("%s\n", output);
free(output);
return 0;
}
// Check if the character is a whitespace
int is_space(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0');
}
// Manual comparison: do these two words match?
int words_match(char *word1, int len1, char *word2, int len2) {
if (len1 != len2) {
return 0;
}
for (int i = 0; i < len1; i++) {
if (word1[i] != word2[i]) {
return 0;
}
}
return 1;
}
char *remove_target_word(char *target, char *text) {
// Find the length of the target word (up to first whitespace)
int target_len = 0;
while (!is_space(target[target_len])) {
target_len++;
}
// Allocate for the result string (max possible size)
char *result = malloc(4097);
int res_index = 0;
int i = 0;
while (text[i] != '\0') {
// 1. Skip whitespace to find the start of a word
while (text[i] != '\0' && is_space(text[i])) {
i++;
}
if (text[i] == '\0') {
break;
}
// 2. Mark the start and find the length of the current word
char *word_start = &text[i];
int word_len = 0;
while (text[i] != '\0' && !is_space(text[i])) {
word_len++;
i++;
}
// 3. If this word does NOT match the target, keep it
if (!words_match(word_start, word_len, target, target_len)) {
if (res_index > 0) {
result[res_index++] = ' ';
}
for (int j = 0; j < word_len; j++) {
result[res_index++] = word_start[j];
}
}
}
// Final null terminator for the result
result[res_index] = '\0';
return result;
}
Q10
// Written by Sofia De Bellis, z5418801
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int num_courses = atoi(argv[1]);
int num_prereqs = (argc - 2) / 2;
int *in_degree = calloc(num_courses, sizeof(int));
int *adj_count = calloc(num_courses, sizeof(int));
int **adj = malloc(num_courses * sizeof(int *));
int *prereq_a = malloc(num_prereqs * sizeof(int));
int *prereq_b = malloc(num_prereqs * sizeof(int));
for (int i = 0; i < num_prereqs; i++) {
prereq_a[i] = atoi(argv[2 + i * 2]);
prereq_b[i] = atoi(argv[2 + i * 2 + 1]);
in_degree[prereq_a[i]]++;
adj_count[prereq_b[i]]++;
}
for (int i = 0; i < num_courses; i++) {
adj[i] = malloc(adj_count[i] * sizeof(int));
adj_count[i] = 0;
}
for (int i = 0; i < num_prereqs; i++) {
int from = prereq_b[i];
int to = prereq_a[i];
adj[from][adj_count[from]++] = to;
}
int *queue = malloc(num_courses * sizeof(int));
int *result = malloc(num_courses * sizeof(int));
int front = 0;
int back = 0;
int result_size = 0;
for (int i = 0; i < num_courses; i++) {
if (in_degree[i] == 0) {
queue[back++] = i;
}
}
while (front < back) {
int min_idx = front;
for (int i = front + 1; i < back; i++) {
if (queue[i] < queue[min_idx]) {
min_idx = i;
}
}
int temp = queue[front];
queue[front] = queue[min_idx];
queue[min_idx] = temp;
int course = queue[front++];
result[result_size++] = course;
for (int i = 0; i < adj_count[course]; i++) {
int next = adj[course][i];
in_degree[next]--;
if (in_degree[next] == 0) {
queue[back++] = next;
}
}
}
if (result_size == num_courses) {
printf("Order: [");
for (int i = 0; i < result_size; i++) {
if (i == result_size - 1) {
printf("%d]\n", result[i]);
} else {
printf("%d, ", result[i]);
}
}
} else {
printf("Order: []\n");
}
free(in_degree);
for (int i = 0; i < num_courses; i++) {
free(adj[i]);
}
free(adj);
free(adj_count);
free(prereq_a);
free(prereq_b);
free(queue);
free(result);
return 0;
}
Q11
// Written by Sofia De Bellis, z5418801
#include <stdio.h>
#include <stdlib.h>
struct box {
int w;
int h;
};
void merge(struct box *boxes, struct box *temp, int left, int mid, int right);
void merge_sort(struct box *boxes, struct box *temp, int n);
int lower_bound(int *arr, int size, int target);
int max_nested_boxes(struct box *boxes, int n);
int main(int argc, char *argv[]) {
int n = (argc - 1) / 2;
struct box *boxes = malloc(n * sizeof(struct box));
for (int i = 0; i < n; i++) {
boxes[i].w = atoi(argv[i * 2 + 1]);
boxes[i].h = atoi(argv[i * 2 + 2]);
}
int result = max_nested_boxes(boxes, n);
printf("Max boxes: %d\n", result);
free(boxes);
return 0;
}
void merge(struct box *boxes, struct box *temp, int left, int mid, int right) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (boxes[i].w < boxes[j].w ||
(boxes[i].w == boxes[j].w && boxes[i].h > boxes[j].h)) {
temp[k++] = boxes[i++];
} else {
temp[k++] = boxes[j++];
}
}
while (i <= mid) {
temp[k++] = boxes[i++];
}
while (j <= right) {
temp[k++] = boxes[j++];
}
for (int x = left; x <= right; x++) {
boxes[x] = temp[x];
}
}
void merge_sort(struct box *boxes, struct box *temp, int n) {
for (int width = 1; width < n; width *= 2) {
for (int left = 0; left < n; left += 2 * width) {
int mid = left + width - 1;
int right = left + 2 * width - 1;
if (mid >= n) {
break;
}
if (right >= n) {
right = n - 1;
}
merge(boxes, temp, left, mid, right);
}
}
}
int lower_bound(int *arr, int size, int target) {
int low = 0;
int high = size;
while (low < high) {
int mid = low + (high - low) / 2;
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
int max_nested_boxes(struct box *boxes, int n) {
if (n == 0) {
return 0;
}
struct box *temp = malloc(n * sizeof(struct box));
merge_sort(boxes, temp, n);
free(temp);
int *tails = malloc(n * sizeof(int));
int length = 0;
for (int i = 0; i < n; i++) {
int pos = lower_bound(tails, length, boxes[i].h);
tails[pos] = boxes[i].h;
if (pos == length) {
length++;
}
}
free(tails);
return length;
}