Programming Fundamentals
Information
- This page contains additional revision exercises for week 10.
- These exercises are not compulsory, nor do they provide any marks in the course.
- You cannot submit any of these exercises, however autotests may be available for some them (Command included at bottom of each exercise if applicable).
Revision Video: Linked Lists - Prerequisites
Revision Video: Linked Lists - Creating and traversing a linked list (Coding)
Revision Video: Linked List - Sorted Insert
Revision Video: Linked Lists - Adding elements to a Linked List (Coding)
Revision Video: Linked List - Delete
Revision Video: Linked Lists - Deleting elements from a Linked List (Coding)
Exercise — individual:
Pokemon (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Follow the instructions in pokemon.c
to create some struct pokemon
. The level_up()
function should be passed a pointer and should increase the level of the pokemon at that address.
No autotests are provided for this question.
Examples
dcc pokemon.c -o pokemon ./pokemon charmander is level 5. wartortle is level 16. charmander is now level 6! wartortle is now level 20!
Assumptions/Restrictions/Clarifications
- This program does not take in any input from the terminal
pokemon.c
// Program to demonstrate pointers by leveling up pokemon
#include <stdio.h>
#include <string.h>
#define MAX_NAME_LEN 50
struct pokemon {
char name[MAX_NAME_LEN];
int level;
};
void level_up(struct pokemon *pokeball);
int main(void) {
struct pokemon pokeball1;
strcpy(pokeball1.name, "charmander");
pokeball1.level = 5;
struct pokemon pokeball2;
strcpy(pokeball2.name, "wartortle");
pokeball2.level = 16;
printf("%s is level %d.\n", pokeball1.name, pokeball1.level);
printf("%s is level %d.\n", pokeball2.name, pokeball2.level);
level_up(&pokeball1);
printf("%s is now level %d!\n", pokeball1.name, pokeball1.level);
level_up(&pokeball2);
level_up(&pokeball2);
level_up(&pokeball2);
level_up(&pokeball2);
printf("%s is now level %d!\n", pokeball2.name, pokeball2.level);
}
void level_up(struct pokemon *pokeball) {
(pokeball->level)++;
}
Exercise — individual:
Reverse an Array (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function array_reverse
in array_reverse.c
which takes in an array and reverses the order of elements in that array. array_reverse
does not return anything, so you will not be able to create a new array and return that. Instead, you will need to edit the values of the array you receive.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc array_reverse.c -o array_reverse ./array_reverse 6 5 4 3 2 1
Assumptions/Restrictions/Clarifications
- The given array should be edited directly.
- The function should not return anything.
- This program does not take in any input from the terminal
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest array_reverse
array_reverse.c
#include <stdio.h>
#define SIZE 6
void array_reverse(int *array, int size);
int main(void) {
int array[SIZE] = {1, 2, 3, 4, 5, 6};
array_reverse(array, SIZE);
printf("Reversed array:\n");
for (int i = 0; i < SIZE; i++) {
printf("%d\n", array[i]);
}
return 0;
}
void array_reverse(int *array, int size) {
int start = 0;
int end = size - 1;
while (start < end) {
int temp = array[start];
array[start] = array[end];
array[end] = temp;
start++;
end--;
}
}
Exercise — individual:
Count Frequency (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function count_frequency
in count_frequency.c
, which takes in an array of ints and prints out how many times each number appears in the array.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc count_frequency.c -o count_frequency ./count_frequency The number 5 came up 2 times. The number 3 came up 2 times. The number 8 came up 1 times. The number 6 came up 1 times.
Assumptions/Restrictions/Clarifications
- The count for each number should only be printed once.
- This program does not take in any input from the terminal
count_frequency.c
// Counts how many times a unique number was in an array
#include <stdio.h>
#define SIZE 6
void count_frequency(int *array, int size);
int main(void) {
int array[SIZE] = {5, 3, 5, 3, 8, 6};
count_frequency(array, SIZE);
return 0;
}
void count_frequency(int *array, int size) {
int frequency[SIZE] = {};
int already_visited = -1;
for (int i = 0; i < size; i++) {
int count = 1;
for (int j = i + 1; j < size; j++) {
if (array[i] == array[j]) {
count++;
frequency[j] = already_visited;
}
}
if (frequency[i] != already_visited) {
frequency[i] = count;
}
}
for (int i = 0; i < size; i++) {
if (frequency[i] != already_visited) {
printf("The number %d came up %d times.\n", array[i], frequency[i]);
}
}
}
Exercise — individual:
Combine Words (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function combine_words()
in words.c
which takes in 2 linked lists of equal length, and combines the strings at the same position into a single string, and returns a new list of these combined strings. E.g. if the first string in the first list is "hello" and the first string in the second list is "world", the new list's first string should be "hello world"
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc words.c -o words ./words hello world world hello cheese pizza
Assumptions/Restrictions/Clarifications
- The combined string should be stored in the same position as the strings it was made from
- This program does not take in any input from the terminal
words.c
// Creates a new list by combining words in the same position in two different lists together
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STR_LEN 1024
struct node {
char word[MAX_STR_LEN];
struct node *next;
};
struct node *create_node(char *word);
struct node *append_node(struct node *head, char *word);
struct node *combine_words(struct node *h1, struct node *h2);
void print_list(struct node *head);
void free_list(struct node *head);
int main(void) {
struct node *list1 = NULL;
list1 = append_node(list1, "hello");
list1 = append_node(list1, "world");
list1 = append_node(list1, "cheese");
struct node *list2 = NULL;
list2 = append_node(list2, "world");
list2 = append_node(list2, "hello");
list2 = append_node(list2, "pizza");
struct node *list3 = combine_words(list1, list2);
print_list(list3);
free_list(list1);
free_list(list2);
free_list(list3);
}
struct node *create_node(char *word) {
struct node *new = malloc(sizeof(struct node));
strcpy(new->word, word);
new->next = NULL;
return new;
}
struct node *append_node(struct node *head, char *word) {
struct node *new = create_node(word);
if (head == NULL) {
return new;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new;
return head;
}
// can assume the lists will be the same length
struct node *combine_words(struct node *l1, struct node *l2) {
struct node *head = NULL;
while (l1 != NULL) {
char new_word[MAX_STR_LEN];
strcpy(new_word, l1->word);
int i = 0;
while (new_word[i] != '\0') {
i++;
}
new_word[i] = ' ';
i++;
strcpy(&new_word[i], l2->word);
head = append_node(head, new_word);
l1 = l1->next;
l2 = l2->next;
}
return head;
}
void print_list(struct node *head) {
while (head != NULL) {
printf("%s\n", head->word);
head = head->next;
}
}
void free_list(struct node *head) {
while (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
}
}
Exercise — individual:
Bubble Tea (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Given a program words.c
which takes in bubble tea orders and save them as a 2D linked list, your task is to complete the free_shop
function to free all the malloc'd elements at the end of the bubble tea program. You can compile your program with --leak-check
to check if all malloc'd memory has been freed.
These following commands have been implemented in the starter code:
- v prints out the bubble tea orders (base only)
- p places an order by appending a new order to the bubble tea list, in the format: [tea base] [sugar] [ice] [toppings] where toppings can continue to be scanned until 0 is input. Toppings should also be stored in a linked list
- d grabs the details of a specified position; its sugar, ice, and all toppings
If you want to implement the commands yourself for practice, feel free to start from scratch rather than using the starter code.
No autotests are provided for this question.
Examples
dcc words.c -o words ./words Welcome to the Bubble Tea Shop! What would you like to do? v: view orders p: place an order d: get the details of an order v No orders!!! What would you like to do? v: view orders p: place an order d: get the details of an order p 1 2 3 4 3 2 1 0 What would you like to do? v: view orders p: place an order d: get the details of an order v 1. Green Tea What would you like to do? v: view orders p: place an order d: get the details of an order d 1 Sugar: 2 Ice: 3 The toppings in this bubble tea are: Grass Jelly Red Bean Lychee Jelly Pearls What would you like to do? v: view orders p: place an order d: get the details of an order d 2 Invalid order number What would you like to do? v: view orders p: place an order d: get the details of an order Thanks for visiting!
Assumptions/Restrictions/Clarifications
- All of the bubble tea shop functionality has been implemented for you. Your task is to complete the free_shop function
- When using the p command, toppings can be scanned in until 0 is input.
bubble_tea.c
// Simulates a bubble tea store by taking orders and printing orders
// Consists of a bubble tea store that contains a list of orders
// Each order has a list of toppings
#include <stdio.h>
#include <stdlib.h>
#define VIEW_ORDERS 'v'
#define PLACE_ORDER 'p'
#define DETAILS 'd'
#define NO_MORE_TOPPINGS 0
enum tea {
BLACK,
GREEN,
MILK,
};
enum topping_type {
PEARLS = 1,
LYCHEE_JELLY,
RED_BEAN,
GRASS_JELLY,
};
struct topping {
enum topping_type type;
struct topping *next;
};
struct bubble_tea {
enum tea base;
int sugar;
int ice;
struct topping *toppings;
struct bubble_tea *next;
};
struct bubble_tea_shop {
struct bubble_tea *orders;
};
void view_orders(struct bubble_tea_shop *shop);
void place_order(struct bubble_tea_shop *shop);
void details(struct bubble_tea_shop *shop);
void free_shop(struct bubble_tea_shop *shop);
void free_toppings(struct topping *topping);
void print_bubble_tea(struct bubble_tea *bt, int position);
void command_loop(struct bubble_tea_shop *shop);
int main(void) {
printf("Welcome to the Bubble Tea Shop!\n");
struct bubble_tea_shop *shop = malloc(sizeof(struct bubble_tea_shop));
shop->orders = NULL;
command_loop(shop);
printf("Thanks for visiting!\n");
free_shop(shop);
return 0;
}
// Loops until CTRL + D, taking in commands:
// 'v': prints the tea bases of all bubble teas ordered so far
// 'p': appends a new bubble tea order to the end of the list of orders
// 'd': gets the details of a specific order (sugar, ice and toppings)
void command_loop(struct bubble_tea_shop *shop) {
printf("\nWhat would you like to do?\n");
printf("v: view orders\np: place an order\nd: get the details of an order\n\n");
char command;
while (scanf(" %c", &command) == 1) {
if (command == VIEW_ORDERS) {
view_orders(shop);
} else if (command == PLACE_ORDER) {
place_order(shop);
} else if (command == DETAILS) {
details(shop);
}
printf("\nWhat would you like to do?\n");
printf("v: view orders\np: place an order\nd: get the details of an order\n\n");
}
}
// Prints the tea base of all orders in the shop, with their position indexed from 1
void view_orders(struct bubble_tea_shop *shop) {
if (shop->orders == NULL) {
printf("No orders!!!\n");
return;
}
struct bubble_tea *curr = shop->orders;
int i = 1;
while (curr != NULL) {
print_bubble_tea(curr, i);
i++;
curr = curr->next;
if (curr != NULL) {
printf("\t|\n\tv\n");
}
}
}
// Scans in details for a bubble tea order:
// Base
// Sugar
// Ice
// Toppings until 0 is entered
// Appends the bubble tea order to the end of the list of orders in the shop
void place_order(struct bubble_tea_shop *shop) {
// create the bubble tea and scan in fields
struct bubble_tea *bt = malloc(sizeof(struct bubble_tea));
int base;
int sugar;
int ice;
int topping;
scanf("%d %d %d %d", &base, &sugar, &ice, &topping);
bt->base = base;
bt->sugar = sugar;
bt->ice = ice;
bt->toppings = NULL;
bt->next = NULL;
// create a list of toppings until 0 is entered
struct topping *curr_topping = bt->toppings;
while (topping != NO_MORE_TOPPINGS) {
struct topping *new_topping = malloc(sizeof(struct topping));
new_topping->type = topping;
new_topping->next = NULL;
if (curr_topping == NULL) {
bt->toppings = new_topping;
curr_topping = new_topping;
} else {
curr_topping->next = new_topping;
curr_topping = curr_topping->next;
}
scanf(" %d", &topping);
}
// append new bubble tea to end of list
struct bubble_tea *curr_bt = shop->orders;
// empty list
if (curr_bt == NULL) {
shop->orders = bt;
return;
}
// normal append case
while (curr_bt->next != NULL) {
curr_bt = curr_bt->next;
}
curr_bt->next = bt;
return;
}
// Prints out the details of a specific bubble tea
// sugar, ice and all toppings
void details(struct bubble_tea_shop *shop) {
int position;
scanf("%d", &position);
struct bubble_tea *curr_bt = shop->orders;
int i = 1;
while (i < position && curr_bt != NULL) {
i++;
curr_bt = curr_bt->next;
}
if (curr_bt == NULL) {
printf("Invalid order number\n");
return;
}
printf("Sugar: %d\nIce: %d\n", curr_bt->sugar, curr_bt->ice);
printf("The toppings in this bubble tea are:\n");
if (curr_bt->toppings == NULL) {
printf("no toppings\n");
return;
}
struct topping *curr_topping = curr_bt->toppings;
while (curr_topping != NULL) {
if (curr_topping->type == PEARLS) {
printf("Pearls\n");
} else if (curr_topping->type == LYCHEE_JELLY) {
printf("Lychee Jelly\n");
} else if (curr_topping->type == RED_BEAN) {
printf("Red Bean\n");
} else if (curr_topping->type == GRASS_JELLY) {
printf("Grass Jelly\n");
}
curr_topping = curr_topping->next;
}
}
// Frees all toppings, bubble teas, and the shop itself
void free_shop(struct bubble_tea_shop *shop) {
struct bubble_tea *bt = shop->orders;
while (bt != NULL) {
free_toppings(bt->toppings);
struct bubble_tea *temp = bt;
bt = bt->next;
free(temp);
}
free(shop);
}
// frees all toppings including the supplied head topping
void free_toppings(struct topping *topping) {
while (topping != NULL) {
struct topping *temp = topping;
topping = topping->next;
free(temp);
}
}
// prints a single bubble tea's given position and base
void print_bubble_tea(struct bubble_tea *bt, int position) {
printf("%d. ", position);
if (bt->base == BLACK) {
printf("Black Tea\n");
} else if (bt->base == GREEN) {
printf("Green Tea\n");
} else if (bt->base == MILK) {
printf("Milk Tea\n");
} else {
printf("Unknown base\n");
}
}
Exercise — individual:
Merge Lists (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the program merge_lists.c
which takes 2 lists with elements in ascending order, and combines those lists while preserving the ascending order.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc merge_lists.c -o merge_lists ./merge_lists List 1: 0 -> 5 -> 40 -> X List 2: 1 -> 3 -> 10 -> 100 -> X Merged List: 0 -> 1 -> 3 -> 5 -> 10 -> 40 -> 100 -> X
Assumptions/Restrictions/Clarifications
- The 2 given lists are not necessarily the the same length.
- The elements of the new list should be in ascending order.
- This program does not take in any input from the terminal
merge_lists.c
// Merges 2 sorted linked lists
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STR_LEN 1024
struct node {
int data;
struct node *next;
};
struct node *create_node(int value);
struct node *append_node(struct node *head, int value);
struct node *merge_lists(struct node *l1, struct node *l2);
void print_list(struct node *head);
void free_list(struct node *head);
int main(void) {
struct node *list1 = NULL;
list1 = append_node(list1, 0);
list1 = append_node(list1, 5);
list1 = append_node(list1, 40);
struct node *list2 = NULL;
list2 = append_node(list2, 1);
list2 = append_node(list2, 3);
list2 = append_node(list2, 10);
list2 = append_node(list2, 100);
printf("List 1:\n");
print_list(list1);
printf("List 2:\n");
print_list(list2);
struct node *list3 = merge_lists(list1, list2);
printf("Merged List:\n");
print_list(list3);
free_list(list3);
}
struct node *create_node(int value) {
struct node *new = malloc(sizeof(struct node));
new->data = value;
new->next = NULL;
return new;
}
struct node *append_node(struct node *head, int value) {
struct node *new = create_node(value);
if (head == NULL) {
return new;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new;
return head;
}
struct node *merge_lists(struct node *l1, struct node *l2) {
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
struct node *head = NULL;
struct node *curr1 = l1;
struct node *curr2 = l2;
struct node *prev = NULL;
while (curr1 != NULL && curr2 != NULL) {
if (curr1->data <= curr2->data) {
if (head == NULL) {
head = curr1;
prev = head;
} else {
prev->next = curr1;
prev = curr1;
}
curr1 = curr1->next;
} else {
if (head == NULL) {
head = curr2;
prev = head;
} else {
prev->next = curr2;
prev = curr2;
}
curr2 = curr2->next;
}
}
if (curr1 != NULL) {
prev->next = curr1;
} else {
prev->next = curr2;
}
return head;
}
void print_list(struct node *head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("X\n");
}
void free_list(struct node *head) {
while (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
}
}
Exercise — individual:
Reverse a Linked List (Revision Session Exercise)
Download list_reverse.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_reverse
Your task is to add code to this function in list_reverse.c:
//
// Place the list pointed to by head into reverse order.
// The head of the list is returned.
//
struct node *reverse(struct node *head) {
// PUT YOUR CODE HERE (change the next line!)
return NULL;
}
Note list_reverse.c
uses the following familiar data type:
struct node { struct node *next; int data; };
list_reverse
is given one argument, head
which is the pointer to the first
node in the linked list.
Add code to reverse
which rearranges the list to be in reverse order.
reverse
should return a pointer to the new list.
reverse
must rearrange the list by changing the next
fields of nodes.
reverse
must not change the data
fields of nodes.
For example if the linked list contains these 8 elements:
16, 7, 8, 12, 13, 19, 21, 12
reverse
should return a pointer to a list with these elements:
12, 21, 19, 13, 12, 8, 7, 16
Testing
list_reverse.c
also contains a main
function which allows you to test your
list_reverse
function.
This main function:
- takes in the size of the linked list,
- converts the input numbers to a linked list,
- assigns a pointer to the first node in the linked list to
head
, - calls
reverse(head)
and - prints the result.
Do not change this function. If you want to change it, you have misread the question.
Your list_reverse
function will be called directly in marking. The main
function is only to let you test your list_reverse
function
Examples
dcc list_reverse.c -o list_reverse ./list_reverse How many numbers in list?: 8 16 7 8 12 13 19 21 12 [12, 21, 19, 13, 12, 8, 7, 16] ./list_reverse How many numbers in list?: 6 2 4 6 2 4 6 [6, 4, 2, 6, 4, 2] ./list_reverse 42 How many numbers in list?: 1 42 [42] ./list_reverse How many numbers in list?: 0 []
Assumptions/Restrictions/Clarifications
list_reverse
should not change the data fields of list nodeslist_reverse
should not use arrayslist_reverse
should not callmalloc
list_reverse
should not call scanf (orgetchar
orfgets
)list_reverse
should not print anything. It should not callprintf
- Do not change the supplied
main
function. It will not be tested or marked
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_reverse
list_reverse.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
int data;
};
struct node *reverse(struct node *head);
struct node *array_to_list(int len, int array[]);
void print_list(struct node *head);
// DO NOT CHANGE THIS MAIN FUNCTION
#define MAX_INIT_LIST_LEN 100
int main() {
// Need to read in a number of ints into an array
printf("How many numbers in list?: ");
int list_size = 0;
scanf("%d", &list_size);
int initial_elems[MAX_INIT_LIST_LEN] = {0};
int n_read = 0;
while (n_read < list_size && scanf("%d", &initial_elems[n_read])) {
n_read++;
}
// create linked list from first set of inputs
struct node *head = NULL;
if (n_read > 0) {
// list has elements
head = array_to_list(n_read, initial_elems);
}
struct node *new_head = reverse(head);
print_list(new_head);
return 0;
}
// Place the list into reverse order.
// The head of the list is returned.
struct node *reverse(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *previous = NULL;
struct node *x = head;
while (x != NULL) {
struct node *y = x->next;
x->next = previous;
previous = x;
x = y;
}
return previous;
}
// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *array_to_list(int len, int array[]) {
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 = array[i];
head = n;
i -= 1;
}
return head;
}
// print linked list
void print_list(struct node *head) {
printf("[");
for (struct node *n = head; n != NULL; n = n->next) {
// If you're getting an error here,
// you have returned an invalid list
printf("%d", n->data);
if (n->next != NULL) {
printf(", ");
}
}
printf("]\n");
}
list_reverse.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
int data;
};
// Place the list into reverse order.
// The head of the list is returned.
struct node *reverse(struct node *head) {
// lists of 0 or 1 node don't need to be changed
if (head == NULL || head->next == NULL) {
return head;
}
//reverse rest of list
struct node *new_head = reverse(head->next);
// head->next will be the last element in the reversed rest of list
// append head to it
head->next->next = head;
head->next = NULL;
return new_head;
}
Exercise — individual:
Filter a 1D array
Download filter_list.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity filter_list
Your task is to write a program to find the number of bags from people over a specified height.
More specifically, your program should do the following.
- Scan in 5 pairs of height and number of bags, and store these pairs in an array of structs
- Ask the user for a minimum height to filter by
- Find the number of bags, from people who were greater than or equal to that height
This program has some starter code which includes the following struct.
struct passenger {
double height;
int num_bags;
};
The starter code also creates an array for you to store data in.
struct passenger my_array[SIZE];
Examples
dcc filter_list.c -o filter_list ./filter_list Enter height & number of bags: 150.0 1 Enter height & number of bags: 160.0 2 Enter height & number of bags: 170.0 3 Enter height & number of bags: 180.0 1 Enter height & number of bags: 190.0 2 Select height: 170.0 Total of 6 bags from people over 170.000000 ./filter_list Enter height & number of bags: 150.0 1 Enter height & number of bags: 160.0 1 Enter height & number of bags: 170.0 1 Enter height & number of bags: 180.0 1 Enter height & number of bags: 190.0 1 Select height: 200.0 Total of 0 bags from people over 200.000000
Assumptions/Restrictions/Clarifications
- Your program should match the output shown above exactly.
- You can assume you will always be given the correct data type during input.
- You can assume a height is always a positive and non-zero number.
- You can assume the number of bags is non-negative.
- Your program should still work when a person has no baggage.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest filter_list
filter_list.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
struct passenger {
double height;
int num_bags;
};
int main(void) {
struct passenger my_array[SIZE];
for(int i = 0; i < SIZE; i++) {
printf("Enter height & number of bags: ");
scanf("%lf %d", &my_array[i].height, &my_array[i].num_bags);
}
double filter_height;
printf("Select height: ");
scanf("%lf", &filter_height);
int count = 0;
for (int i = 0; i < SIZE; i++) {
if (my_array[i].height >= filter_height) {
count += my_array[i].num_bags;
}
}
printf("Total of %d bags from people over %lf\n", count, filter_height);
return 0;
}
Exercise — individual:
Find totals of rows
Download find_totals.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity find_totals
Your task is to add code to this function in find_totals.c:
int find_totals(int arr[SIZE][SIZE], int size) {
// TODO: Find the number of rows with a
// sum equal to exactly 10
return 0;
}
Given a 2d arrays of integers, your task is to find the number of rows where the sum of the integers equates to exactly 10.
You can assume the given array is always of size 5
You can assume the array always has the same number of rows and columns (The array is always square)
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions it is helpful.
For example, if the following 2D array was given
The output should be exactly
dcc find_totals.c -o find_totals ./find_totals 2 rows had a sum of 10
This output is becasue rows 2 and 3 each have a sum of exactly 10.
Your function should work when there are arrays with no rows equal to 10.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest find_totals
find_totals.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
int find_totals(int arr[SIZE][SIZE], int size);
int main(void) {
int array1[SIZE][SIZE] = {{0, 3, 2, 5, 2},
{2, 1, 5, 1, 1}, // == 10
{4, 4, 7, 7, 0},
{10, 0, 0, 0, 0}, // == 10
{0, 0, 0, 0 ,0}};
printf("%d rows had a sum of 10\n", find_totals(array1, SIZE));
return 0;
}
int find_totals(int arr[SIZE][SIZE], int size) {
int count = 0;
for (int row = 0; row < size; row++) {
int row_total = 0;
for (int col = 0; col < size; col++) {
row_total += arr[row][col];
}
if (row_total == 10) {
count++;
}
}
return count;
}
Exercise — individual:
Insert after lowest
Download list_insert_after_lowest.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_insert_after_lowest
Your task is to add code to this function in list_insert_after_lowest.c:
struct node *insert_after_lowest(struct node *head, int data) {
// TODO: Insert a new node with the value, 'data'
// after the node with the lowest data.
return NULL;
}
Given a linked list, your task is to insert a new node, with a specific value, after the node with the lowest values in the linked list.
insert_after_lowest
is given a pointer to a linked list and the data values
that is to be added.
insert_after_lowest
should return a pointer to the linked list
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
insert_after_lowest
should find the lowest value in the linked list, and
insert a new node directly after it.
For example, if the linked list had the values
Head => [4, 2, 6]
And the function was asked to add the value 99, the list after modification would look as the following
Head => [4, 2, 99, 6]
The below shows the output when the program is run with the example given in the starter code main function.
dcc insert_after_lowest.c -o insert_after_lowest ./insert_after_lowest 4 -> 2 -> 6 -> X 4 -> 2 -> 99 -> 6 -> X
Assumptions/Restrictions/Clarifications
insert_after_lowest
should still insert the new node if the list is empty.insert_after_lowest
should only ever insert ONE node after the first instance of the lowest value, even if there are multiple nodes with the same lowest value.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_insert_after_lowest
list_insert_after_lowest.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *insert_after_lowest(struct node *head, int data);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, 2);
head = insert_at_head(head, 4);
print_list(head);
head = insert_after_lowest(head, 99);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
// Inserts a new node after the node with the
// lowest data in the list
struct node *insert_after_lowest(struct node *head, int data) {
// If list is empty, insert at the head
if (head == NULL) {
return insert_at_head(NULL, data);
}
int min_val = find_lowest(head);
struct node *curr = head;
while (curr != NULL) {
if (curr->data == min_val) {
struct node *new = create_node(data);
new->next = curr->next;
curr->next = new;
return head;
}
curr = curr->next;
}
return head;
}
// ASSUMES LIST IS NOT NULL
int find_lowest(struct node *head) {
struct node *curr = head;
int min = curr->data;
while (curr != NULL) {
if (curr->data < min) {
min = curr->data;
}
curr = curr->next;
}
return min;
}
Exercise — individual:
Insert in alternating order
Download list_insert_alternating.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_insert_alternating
Your task is to write a program which will read values until EOF, and insert these values into a linked list in an alternating order.
Specifically, your program should read integers from the terminal, until EOF, and insert the first value to the head of the list, then the second value is to the tail of the list, then the third value is added to the head of the list etc.
A minimal starter program is given to you, this program should use the familiar data type
struct node {
int data;
struct node *next;
};
You may also find the given create_node
function helpful in you implementation.
Your program should use the provided print_list
function to print the list after EOF is received.
For example, if your program was given the following inputs
1 2 3 4 5
The resultant linked list should be as follows
Head => [5, 3, 1, 2, 4]
This is because;
- 1 was added to the head of an empty list
- 2 was added to the tail of the list
- 3 was added to the head of the list
- 4 was added to the tail of the list
- 5 was added to the head of the list
Examples
dcc insert_alternating.c -o insert_alternating ./insert_alternating 1 2 3 4 5 5 -> 3 -> 1 -> 2 -> 4 -> X ./insert_alternating 1 1 1 2 2 3 3 3 -> 2 -> 1 -> 1 -> 1 -> 2 -> 3 -> X ./insert_alternating X
Your program should be able to accept an unlimited number of values
Your program should print an empty list if no values were inputted
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_insert_alternating
list_insert_alternating.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
void print_list(struct node *head);
// Your functions
struct node *insert_at_head(struct node *head, int data);
struct node *insert_after_lowest(struct node *head, int data);
struct node *insert_at_tail(struct node *head, int data);
int main(void) {
struct node *head = NULL;
int count = 0;
int data = 0;
while(scanf("%d", &data) == 1) {
if (count % 2 == 0) {
head = insert_at_head(head, data);
} else {
head = insert_at_tail(head, data);
}
count++;
}
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Inserts at the tail of the linked list
// Returns a pointer to the head of the list
struct node *insert_at_tail(struct node *head, int data) {
struct node *new_node = create_node(data);
if (head == NULL) {
return new_node;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
return head;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
Exercise — individual:
Find adjacent point distances
Download adjacent_distances.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity adjacent_distances
Your task is to add code to this function in adjacent_distances.c:
void adjacent_distances(struct coordinate arr[SIZE], int size) {
// TODO: Print the distances between adjacent coordinates
// Your function should NOT return anything
// Your function SHOULD print the distances
}
Your task is to print the Euclidean distance between adjacent coordinates in an array of coordinates.
Specifically, given a 1D array of structs, where each struct contains an x and y coordinate, you need to calculate and print the distance between coordinates stored next to each other in the array.
This program uses the following struct to store coordinates
struct coordinate {
int x;
int y;
};
Coordinates are stored in an array of struct coordinates, always of size 5. This can be seen in the starter program. Note; Some example values are given to the array of structs for your testing
struct coordinate array1[SIZE];
For this array of size 5, you must calculate and print the Euclidean distance between coordinates in
- Index 0 & Index 1
- Index 1 & Index 2
- Index 2 & Index 3
- Index 3 & Index 4
The euclidean distance can be calculated using the provided e_dist
function in the starter code. This function takes in two struct coordinate
and returns the distance between them as a double.
You must implement the function given to you, the function will be called directly in marking and the main function will be ignored. You may create extra function if you find that helpful.
For example, the output of the test input given in the main function, would be
dcc adjacent_distances.c -o adjacent_distances ./adjacent_distances Dist: 1.414214 Dist: 7.000000 Dist: 9.899495 Dist: 9.219544
Your program must produce this output exactly
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest adjacent_distances
adjacent_distances.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SIZE 5
struct coordinate {
int x;
int y;
};
double e_dist(struct coordinate p0, struct coordinate p1);
void adjacent_distances(struct coordinate arr[SIZE], int size);
int main(void) {
// Only your function is called during testing
// Any changes in this main function will not
// be used in testing
struct coordinate array1[SIZE] = {{.x = 1, .y = 1},
{.x = 2, .y = 2},
{.x = 9, .y = 2},
{.x = 2, .y = 9},
{.x = 0, .y = 0}};
adjacent_distances(array1, SIZE);
return 0;
}
void adjacent_distances(struct coordinate arr[SIZE], int size) {
for (int i = 0; i < (size - 1); i++) {
printf("Dist: %lf\n", e_dist(arr[i], arr[i+1]));
}
}
double e_dist(struct coordinate p0, struct coordinate p1) {
return sqrt((p1.x - p0.x)*(p1.x - p0.x)*1.0 + (p1.y - p0.y)*(p1.y - p0.y)*1.0);
}
Exercise — individual:
Clamp a 2D array
Download array_clamping_max.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity array_clamping_max
Your task is to add code to this function in array_clamping_max.c:
void clamp_max(int arr[SIZE][SIZE], int size, int max) {
// TODO: Make sure all values are <= max
// Change any values that are > max
}
Given a 2D array of integers and a maximium value, you must make sure all values within the 2D array are less than or equal to that maximium value. If a value is greater than the max value, you should change the value to be equal to the max value.
For example if the given array was as follows, and the max value was set to 10
Then the array should be changed to be
Your function will be called directly in marking, any changes in the main function will not be used. You may use additional functions if you find it helpful.
You can assume the array is always square and the size is always 5.
The array values given can be any valid integer.
You are not required to print the array, this is handled separately.
You are only required to implement the clamp_max
function.
Examples
dcc adjacent_distances.c -o adjacent_distances ./adjacent_distances Before: 9 3 2 5 2 2 12 5 1 11 4 4 7 7 6 10 0 4 15 0 2 9 0 4 0 After: 9 3 2 5 2 2 10 5 1 10 4 4 7 7 6 10 0 4 10 0 2 9 0 4 0
Your program must produce this output exactly
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest array_clamping_max
array_clamping_max.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
void print_array(int arr[SIZE][SIZE], int size);
void clamp_max(int arr[SIZE][SIZE], int size, int max);
int main(void) {
int array1[SIZE][SIZE] = {{9, 3, 2, 5, 2},
{2, 12, 5, 1, 11},
{4, 4, 7, 7, 6},
{10, 0, 4, 15, 0},
{2, 9, 0, 4, 0}};
printf("Before:\n");
print_array(array1, SIZE);
clamp_max(array1, SIZE, 10);
printf("After:\n");
print_array(array1, SIZE);
return 0;
}
void clamp_max(int arr[SIZE][SIZE], int size, int max) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (arr[row][col] > max) {
arr[row][col] = max;
}
}
}
}
void print_array(int arr[SIZE][SIZE], int size) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
printf("%3d ", arr[row][col]);
}
printf("\n");
}
}
Exercise — individual:
Delete negatives
Download list_delete_negatives.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_delete_negatives
Your task is to add code to this function in list_delete_negatives.c:
struct node *delete_negatives(struct node *head) {
// TODO: Delete any nodes in the linked list
// with a data value < 0
return NULL;
}
Given a linked list, your task is to delete any nodes which have a value strictly less than 0. Any nodes which are deleted must be properly free'd.
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
list_delete_negatives
is given a pointer to a linked list.
list_delete_negatives
should return a pointer to the head of the linked list.
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
Your function should operate normally with an empty linked list.
Your function should not change the list if there are no negative numbers within the list.
You function should not call malloc.
Your function should not have any memory leaks and should pass a leak-check.
For example, if the linked list had the values
Head => [3, 4, -5, 10, -10]
Your function should return a pointer to a linked list with the following values
Head => [3, 4, 10]
Additionally, if the linked list had the values
Head => [-2, -2, 6]
Your function should return a pointer to a linked list with the following values
Head => [6]
Examples
dcc list_delete_negatives.c -o list_delete_negatives ./list_delete_negatives 4 -> -2 -> 6 -> X 4 -> 6 -> X
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_delete_negatives
list_delete_negatives.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *delete_negatives(struct node *head);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, -2);
head = insert_at_head(head, 4);
print_list(head);
head = delete_negatives(head);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
struct node *delete_negatives(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *prev = NULL;
struct node *curr = head;
while (curr != NULL) {
if (curr->data < 0) {
struct node *to_del = curr;
// is it the head?
if (prev == NULL) {
curr = curr->next;
head = curr;
free(to_del);
} else {
prev->next = curr->next;
curr = curr->next;
free(to_del);
}
} else {
prev = curr;
curr = curr->next;
}
}
return head;
}
Exercise — individual:
Delete Duplicates
Download list_delete_duplicates.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_delete_duplicates
Your task is to add code to this function in list_delete_duplicates.c:
struct node *delete_duplicates(struct node *head) {
// TODO: delete any adjacent duplicate values
return NULL;
}
Given a linked list, delete any values which are adjacent duplicates in the linked list.
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
delete_duplicates
is given a pointer to a linked list.
delete_duplicates
should return a pointer to the head of the linked list.
delete_duplicates
should only remove duplicate values which are next to each
other in the list (adjacent).
delete_duplicates
can delete more than 1 successive duplicate value.
delete_duplicates
should remove all but the first instance of the value in a
set of duplicates, such that the value only appears once in that part of the
list.
The same value can appear multiple times in the linked list, provided they are not adjacent.
delete_duplicates
can remove the same value multiple times in the list.
See the examples for more details
Example 1
For example, if the linked list had the values
Head => [2, 3, 3, 5, 6]
After removing duplicates, the list would become
Head => [2, 3, 5, 6]
Example 2
For example, if the linked list had the values
Head => [10, 11, 11, 11, 11, 12]
After removing duplicates, the list would become
Head => [10, 11, 12]
Example 3
For example, if the linked list had the values
Head => [10, 11, 11, 25, 11, 11]
After removing duplicates, the list would become
Head => [10, 11, 25, 11]
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
Your function should operate normally with an empty linked list.
Your function should not change the list if there are no duplicate numbers within the list.
You function should not call malloc.
Your function should not have any memory leaks and should pass a leak-check.
Examples
dcc list_delete_duplicates.c -o list_delete_duplicates ./list_delete_duplicates 2 -> 4 -> 4 -> 6 -> X 2 -> 4 -> 6 -> X
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_delete_duplicates
list_delete_duplicates.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *delete_duplicates(struct node *head);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, 4);
head = insert_at_head(head, 4);
head = insert_at_head(head, 2);
print_list(head);
head = delete_duplicates(head);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
struct node *delete_duplicates(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *curr = head;
while (curr != NULL && curr->next != NULL) {
if (curr->data == curr->next->data) {
struct node *to_del = curr->next;
curr->next = curr->next->next;
free(to_del);
} else {
curr = curr->next;
}
}
return head;
}
Exercise — individual:
Pokemon (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Follow the instructions in pokemon.c
to create some struct pokemon
. The level_up()
function should be passed a pointer and should increase the level of the pokemon at that address.
No autotests are provided for this question.
Examples
dcc pokemon.c -o pokemon ./pokemon charmander is level 5. wartortle is level 16. charmander is now level 6! wartortle is now level 20!
Assumptions/Restrictions/Clarifications
- This program does not take in any input from the terminal
pokemon.c
// Program to demonstrate pointers by leveling up pokemon
#include <stdio.h>
#include <string.h>
#define MAX_NAME_LEN 50
struct pokemon {
char name[MAX_NAME_LEN];
int level;
};
void level_up(struct pokemon *pokeball);
int main(void) {
struct pokemon pokeball1;
strcpy(pokeball1.name, "charmander");
pokeball1.level = 5;
struct pokemon pokeball2;
strcpy(pokeball2.name, "wartortle");
pokeball2.level = 16;
printf("%s is level %d.\n", pokeball1.name, pokeball1.level);
printf("%s is level %d.\n", pokeball2.name, pokeball2.level);
level_up(&pokeball1);
printf("%s is now level %d!\n", pokeball1.name, pokeball1.level);
level_up(&pokeball2);
level_up(&pokeball2);
level_up(&pokeball2);
level_up(&pokeball2);
printf("%s is now level %d!\n", pokeball2.name, pokeball2.level);
}
void level_up(struct pokemon *pokeball) {
(pokeball->level)++;
}
Exercise — individual:
Reverse an Array (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function array_reverse
in array_reverse.c
which takes in an array and reverses the order of elements in that array. array_reverse
does not return anything, so you will not be able to create a new array and return that. Instead, you will need to edit the values of the array you receive.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc array_reverse.c -o array_reverse ./array_reverse 6 5 4 3 2 1
Assumptions/Restrictions/Clarifications
- The given array should be edited directly.
- The function should not return anything.
- This program does not take in any input from the terminal
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest array_reverse
array_reverse.c
#include <stdio.h>
#define SIZE 6
void array_reverse(int *array, int size);
int main(void) {
int array[SIZE] = {1, 2, 3, 4, 5, 6};
array_reverse(array, SIZE);
printf("Reversed array:\n");
for (int i = 0; i < SIZE; i++) {
printf("%d\n", array[i]);
}
return 0;
}
void array_reverse(int *array, int size) {
int start = 0;
int end = size - 1;
while (start < end) {
int temp = array[start];
array[start] = array[end];
array[end] = temp;
start++;
end--;
}
}
Exercise — individual:
Count Frequency (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function count_frequency
in count_frequency.c
, which takes in an array of ints and prints out how many times each number appears in the array.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc count_frequency.c -o count_frequency ./count_frequency The number 5 came up 2 times. The number 3 came up 2 times. The number 8 came up 1 times. The number 6 came up 1 times.
Assumptions/Restrictions/Clarifications
- The count for each number should only be printed once.
- This program does not take in any input from the terminal
count_frequency.c
// Counts how many times a unique number was in an array
#include <stdio.h>
#define SIZE 6
void count_frequency(int *array, int size);
int main(void) {
int array[SIZE] = {5, 3, 5, 3, 8, 6};
count_frequency(array, SIZE);
return 0;
}
void count_frequency(int *array, int size) {
int frequency[SIZE] = {};
int already_visited = -1;
for (int i = 0; i < size; i++) {
int count = 1;
for (int j = i + 1; j < size; j++) {
if (array[i] == array[j]) {
count++;
frequency[j] = already_visited;
}
}
if (frequency[i] != already_visited) {
frequency[i] = count;
}
}
for (int i = 0; i < size; i++) {
if (frequency[i] != already_visited) {
printf("The number %d came up %d times.\n", array[i], frequency[i]);
}
}
}
Exercise — individual:
Combine Words (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the function combine_words()
in words.c
which takes in 2 linked lists of equal length, and combines the strings at the same position into a single string, and returns a new list of these combined strings. E.g. if the first string in the first list is "hello" and the first string in the second list is "world", the new list's first string should be "hello world"
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc words.c -o words ./words hello world world hello cheese pizza
Assumptions/Restrictions/Clarifications
- The combined string should be stored in the same position as the strings it was made from
- This program does not take in any input from the terminal
words.c
// Creates a new list by combining words in the same position in two different lists together
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STR_LEN 1024
struct node {
char word[MAX_STR_LEN];
struct node *next;
};
struct node *create_node(char *word);
struct node *append_node(struct node *head, char *word);
struct node *combine_words(struct node *h1, struct node *h2);
void print_list(struct node *head);
void free_list(struct node *head);
int main(void) {
struct node *list1 = NULL;
list1 = append_node(list1, "hello");
list1 = append_node(list1, "world");
list1 = append_node(list1, "cheese");
struct node *list2 = NULL;
list2 = append_node(list2, "world");
list2 = append_node(list2, "hello");
list2 = append_node(list2, "pizza");
struct node *list3 = combine_words(list1, list2);
print_list(list3);
free_list(list1);
free_list(list2);
free_list(list3);
}
struct node *create_node(char *word) {
struct node *new = malloc(sizeof(struct node));
strcpy(new->word, word);
new->next = NULL;
return new;
}
struct node *append_node(struct node *head, char *word) {
struct node *new = create_node(word);
if (head == NULL) {
return new;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new;
return head;
}
// can assume the lists will be the same length
struct node *combine_words(struct node *l1, struct node *l2) {
struct node *head = NULL;
while (l1 != NULL) {
char new_word[MAX_STR_LEN];
strcpy(new_word, l1->word);
int i = 0;
while (new_word[i] != '\0') {
i++;
}
new_word[i] = ' ';
i++;
strcpy(&new_word[i], l2->word);
head = append_node(head, new_word);
l1 = l1->next;
l2 = l2->next;
}
return head;
}
void print_list(struct node *head) {
while (head != NULL) {
printf("%s\n", head->word);
head = head->next;
}
}
void free_list(struct node *head) {
while (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
}
}
Exercise — individual:
Bubble Tea (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Given a program words.c
which takes in bubble tea orders and save them as a 2D linked list, your task is to complete the free_shop
function to free all the malloc'd elements at the end of the bubble tea program. You can compile your program with --leak-check
to check if all malloc'd memory has been freed.
These following commands have been implemented in the starter code:
- v prints out the bubble tea orders (base only)
- p places an order by appending a new order to the bubble tea list, in the format: [tea base] [sugar] [ice] [toppings] where toppings can continue to be scanned until 0 is input. Toppings should also be stored in a linked list
- d grabs the details of a specified position; its sugar, ice, and all toppings
If you want to implement the commands yourself for practice, feel free to start from scratch rather than using the starter code.
No autotests are provided for this question.
Examples
dcc words.c -o words ./words Welcome to the Bubble Tea Shop! What would you like to do? v: view orders p: place an order d: get the details of an order v No orders!!! What would you like to do? v: view orders p: place an order d: get the details of an order p 1 2 3 4 3 2 1 0 What would you like to do? v: view orders p: place an order d: get the details of an order v 1. Green Tea What would you like to do? v: view orders p: place an order d: get the details of an order d 1 Sugar: 2 Ice: 3 The toppings in this bubble tea are: Grass Jelly Red Bean Lychee Jelly Pearls What would you like to do? v: view orders p: place an order d: get the details of an order d 2 Invalid order number What would you like to do? v: view orders p: place an order d: get the details of an order Thanks for visiting!
Assumptions/Restrictions/Clarifications
- All of the bubble tea shop functionality has been implemented for you. Your task is to complete the free_shop function
- When using the p command, toppings can be scanned in until 0 is input.
bubble_tea.c
// Simulates a bubble tea store by taking orders and printing orders
// Consists of a bubble tea store that contains a list of orders
// Each order has a list of toppings
#include <stdio.h>
#include <stdlib.h>
#define VIEW_ORDERS 'v'
#define PLACE_ORDER 'p'
#define DETAILS 'd'
#define NO_MORE_TOPPINGS 0
enum tea {
BLACK,
GREEN,
MILK,
};
enum topping_type {
PEARLS = 1,
LYCHEE_JELLY,
RED_BEAN,
GRASS_JELLY,
};
struct topping {
enum topping_type type;
struct topping *next;
};
struct bubble_tea {
enum tea base;
int sugar;
int ice;
struct topping *toppings;
struct bubble_tea *next;
};
struct bubble_tea_shop {
struct bubble_tea *orders;
};
void view_orders(struct bubble_tea_shop *shop);
void place_order(struct bubble_tea_shop *shop);
void details(struct bubble_tea_shop *shop);
void free_shop(struct bubble_tea_shop *shop);
void free_toppings(struct topping *topping);
void print_bubble_tea(struct bubble_tea *bt, int position);
void command_loop(struct bubble_tea_shop *shop);
int main(void) {
printf("Welcome to the Bubble Tea Shop!\n");
struct bubble_tea_shop *shop = malloc(sizeof(struct bubble_tea_shop));
shop->orders = NULL;
command_loop(shop);
printf("Thanks for visiting!\n");
free_shop(shop);
return 0;
}
// Loops until CTRL + D, taking in commands:
// 'v': prints the tea bases of all bubble teas ordered so far
// 'p': appends a new bubble tea order to the end of the list of orders
// 'd': gets the details of a specific order (sugar, ice and toppings)
void command_loop(struct bubble_tea_shop *shop) {
printf("\nWhat would you like to do?\n");
printf("v: view orders\np: place an order\nd: get the details of an order\n\n");
char command;
while (scanf(" %c", &command) == 1) {
if (command == VIEW_ORDERS) {
view_orders(shop);
} else if (command == PLACE_ORDER) {
place_order(shop);
} else if (command == DETAILS) {
details(shop);
}
printf("\nWhat would you like to do?\n");
printf("v: view orders\np: place an order\nd: get the details of an order\n\n");
}
}
// Prints the tea base of all orders in the shop, with their position indexed from 1
void view_orders(struct bubble_tea_shop *shop) {
if (shop->orders == NULL) {
printf("No orders!!!\n");
return;
}
struct bubble_tea *curr = shop->orders;
int i = 1;
while (curr != NULL) {
print_bubble_tea(curr, i);
i++;
curr = curr->next;
if (curr != NULL) {
printf("\t|\n\tv\n");
}
}
}
// Scans in details for a bubble tea order:
// Base
// Sugar
// Ice
// Toppings until 0 is entered
// Appends the bubble tea order to the end of the list of orders in the shop
void place_order(struct bubble_tea_shop *shop) {
// create the bubble tea and scan in fields
struct bubble_tea *bt = malloc(sizeof(struct bubble_tea));
int base;
int sugar;
int ice;
int topping;
scanf("%d %d %d %d", &base, &sugar, &ice, &topping);
bt->base = base;
bt->sugar = sugar;
bt->ice = ice;
bt->toppings = NULL;
bt->next = NULL;
// create a list of toppings until 0 is entered
struct topping *curr_topping = bt->toppings;
while (topping != NO_MORE_TOPPINGS) {
struct topping *new_topping = malloc(sizeof(struct topping));
new_topping->type = topping;
new_topping->next = NULL;
if (curr_topping == NULL) {
bt->toppings = new_topping;
curr_topping = new_topping;
} else {
curr_topping->next = new_topping;
curr_topping = curr_topping->next;
}
scanf(" %d", &topping);
}
// append new bubble tea to end of list
struct bubble_tea *curr_bt = shop->orders;
// empty list
if (curr_bt == NULL) {
shop->orders = bt;
return;
}
// normal append case
while (curr_bt->next != NULL) {
curr_bt = curr_bt->next;
}
curr_bt->next = bt;
return;
}
// Prints out the details of a specific bubble tea
// sugar, ice and all toppings
void details(struct bubble_tea_shop *shop) {
int position;
scanf("%d", &position);
struct bubble_tea *curr_bt = shop->orders;
int i = 1;
while (i < position && curr_bt != NULL) {
i++;
curr_bt = curr_bt->next;
}
if (curr_bt == NULL) {
printf("Invalid order number\n");
return;
}
printf("Sugar: %d\nIce: %d\n", curr_bt->sugar, curr_bt->ice);
printf("The toppings in this bubble tea are:\n");
if (curr_bt->toppings == NULL) {
printf("no toppings\n");
return;
}
struct topping *curr_topping = curr_bt->toppings;
while (curr_topping != NULL) {
if (curr_topping->type == PEARLS) {
printf("Pearls\n");
} else if (curr_topping->type == LYCHEE_JELLY) {
printf("Lychee Jelly\n");
} else if (curr_topping->type == RED_BEAN) {
printf("Red Bean\n");
} else if (curr_topping->type == GRASS_JELLY) {
printf("Grass Jelly\n");
}
curr_topping = curr_topping->next;
}
}
// Frees all toppings, bubble teas, and the shop itself
void free_shop(struct bubble_tea_shop *shop) {
struct bubble_tea *bt = shop->orders;
while (bt != NULL) {
free_toppings(bt->toppings);
struct bubble_tea *temp = bt;
bt = bt->next;
free(temp);
}
free(shop);
}
// frees all toppings including the supplied head topping
void free_toppings(struct topping *topping) {
while (topping != NULL) {
struct topping *temp = topping;
topping = topping->next;
free(temp);
}
}
// prints a single bubble tea's given position and base
void print_bubble_tea(struct bubble_tea *bt, int position) {
printf("%d. ", position);
if (bt->base == BLACK) {
printf("Black Tea\n");
} else if (bt->base == GREEN) {
printf("Green Tea\n");
} else if (bt->base == MILK) {
printf("Milk Tea\n");
} else {
printf("Unknown base\n");
}
}
Exercise — individual:
Merge Lists (Revision Session Exercise)
Copy the file(s) for this exercise to your CSE account using the following command:
1511 fetch-revision 11
Complete the program merge_lists.c
which takes 2 lists with elements in ascending order, and combines those lists while preserving the ascending order.
The input for this function is provided in the main function.
No autotests are provided for this question.
Examples
dcc merge_lists.c -o merge_lists ./merge_lists List 1: 0 -> 5 -> 40 -> X List 2: 1 -> 3 -> 10 -> 100 -> X Merged List: 0 -> 1 -> 3 -> 5 -> 10 -> 40 -> 100 -> X
Assumptions/Restrictions/Clarifications
- The 2 given lists are not necessarily the the same length.
- The elements of the new list should be in ascending order.
- This program does not take in any input from the terminal
merge_lists.c
// Merges 2 sorted linked lists
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STR_LEN 1024
struct node {
int data;
struct node *next;
};
struct node *create_node(int value);
struct node *append_node(struct node *head, int value);
struct node *merge_lists(struct node *l1, struct node *l2);
void print_list(struct node *head);
void free_list(struct node *head);
int main(void) {
struct node *list1 = NULL;
list1 = append_node(list1, 0);
list1 = append_node(list1, 5);
list1 = append_node(list1, 40);
struct node *list2 = NULL;
list2 = append_node(list2, 1);
list2 = append_node(list2, 3);
list2 = append_node(list2, 10);
list2 = append_node(list2, 100);
printf("List 1:\n");
print_list(list1);
printf("List 2:\n");
print_list(list2);
struct node *list3 = merge_lists(list1, list2);
printf("Merged List:\n");
print_list(list3);
free_list(list3);
}
struct node *create_node(int value) {
struct node *new = malloc(sizeof(struct node));
new->data = value;
new->next = NULL;
return new;
}
struct node *append_node(struct node *head, int value) {
struct node *new = create_node(value);
if (head == NULL) {
return new;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new;
return head;
}
struct node *merge_lists(struct node *l1, struct node *l2) {
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
struct node *head = NULL;
struct node *curr1 = l1;
struct node *curr2 = l2;
struct node *prev = NULL;
while (curr1 != NULL && curr2 != NULL) {
if (curr1->data <= curr2->data) {
if (head == NULL) {
head = curr1;
prev = head;
} else {
prev->next = curr1;
prev = curr1;
}
curr1 = curr1->next;
} else {
if (head == NULL) {
head = curr2;
prev = head;
} else {
prev->next = curr2;
prev = curr2;
}
curr2 = curr2->next;
}
}
if (curr1 != NULL) {
prev->next = curr1;
} else {
prev->next = curr2;
}
return head;
}
void print_list(struct node *head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("X\n");
}
void free_list(struct node *head) {
while (head != NULL) {
struct node *temp = head;
head = head->next;
free(temp);
}
}
Exercise — individual:
Reverse a Linked List (Revision Session Exercise)
Download list_reverse.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_reverse
Your task is to add code to this function in list_reverse.c:
//
// Place the list pointed to by head into reverse order.
// The head of the list is returned.
//
struct node *reverse(struct node *head) {
// PUT YOUR CODE HERE (change the next line!)
return NULL;
}
Note list_reverse.c
uses the following familiar data type:
struct node { struct node *next; int data; };
list_reverse
is given one argument, head
which is the pointer to the first
node in the linked list.
Add code to reverse
which rearranges the list to be in reverse order.
reverse
should return a pointer to the new list.
reverse
must rearrange the list by changing the next
fields of nodes.
reverse
must not change the data
fields of nodes.
For example if the linked list contains these 8 elements:
16, 7, 8, 12, 13, 19, 21, 12
reverse
should return a pointer to a list with these elements:
12, 21, 19, 13, 12, 8, 7, 16
Testing
list_reverse.c
also contains a main
function which allows you to test your
list_reverse
function.
This main function:
- takes in the size of the linked list,
- converts the input numbers to a linked list,
- assigns a pointer to the first node in the linked list to
head
, - calls
reverse(head)
and - prints the result.
Do not change this function. If you want to change it, you have misread the question.
Your list_reverse
function will be called directly in marking. The main
function is only to let you test your list_reverse
function
Examples
dcc list_reverse.c -o list_reverse ./list_reverse How many numbers in list?: 8 16 7 8 12 13 19 21 12 [12, 21, 19, 13, 12, 8, 7, 16] ./list_reverse How many numbers in list?: 6 2 4 6 2 4 6 [6, 4, 2, 6, 4, 2] ./list_reverse 42 How many numbers in list?: 1 42 [42] ./list_reverse How many numbers in list?: 0 []
Assumptions/Restrictions/Clarifications
list_reverse
should not change the data fields of list nodeslist_reverse
should not use arrayslist_reverse
should not callmalloc
list_reverse
should not call scanf (orgetchar
orfgets
)list_reverse
should not print anything. It should not callprintf
- Do not change the supplied
main
function. It will not be tested or marked
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_reverse
list_reverse.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
int data;
};
struct node *reverse(struct node *head);
struct node *array_to_list(int len, int array[]);
void print_list(struct node *head);
// DO NOT CHANGE THIS MAIN FUNCTION
#define MAX_INIT_LIST_LEN 100
int main() {
// Need to read in a number of ints into an array
printf("How many numbers in list?: ");
int list_size = 0;
scanf("%d", &list_size);
int initial_elems[MAX_INIT_LIST_LEN] = {0};
int n_read = 0;
while (n_read < list_size && scanf("%d", &initial_elems[n_read])) {
n_read++;
}
// create linked list from first set of inputs
struct node *head = NULL;
if (n_read > 0) {
// list has elements
head = array_to_list(n_read, initial_elems);
}
struct node *new_head = reverse(head);
print_list(new_head);
return 0;
}
// Place the list into reverse order.
// The head of the list is returned.
struct node *reverse(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *previous = NULL;
struct node *x = head;
while (x != NULL) {
struct node *y = x->next;
x->next = previous;
previous = x;
x = y;
}
return previous;
}
// DO NOT CHANGE THIS FUNCTION
// create linked list from array of strings
struct node *array_to_list(int len, int array[]) {
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 = array[i];
head = n;
i -= 1;
}
return head;
}
// print linked list
void print_list(struct node *head) {
printf("[");
for (struct node *n = head; n != NULL; n = n->next) {
// If you're getting an error here,
// you have returned an invalid list
printf("%d", n->data);
if (n->next != NULL) {
printf(", ");
}
}
printf("]\n");
}
list_reverse.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node {
struct node *next;
int data;
};
// Place the list into reverse order.
// The head of the list is returned.
struct node *reverse(struct node *head) {
// lists of 0 or 1 node don't need to be changed
if (head == NULL || head->next == NULL) {
return head;
}
//reverse rest of list
struct node *new_head = reverse(head->next);
// head->next will be the last element in the reversed rest of list
// append head to it
head->next->next = head;
head->next = NULL;
return new_head;
}
Exercise — individual:
Filter a 1D array
Download filter_list.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity filter_list
Your task is to write a program to find the number of bags from people over a specified height.
More specifically, your program should do the following.
- Scan in 5 pairs of height and number of bags, and store these pairs in an array of structs
- Ask the user for a minimum height to filter by
- Find the number of bags, from people who were greater than or equal to that height
This program has some starter code which includes the following struct.
struct passenger {
double height;
int num_bags;
};
The starter code also creates an array for you to store data in.
struct passenger my_array[SIZE];
Examples
dcc filter_list.c -o filter_list ./filter_list Enter height & number of bags: 150.0 1 Enter height & number of bags: 160.0 2 Enter height & number of bags: 170.0 3 Enter height & number of bags: 180.0 1 Enter height & number of bags: 190.0 2 Select height: 170.0 Total of 6 bags from people over 170.000000 ./filter_list Enter height & number of bags: 150.0 1 Enter height & number of bags: 160.0 1 Enter height & number of bags: 170.0 1 Enter height & number of bags: 180.0 1 Enter height & number of bags: 190.0 1 Select height: 200.0 Total of 0 bags from people over 200.000000
Assumptions/Restrictions/Clarifications
- Your program should match the output shown above exactly.
- You can assume you will always be given the correct data type during input.
- You can assume a height is always a positive and non-zero number.
- You can assume the number of bags is non-negative.
- Your program should still work when a person has no baggage.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest filter_list
filter_list.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
struct passenger {
double height;
int num_bags;
};
int main(void) {
struct passenger my_array[SIZE];
for(int i = 0; i < SIZE; i++) {
printf("Enter height & number of bags: ");
scanf("%lf %d", &my_array[i].height, &my_array[i].num_bags);
}
double filter_height;
printf("Select height: ");
scanf("%lf", &filter_height);
int count = 0;
for (int i = 0; i < SIZE; i++) {
if (my_array[i].height >= filter_height) {
count += my_array[i].num_bags;
}
}
printf("Total of %d bags from people over %lf\n", count, filter_height);
return 0;
}
Exercise — individual:
Find totals of rows
Download find_totals.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity find_totals
Your task is to add code to this function in find_totals.c:
int find_totals(int arr[SIZE][SIZE], int size) {
// TODO: Find the number of rows with a
// sum equal to exactly 10
return 0;
}
Given a 2d arrays of integers, your task is to find the number of rows where the sum of the integers equates to exactly 10.
You can assume the given array is always of size 5
You can assume the array always has the same number of rows and columns (The array is always square)
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions it is helpful.
For example, if the following 2D array was given
The output should be exactly
dcc find_totals.c -o find_totals ./find_totals 2 rows had a sum of 10
This output is becasue rows 2 and 3 each have a sum of exactly 10.
Your function should work when there are arrays with no rows equal to 10.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest find_totals
find_totals.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
int find_totals(int arr[SIZE][SIZE], int size);
int main(void) {
int array1[SIZE][SIZE] = {{0, 3, 2, 5, 2},
{2, 1, 5, 1, 1}, // == 10
{4, 4, 7, 7, 0},
{10, 0, 0, 0, 0}, // == 10
{0, 0, 0, 0 ,0}};
printf("%d rows had a sum of 10\n", find_totals(array1, SIZE));
return 0;
}
int find_totals(int arr[SIZE][SIZE], int size) {
int count = 0;
for (int row = 0; row < size; row++) {
int row_total = 0;
for (int col = 0; col < size; col++) {
row_total += arr[row][col];
}
if (row_total == 10) {
count++;
}
}
return count;
}
Exercise — individual:
Insert after lowest
Download list_insert_after_lowest.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_insert_after_lowest
Your task is to add code to this function in list_insert_after_lowest.c:
struct node *insert_after_lowest(struct node *head, int data) {
// TODO: Insert a new node with the value, 'data'
// after the node with the lowest data.
return NULL;
}
Given a linked list, your task is to insert a new node, with a specific value, after the node with the lowest values in the linked list.
insert_after_lowest
is given a pointer to a linked list and the data values
that is to be added.
insert_after_lowest
should return a pointer to the linked list
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
insert_after_lowest
should find the lowest value in the linked list, and
insert a new node directly after it.
For example, if the linked list had the values
Head => [4, 2, 6]
And the function was asked to add the value 99, the list after modification would look as the following
Head => [4, 2, 99, 6]
The below shows the output when the program is run with the example given in the starter code main function.
dcc insert_after_lowest.c -o insert_after_lowest ./insert_after_lowest 4 -> 2 -> 6 -> X 4 -> 2 -> 99 -> 6 -> X
Assumptions/Restrictions/Clarifications
insert_after_lowest
should still insert the new node if the list is empty.insert_after_lowest
should only ever insert ONE node after the first instance of the lowest value, even if there are multiple nodes with the same lowest value.
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_insert_after_lowest
list_insert_after_lowest.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *insert_after_lowest(struct node *head, int data);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, 2);
head = insert_at_head(head, 4);
print_list(head);
head = insert_after_lowest(head, 99);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
// Inserts a new node after the node with the
// lowest data in the list
struct node *insert_after_lowest(struct node *head, int data) {
// If list is empty, insert at the head
if (head == NULL) {
return insert_at_head(NULL, data);
}
int min_val = find_lowest(head);
struct node *curr = head;
while (curr != NULL) {
if (curr->data == min_val) {
struct node *new = create_node(data);
new->next = curr->next;
curr->next = new;
return head;
}
curr = curr->next;
}
return head;
}
// ASSUMES LIST IS NOT NULL
int find_lowest(struct node *head) {
struct node *curr = head;
int min = curr->data;
while (curr != NULL) {
if (curr->data < min) {
min = curr->data;
}
curr = curr->next;
}
return min;
}
Exercise — individual:
Insert in alternating order
Download list_insert_alternating.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_insert_alternating
Your task is to write a program which will read values until EOF, and insert these values into a linked list in an alternating order.
Specifically, your program should read integers from the terminal, until EOF, and insert the first value to the head of the list, then the second value is to the tail of the list, then the third value is added to the head of the list etc.
A minimal starter program is given to you, this program should use the familiar data type
struct node {
int data;
struct node *next;
};
You may also find the given create_node
function helpful in you implementation.
Your program should use the provided print_list
function to print the list after EOF is received.
For example, if your program was given the following inputs
1 2 3 4 5
The resultant linked list should be as follows
Head => [5, 3, 1, 2, 4]
This is because;
- 1 was added to the head of an empty list
- 2 was added to the tail of the list
- 3 was added to the head of the list
- 4 was added to the tail of the list
- 5 was added to the head of the list
Examples
dcc insert_alternating.c -o insert_alternating ./insert_alternating 1 2 3 4 5 5 -> 3 -> 1 -> 2 -> 4 -> X ./insert_alternating 1 1 1 2 2 3 3 3 -> 2 -> 1 -> 1 -> 1 -> 2 -> 3 -> X ./insert_alternating X
Your program should be able to accept an unlimited number of values
Your program should print an empty list if no values were inputted
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_insert_alternating
list_insert_alternating.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
void print_list(struct node *head);
// Your functions
struct node *insert_at_head(struct node *head, int data);
struct node *insert_after_lowest(struct node *head, int data);
struct node *insert_at_tail(struct node *head, int data);
int main(void) {
struct node *head = NULL;
int count = 0;
int data = 0;
while(scanf("%d", &data) == 1) {
if (count % 2 == 0) {
head = insert_at_head(head, data);
} else {
head = insert_at_tail(head, data);
}
count++;
}
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Inserts at the tail of the linked list
// Returns a pointer to the head of the list
struct node *insert_at_tail(struct node *head, int data) {
struct node *new_node = create_node(data);
if (head == NULL) {
return new_node;
}
struct node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
return head;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
Exercise — individual:
Find adjacent point distances
Download adjacent_distances.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity adjacent_distances
Your task is to add code to this function in adjacent_distances.c:
void adjacent_distances(struct coordinate arr[SIZE], int size) {
// TODO: Print the distances between adjacent coordinates
// Your function should NOT return anything
// Your function SHOULD print the distances
}
Your task is to print the Euclidean distance between adjacent coordinates in an array of coordinates.
Specifically, given a 1D array of structs, where each struct contains an x and y coordinate, you need to calculate and print the distance between coordinates stored next to each other in the array.
This program uses the following struct to store coordinates
struct coordinate {
int x;
int y;
};
Coordinates are stored in an array of struct coordinates, always of size 5. This can be seen in the starter program. Note; Some example values are given to the array of structs for your testing
struct coordinate array1[SIZE];
For this array of size 5, you must calculate and print the Euclidean distance between coordinates in
- Index 0 & Index 1
- Index 1 & Index 2
- Index 2 & Index 3
- Index 3 & Index 4
The euclidean distance can be calculated using the provided e_dist
function in the starter code. This function takes in two struct coordinate
and returns the distance between them as a double.
You must implement the function given to you, the function will be called directly in marking and the main function will be ignored. You may create extra function if you find that helpful.
For example, the output of the test input given in the main function, would be
dcc adjacent_distances.c -o adjacent_distances ./adjacent_distances Dist: 1.414214 Dist: 7.000000 Dist: 9.899495 Dist: 9.219544
Your program must produce this output exactly
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest adjacent_distances
adjacent_distances.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SIZE 5
struct coordinate {
int x;
int y;
};
double e_dist(struct coordinate p0, struct coordinate p1);
void adjacent_distances(struct coordinate arr[SIZE], int size);
int main(void) {
// Only your function is called during testing
// Any changes in this main function will not
// be used in testing
struct coordinate array1[SIZE] = {{.x = 1, .y = 1},
{.x = 2, .y = 2},
{.x = 9, .y = 2},
{.x = 2, .y = 9},
{.x = 0, .y = 0}};
adjacent_distances(array1, SIZE);
return 0;
}
void adjacent_distances(struct coordinate arr[SIZE], int size) {
for (int i = 0; i < (size - 1); i++) {
printf("Dist: %lf\n", e_dist(arr[i], arr[i+1]));
}
}
double e_dist(struct coordinate p0, struct coordinate p1) {
return sqrt((p1.x - p0.x)*(p1.x - p0.x)*1.0 + (p1.y - p0.y)*(p1.y - p0.y)*1.0);
}
Exercise — individual:
Clamp a 2D array
Download array_clamping_max.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity array_clamping_max
Your task is to add code to this function in array_clamping_max.c:
void clamp_max(int arr[SIZE][SIZE], int size, int max) {
// TODO: Make sure all values are <= max
// Change any values that are > max
}
Given a 2D array of integers and a maximium value, you must make sure all values within the 2D array are less than or equal to that maximium value. If a value is greater than the max value, you should change the value to be equal to the max value.
For example if the given array was as follows, and the max value was set to 10
Then the array should be changed to be
Your function will be called directly in marking, any changes in the main function will not be used. You may use additional functions if you find it helpful.
You can assume the array is always square and the size is always 5.
The array values given can be any valid integer.
You are not required to print the array, this is handled separately.
You are only required to implement the clamp_max
function.
Examples
dcc adjacent_distances.c -o adjacent_distances ./adjacent_distances Before: 9 3 2 5 2 2 12 5 1 11 4 4 7 7 6 10 0 4 15 0 2 9 0 4 0 After: 9 3 2 5 2 2 10 5 1 10 4 4 7 7 6 10 0 4 10 0 2 9 0 4 0
Your program must produce this output exactly
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest array_clamping_max
array_clamping_max.c
#include <stdio.h>
#include <stdlib.h>
#define SIZE 5
void print_array(int arr[SIZE][SIZE], int size);
void clamp_max(int arr[SIZE][SIZE], int size, int max);
int main(void) {
int array1[SIZE][SIZE] = {{9, 3, 2, 5, 2},
{2, 12, 5, 1, 11},
{4, 4, 7, 7, 6},
{10, 0, 4, 15, 0},
{2, 9, 0, 4, 0}};
printf("Before:\n");
print_array(array1, SIZE);
clamp_max(array1, SIZE, 10);
printf("After:\n");
print_array(array1, SIZE);
return 0;
}
void clamp_max(int arr[SIZE][SIZE], int size, int max) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (arr[row][col] > max) {
arr[row][col] = max;
}
}
}
}
void print_array(int arr[SIZE][SIZE], int size) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
printf("%3d ", arr[row][col]);
}
printf("\n");
}
}
Exercise — individual:
Delete negatives
Download list_delete_negatives.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_delete_negatives
Your task is to add code to this function in list_delete_negatives.c:
struct node *delete_negatives(struct node *head) {
// TODO: Delete any nodes in the linked list
// with a data value < 0
return NULL;
}
Given a linked list, your task is to delete any nodes which have a value strictly less than 0. Any nodes which are deleted must be properly free'd.
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
list_delete_negatives
is given a pointer to a linked list.
list_delete_negatives
should return a pointer to the head of the linked list.
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
Your function should operate normally with an empty linked list.
Your function should not change the list if there are no negative numbers within the list.
You function should not call malloc.
Your function should not have any memory leaks and should pass a leak-check.
For example, if the linked list had the values
Head => [3, 4, -5, 10, -10]
Your function should return a pointer to a linked list with the following values
Head => [3, 4, 10]
Additionally, if the linked list had the values
Head => [-2, -2, 6]
Your function should return a pointer to a linked list with the following values
Head => [6]
Examples
dcc list_delete_negatives.c -o list_delete_negatives ./list_delete_negatives 4 -> -2 -> 6 -> X 4 -> 6 -> X
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_delete_negatives
list_delete_negatives.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *delete_negatives(struct node *head);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, -2);
head = insert_at_head(head, 4);
print_list(head);
head = delete_negatives(head);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
struct node *delete_negatives(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *prev = NULL;
struct node *curr = head;
while (curr != NULL) {
if (curr->data < 0) {
struct node *to_del = curr;
// is it the head?
if (prev == NULL) {
curr = curr->next;
head = curr;
free(to_del);
} else {
prev->next = curr->next;
curr = curr->next;
free(to_del);
}
} else {
prev = curr;
curr = curr->next;
}
}
return head;
}
Exercise — individual:
Delete Duplicates
Download list_delete_duplicates.c here
Or, copy these file(s) to your CSE account using the following command:
1511 fetch-activity list_delete_duplicates
Your task is to add code to this function in list_delete_duplicates.c:
struct node *delete_duplicates(struct node *head) {
// TODO: delete any adjacent duplicate values
return NULL;
}
Given a linked list, delete any values which are adjacent duplicates in the linked list.
This program uses the familiar data type below
struct node {
int data;
struct node *next;
};
delete_duplicates
is given a pointer to a linked list.
delete_duplicates
should return a pointer to the head of the linked list.
delete_duplicates
should only remove duplicate values which are next to each
other in the list (adjacent).
delete_duplicates
can delete more than 1 successive duplicate value.
delete_duplicates
should remove all but the first instance of the value in a
set of duplicates, such that the value only appears once in that part of the
list.
The same value can appear multiple times in the linked list, provided they are not adjacent.
delete_duplicates
can remove the same value multiple times in the list.
See the examples for more details
Example 1
For example, if the linked list had the values
Head => [2, 3, 3, 5, 6]
After removing duplicates, the list would become
Head => [2, 3, 5, 6]
Example 2
For example, if the linked list had the values
Head => [10, 11, 11, 11, 11, 12]
After removing duplicates, the list would become
Head => [10, 11, 12]
Example 3
For example, if the linked list had the values
Head => [10, 11, 11, 25, 11, 11]
After removing duplicates, the list would become
Head => [10, 11, 25, 11]
Only this specific function will be called in marking, the main function is only provided for your testing, however you can create more functions if it is helpful.
Your function should operate normally with an empty linked list.
Your function should not change the list if there are no duplicate numbers within the list.
You function should not call malloc.
Your function should not have any memory leaks and should pass a leak-check.
Examples
dcc list_delete_duplicates.c -o list_delete_duplicates ./list_delete_duplicates 2 -> 4 -> 4 -> 6 -> X 2 -> 4 -> 6 -> X
When you think your program is working,
you can use autotest
to run some simple automated tests:
1511 autotest list_delete_duplicates
list_delete_duplicates.c
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// Provided Functions
struct node *create_node(int data);
struct node *insert_at_head(struct node *head, int data);
void print_list(struct node *head);
// Your functions
struct node *delete_duplicates(struct node *head);
// Solution Functions
int find_lowest(struct node *head);
int main(void) {
struct node *head = insert_at_head(NULL, 6);
head = insert_at_head(head, 4);
head = insert_at_head(head, 4);
head = insert_at_head(head, 2);
print_list(head);
head = delete_duplicates(head);
print_list(head);
return 0;
}
// Mallocs a new node and returns a pointer to it
struct node *create_node(int data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->next = NULL;
new_node->data = data;
return new_node;
}
// Inserts at the head of a linked list
// Returns a pointer to the new head of the list
struct node *insert_at_head(struct node *head, int data) {
struct node *new_node = create_node(data);
new_node->next = head;
return new_node;
}
// Prints a linked list
void print_list(struct node *head) {
struct node *curr = head;
while (curr != NULL) {
printf("%d -> ", curr->data);
curr = curr->next;
}
printf("X\n");
}
struct node *delete_duplicates(struct node *head) {
if (head == NULL) {
return NULL;
}
struct node *curr = head;
while (curr != NULL && curr->next != NULL) {
if (curr->data == curr->next->data) {
struct node *to_del = curr->next;
curr->next = curr->next->next;
free(to_del);
} else {
curr = curr->next;
}
}
return head;
}