Here you'll find all the code I've written in the M15B tutorials, as well as some possibly useful information:
cs1521@cse.unsw.edu.au
x.cooney@unsw.edu.au
print_diary.c
// Write a C program, print_diary.c, which prints the contents
// of the file $HOME/.diary to stdout
// $HOME/.diary
// /home/xav/.diary
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *home_environment = getenv("HOME");
printf("home_environment = \"%s\"\n", home_environment);
int path_size = strlen(home_environment) + strlen("/.diary") + 1;
char *path = malloc(path_size);
snprintf(path, path_size, "%s/.diary", home_environment);
printf("path = \"%s\"\n", path);
FILE *stream = fopen(path, "r");
free(path);
int byte;
while ((byte = fgetc(stream)) != EOF) {
putchar(byte);
}
fclose(stream);
}
chmod_if_public_write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
// ./chmod_if_public_write print_diary.c file code.txt
void chmod_if_public_write(char *path);
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
chmod_if_public_write(argv[i]);
}
}
void chmod_if_public_write(char *path) {
// 1. determine the permissions
struct stat statbuf;
if (stat(path, &statbuf) != 0) {
perror(path);
return;
}
// 2. check if the public write bit is set
// rwxrwxrwx
// ^
// 000000010
if ((statbuf.st_mode & S_IWOTH) == 0) {
printf("%s does not have public write bit set!\n", path);
return;
}
// 3. if it is set...
// 4. remove public write bit
// ~2 = 111111101
if (chmod(path, statbuf.st_mode & ~S_IWOTH) == 0) {
// 5. and maybe print out a message
printf("public write bit removed from %s!\n", path);
} else {
perror(path);
}
}
first_line.c
// Write a C program, first_line.c, which is given one command-line argument,
// the name of a file, and which prints the first line of that file to stdout.
// If given an incorrect number of arguments, or if there was an error opening
// the file, it should print a suitable error message.
#include <stdio.h>
#include <stdlib.h>
// $ ./first_line first_line.c
// argv[0] = "./first_line"
// argv[1] = "first_line.c"
// argc = 2
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: ./first_line <file>\n");
return 1;
}
char *path = argv[1];
FILE *stream = fopen(path, "r");
if (stream == NULL) {
perror(path);
return 1;
}
// functions to read from files: fscanf, fread, fgetc, fgets
// functions to writes from files: fprintf, fwrite, fputc
int byte;
while ((byte = fgetc(stream)) != EOF) {
putchar(byte);
if (byte == '\n') {
break;
}
}
if (fclose(stream) != 0) {
perror(path);
}
return 0;
}
get_bit_groups.c
#include <stdint.h>
typedef struct six_bit_groups {
uint8_t middle_bits;
uint8_t lower_bits;
} six_bit_groups_t;
/*
Example:
01100010 10101101 11001100 10010011
^^^ ^^^ ^^^^^^
middle lower
= 46 = 19
01100010 10101101 11001100 10010011 <-- value
00000000 00000000 00000000 00111111 <-- mask
00000000 00000000 00000000 01000000 <-- 1 << 6
00000000 00000000 00000000 00010011 <-- mask & value
*/
six_bit_groups_t get_bit_groups(uint32_t value) {
struct six_bit_groups answer;
uint32_t mask = 0x3F;
// uint32_t mask = 0b111111;
// uint32_t mask = 077;
// uint32_t mask = (1 << 6) - 1;
answer.lower_bits = value & mask;
answer.middle_bits = (value >> 13) & mask;
// answer.middle_bits = (value & (mask << 13)) >> 13;
return answer;
}
float_weird.c
#include <stdio.h>
#include <math.h>
int main(void) {
float a = 0.1;
float b = 0.2;
float sum = a + b;
printf("a = %.20g, b = %.20g and sum = %.20g\n", a, b, sum);
printf("And sum == 0.3 is: %d\n", fabsf(sum - 0.3f) < 0.0001);
}
reverse_bits.c
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
// Reverse a 32 bit value
uint32_t reverse_bits(uint32_t value) {
uint32_t answer = 0;
for (int i = 0; i < 32; i++) {
// want to check if 'bit i' in `value` is set to a 1?
if ((value & (1u << i)) != 0) {
// ==> if it is: we set the 'opposite' bit in answer to a 1
// printf("there's a 1 in bit %d\n", i);
int opposite_bit_position = 31 - i;
answer |= 1ull << opposite_bit_position;
}
}
return answer;
}
int main(void) {
// reverse_bits(42);
assert(reverse_bits(0xFFFFFFFF) == 0xFFFFFFFF);
assert(reverse_bits(0x00000000) == 0x00000000);
assert(reverse_bits(0x1) == 0x80000000);
assert(reverse_bits(0x2) == 0x40000000);
assert(reverse_bits(0x01234567) == 0xE6A2C480);
printf("All tests passed!\n");
return 0;
}
examples.txt
uint16_t a = 0x5566, b = 0xAAAA, c = 0x0001;
a) a | b
b) a & b
c) a ^ b
d) a & ~b
e) c << 6
f) a >> 4
g) a & (b << 1)
h) b | c
i) a & ~c
rec_max.c
#include <stdio.h>
// C function to find the largest element in an array, recursively.
// Returns the value of the largest element in the array.
//
// array: Array to search
// length: Number of elements in the array
int rec_max(int array[], int length) {
int first_element = array[0];
if (length == 1) {
// Handle the base-case of the recursion, at the end of the array.
return first_element;
} else {
// Recurse on the rest of the array.
// Finds the largest element after first_element in the array.
int max_so_far = rec_max(&array[1], length - 1);
// Compare this element with the largest element after it in the array.
if (first_element > max_so_far) {
max_so_far = first_element;
}
return max_so_far;
}
}
int main(void) {
int data[10] = {2, -3, 5, 4, 42, 2, 8, 4, 1, 9};
printf("%d\n", rec_max(data, 10));
return 0;
}
rec_max.s
########################################################################
# COMP1521 24T3 -- ...
#
#
# !!! IMPORTA first_element;NT !!!
# Before starting work on the assignment, make sure you set your tab-width to 8!
# It is also suggested to indent with tabs only.
# Instructions to configure your text editor can be found here:
# https://cgi.cse.unsw.edu.au/~cs1521/24T3/resources/mips-editors.html
# !!! IMPORTANT !!!
#
#
# This program was written by YOUR-NAME-HERE (z5555555)
# on INSERT-DATE-HERE. INSERT-SIMPLE-PROGRAM-DESCRIPTION-HERE
#
# Version 1.0 (12-06-2023): Team COMP1521 <cs1521@cse.unsw.edu.au>
#
########################################################################
.text
rec_max:
# Args:
# - $a0: int array[]
# - $a1: int length
#
# Returns:
# - $v0: const char *
#
# Frame: [$ra, $s0]
# Uses: [$a0, $a1, $s0, $t1, $t2, $t3, $ra, $v0]
# Clobbers: [$s0, $t1, $t2, $t3, $a0, $a1, $v0]
#
# Locals:
# - $s0: first_element
# - $t1: array
# - $t2: length
# - $t3: max_so_far
#
# Structure:
# current_player_str
# -> [prologue]
# -> body
# -> [epilogue]
# int rec_max(int array[], int length) {
rec_max__prologue:
begin
push $ra
push $s0
rec_max__body:
move $t1, $a0
move $t2, $a1
# int first_element = array[0];
lw $s0, ($t1)
bne $t2, 1, rec_max__length_ne_1 # if (length == 1) {
# return first_element;
move $v0, $s0
b rec_max__epilogue
rec_max__length_ne_1: # } else {
# int max_so_far = rec_max(&array[1], length - 1);
addi $a0, $t1, 4 # &array[1]
sub $a1, $t2, 1 # length - 1
jal rec_max
move $t3, $v0
ble $s0, $t3, rec_max__ret_max_so_far # if (first_element > max_so_far) {
# max_so_far = first_element;
move $t3, $s0
rec_max__ret_max_so_far: # }
# return max_so_far;
move $v0, $t3
rec_max__epilogue: # }
pop $s0
pop $ra
end
jr $ra
main:
main__prologue:
push $ra
main__body:
la $a0, test_data
li $a1, 10
jal rec_max # result = rec_max(test_data, 10)
move $a0, $v0
li $v0, 1 # syscall 1: print_int
syscall # printf("%d", result);
li $v0, 11 # syscall 11: print_char
li $a0, '\n'
syscall # printf("%c", '\n');
li $v0, 0
main__epilogue:
pop $ra
jr $ra # return 0;
.data
test_data:
.word 2, -3, 5, 4, 42, 2, 8, 4, 1, 9
topography.c
// A topographic map!
// This helpful tool will tell explorers how much they need to climb to
// reach various points of interest.
// Given an array of points, `my_points`, it can look up individual cells
// in the 2D map and print their height.
#include <stdio.h>
#define NUM_ROWS 5
#define NUM_COLS 5
#define N_POINTS 4
// 2D representation of a point, stored as a single struct
struct point2D {
int row;
int col;
} typedef point2D_t;
// 2D grid representing the height data for an area.
int topography_grid[NUM_ROWS][NUM_COLS] = {
{ 0, 1, 1, 2, 3 },
{ 1, 1, 2, 3, 4 },
{ 1, 2, 3, 5, 7 },
{ 3, 3, 4, 5, 6 },
{ 3, 4, 5, 6, 7 },
};
// Points of interest to print heights for, as a 1D array.
point2D_t my_points[N_POINTS] = {
{ 1, 2 },
{ 2, 3 },
{ 0, 0 },
{ 4, 4 },
};
int main(void) {
for (int i = 0; i < N_POINTS; i++) {
int row = my_points[i].row;
int col = my_points[i].col;
int height = topography_grid[row][col];
printf("Height at %d,%d=%d\n", row, col, height);
}
return 0;
}
topography.s
# A topographic map!
# Constants
NUM_ROWS = 5
NUM_COLS = 5
N_POINTS = 4
SIZEOF_INT = 4
SIZEOF_POINT2D = 8
POINT2D_ROW_OFFSET = 0
POINT2D_COL_OFFSET = 4
.data
# 2D grid representing the height data for an area.
topography_grid:
.word 0, 1, 1, 2, 3
.word 1, 1, 2, 3, 4
.word 1, 2, 3, 5, 7
.word 3, 3, 4, 5, 6
.word 3, 4, 5, 6, 7
# Points of interest to print heights for, as a 1D array of point2D_t structs.
# Note the memory layout of this array: each element requires 8 bytes, not 4.
my_points:
.word 1, 2
.word 2, 3
.word 0, 0
.word 4, 4
height_str:
.asciiz "Height at "
.text
main:
# Registers:
# - $t0: int i, the loop counter
# - $t1: row of the current point
# - $t2: col of the current point
# - $t3: height of the current point
# - $t4: temporary result for array indexing
# - $t5: temporary result for array indexing
# Loop over all elements, and print their data
points_loop_init: # for (int i = 0; i < N_POINTS; i++) {
li $t0, 0 # $t0 = 0
points_loop_cond:
bge $t0, N_POINTS, points_loop_end # if (i >= N_POINTS)
# We have i in $t0
# We want row in $t1
# We want col in $t2
# We want height in $t3
# int row = my_points[i].row;
# 1. figure out address, get it in a register
# get &my_points[i]
la $t4, my_points
mul $t5, $t0, SIZEOF_POINT2D
add $t4, $t4, $t5 # &my_points[i]
# 2. is it a load or store? ==> it's a load
# 3. byte, half or word? ==> word
lw $t1, ($t4)
# int col = my_points[i].col;
lw $t2, POINT2D_COL_OFFSET($t4)
# int height = topography_grid[row][col];
# &data[row][col] = base + (row * NUM_COLS + col) * sizeof(element)
mul $t4, $t1, NUM_COLS
add $t4, $t4, $t2
mul $t4, $t4, 4
la $t5, topography_grid
add $t4, $t4, $t5
lw $t3, ($t4)
# printf("Height at %d,%d=%d\n", row, col, height);
li $v0, 4 # $v0 = 4 (print string)
la $a0, height_str # load address of height_str into $a0
syscall # print height_str
li $v0, 1 # $v0 = 1 (print int)
move $a0, $t1 # $a0 = row
syscall # print row
li $v0, 11 # $v0 = 11 (print ASCII character)
li $a0, ',' # $a0 = ','
syscall # print ','
li $v0, 1 # $v0 = 1 (print int)
move $a0, $t2 # $a0 = col
syscall # print col
li $v0, 11 # $v0 = 11 (print ASCII character)
li $a0, '=' # $a0 = '='
syscall # print '='
li $v0, 1 # $v0 = 1 (print int)
move $a0, $t3 # $a0 = height
syscall # print height
li $v0, 11 # $v0 = 11 (print ASCII character)
li $a0, '\n' # $a0 = '\n'
syscall # print '\n'
points_loop_iter:
addi $t0, $t0, 1 # i++
b points_loop_cond # branch to points_loop_cond
points_loop_end:
jr $ra # return 0;
print_array.c
// A simple program that will print 10 numbers from an array
#define N_SIZE 10
#include <stdio.h>
// int -> word
// short -> half
// char -> byte
int numbers[N_SIZE] = {
3, 1, 4, 1, 5, 9, 2, 6, 5, 3
};
int main(void) {
int i;
i = 0;
while (i < N_SIZE) {
int num = numbers[i];
printf("%d\n", num);
i++;
}
}
print_array.s
N_SIZE = 10
main:
# Locals:
# i: $t0
# num: $t1
loop__init:
# i = 0;
li $t0, 0
loop__cond:
# while (i < N_SIZE) {
bge $t0, N_SIZE, loop__end
loop__body:
# int num = numbers[i];
# 1. what is the addrss of the object?
# &numbers[i] = &numbers + sizeof(element) * i
la $t2, numbers # &numbers
mul $t3, $t0, 4 # i * 4
add $t2, $t2, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. is it a byte, a half or a word?
# ==> it's a word
# 3. is it a load or a store?
# ==> it's a load
lw $t1, ($t2)
# printf("%d\n", num);
li $v0, 1
move $a0, $t1
syscall
li $v0, 11
li $a0, '\n'
syscall
loop__increment:
# i++;
addi $t0, $t0, 1
b loop__cond
# }
loop__end:
# return 0;
li $v0, 0
jr $ra
.data
numbers:
.word 3, 1, 4, 1, 5, 9, 2, 6, 5, 3
read_array.c
// A simple program that will read 10 numbers into an array
#define N_SIZE 5
#include <stdio.h>
int numbers[N_SIZE];
int main(void) {
int i;
i = 0;
while (i < N_SIZE) {
scanf("%d", &numbers[i]);
i++;
}
i = 0;
while (i < N_SIZE) {
int num = numbers[i];
printf("%d\n", num);
i++;
}
}
read_array.s
N_SIZE = 5
main:
# Locals:
# i: $t0
# num: $t1
loop_read__init:
li $t0, 0
loop_read__cond:
bge $t0, N_SIZE, loop_read__end
loop_read__body:
# scanf("%d", &numbers[i]);
# numbers[i] = read_int();
li $v0, 5
syscall
move $t4, $v0
# 1. what is the addrss of the object?
# &numbers[i] = &numbers + sizeof(element) * i
la $t2, numbers # &numbers
mul $t3, $t0, 4 # i * 4
add $t2, $t2, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. is it a byte, a half or a word?
# ==> it's a word
# 3. is it a load or a store?
# ==> it's a store
sw $t4, ($t2)
loop_read__increment:
# i++;
addi $t0, $t0, 1
b loop_read__cond
loop_read__end:
loop_print__init:
# i = 0;
li $t0, 0
loop_print__cond:
# while (i < N_SIZE) {
bge $t0, N_SIZE, loop_print__end
loop_print__body:
# int num = numbers[i];
# 1. what is the addrss of the object?
# &numbers[i] = &numbers + sizeof(element) * i
la $t2, numbers # &numbers
mul $t3, $t0, 4 # i * 4
add $t2, $t2, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. is it a byte, a half or a word?
# ==> it's a word
# 3. is it a load or a store?
# ==> it's a load
lw $t1, ($t2)
# printf("%d\n", num);
li $v0, 1
move $a0, $t1
syscall
li $v0, 11
li $a0, '\n'
syscall
loop_print__increment:
# i++;
addi $t0, $t0, 1
b loop_print__cond
# }
loop_print__end:
# return 0;
li $v0, 0
jr $ra
.data
numbers:
# .word 0:N_SIZE
.align 2
.space N_SIZE*4
hello.s
# Write a MIPS assembly program that prints out "Hello, world!\n"
main:
li $v0, 4 # $v0 = 4
la $a0, hello_world_string # $a0 = address of hello_world_string
syscall
li $v0, 0
jr $ra # return 0;
.data
hello_world_string:
.asciiz "Hello, world!\n"
square.c
// Prints the square of a number
#include <stdio.h>
int main(void) {
int x, y;
printf("Enter a number: ");
scanf("%d", &x);
y = x * x;
printf("%d", y);
putchar('\n');
}
square.s
main:
# Locals:
# - x: $t0
# - y: $t1
li $v0, 4 # $v0 4: print_string syscall
la $a0, enter_a_number_str
syscall # printf("Enter a number: ");
li $v0, 5 # $v0 5: read_int syscall
syscall # scanf("%d", &x);
move $t0, $v0 # $t0 = $v0
mul $t1, $t0, $t0 # y = x * x
li $v0, 1
move $a0, $t1
syscall # printf("%d", y);
li $v0, 11
li $a0, '\n'
syscall # putchar('\n');
li $v0, 0
jr $ra # return 0;
.data
enter_a_number_str:
.asciiz "Enter a number: "
bounded_square.c
// Squares a number, unless its square is too big for a 32-bit integer.
// If it is too big, prints an error message instead.
#include <stdio.h>
#define SQUARE_MAX 46340
int main(void) {
int x, y;
printf("Enter a number: ");
scanf("%d", &x);
// if (x > SQUARE_MAX) {
// if (x <= SQUARE_MAX)
// goto else_branch;
if (x > SQUARE_MAX) goto if_branch;
goto else_branch;
if_branch:
printf("square too big for 32 bits\n");
goto epilogue;
// } else {
else_branch:
y = x * x;
printf("%d\n", y);
// }
epilogue:
return 0;
}
bounded_square.s
SQUARE_MAX = 46340
main:
# Locals:
# - x: $t0
# - y: $t1
li $v0, 4
la $a0, enter_a_number_str
syscall # printf("Enter a number: ");
li $v0, 5
syscall # scanf("%d", &x);
move $t0, $v0 # $t0 = $v0
ble $t0, SQUARE_MAX, else_branch
li $v0, 4
la $a0, square_too_big
syscall
b epilogue
else_branch:
mul $t1, $t0, $t0 # y = x * x
li $v0, 1
move $a0, $t1
syscall
li $v0, 11
li $a0, '\n'
syscall
epilogue:
li $v0, 0
jr $ra
.data
enter_a_number_str:
.asciiz "Enter a number: "
square_too_big:
.asciiz "square too big for 32 bits\n"
for.c
// Print every third number from 24 to 42.
#include <stdio.h>
int main(void) {
// for (int x = 24; x < 42; x += 3) {
// printf("%d\n", x);
// }
loop_init:;
int x =24;
loop_cond:
if (x >= 42) goto loop_end;
loop_body:
printf("%d\n", x);
loop_increment:
x += 3;
goto loop_init;
loop_end:
}
factorial_scanf.c
// Write a program which calculates n!, where
// n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
// e.g.
// 1! = 1 = 1
// 2! = 2 * 1 = 2
// 3! = 3 * 2 * 1 = 6
// 4! = 4 * 3 * 2 * 1 = 24
// 5! = 5 * 4 * 3 * 2 * 1 = 120
#include <stdio.h>
int main(void) {
int n;
if (scanf("%d", &n) != 1) {
printf("Invalid input!\n");
return 1;
}
int product = 1;
for (int counter = 1; counter <= n; counter++) {
product = product * counter;
}
// product = 1
// product = 1
// product = 2
// product = 6
// product = 24
// product = 120
printf("product = %d\n", product);
return 0;
}
factorial.c
// Write a program which calculates n!, where
// n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
// e.g.
// 1! = 1 = 1
// 2! = 2 * 1 = 2
// 3! = 3 * 2 * 1 = 6
// 4! = 4 * 3 * 2 * 1 = 24
// 5! = 5 * 4 * 3 * 2 * 1 = 120
#include <stdio.h>
#include <stdlib.h>
// ./factorial 5 hiii
// argv[0] = "./factorial"
// argv[1] = "5"
// argv[2] = "hiii"
// argc = 3
// factorial_recurse(n) returns the factorial of n.
int factorial_recurse(int n) {
if (n == 0) {
return 1;
}
return n * factorial_recurse(n - 1);
// n! = n * (n - 1) * (n - 2) * ... * 2 * 1;
// n! = n * ((n - 1) * (n - 2) * ... * 2 * 1);
// n! = n * (n - 1)!
// int product = 1;
// for (int counter = 1; counter <= n; counter++) {
// product = product * counter;
// }
// return product;
}
int main(int argc, char *argv[]) {
int n = atoi(argv[1]);
printf("n = %d\n", n);
printf("factorial_recurse(n) = %d\n", factorial_recurse(n));
return 0;
}