Rename year directories to allow natural ordering

This commit is contained in:
2023-12-20 03:57:27 +00:00
parent 0ab1f5ad3a
commit 1f7d812b98
1895 changed files with 0 additions and 7188 deletions

View File

@ -0,0 +1,15 @@
#include <stdio.h>
int main() {
int my_int;
int* my_int_pointer;
long my_long;
double * my_double_pointer;
char ** my_char_pointer_pointer;
printf("The size of my_int is %lu bytes\n", sizeof(my_int));
printf("The size of my_int_pointer is %lu bytes\n", sizeof(my_int_pointer));
printf("The size of my_long is %lu bytes\n", sizeof(my_long));
printf("The size of my_double_pointer is %lu bytes\n", sizeof(my_double_pointer));
printf("The size of my_char_pointer_pointer is %lu bytes\n", sizeof(my_char_pointer_pointer));
}

View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/question2.iml" filepath="$PROJECT_DIR$/.idea/question2.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

View File

@ -0,0 +1,8 @@
#include <stdio.h>
#include "linkedList.h"
#include "tests.h"
int main(int argc, char* argv[]){
runTests();
return 0;
}

View File

@ -0,0 +1,162 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkedList.h"
typedef struct listElementStruct{
char* data;
size_t size;
struct listElementStruct* next;
} listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(char* data, size_t size){
listElement* e = malloc(sizeof(listElement));
if(e == NULL){
//malloc has had an error
return NULL; //return NULL to indicate an error.
}
char* dataPointer = malloc(sizeof(char)*size);
if(dataPointer == NULL){
//malloc has had an error
free(e); //release the previously allocated memory
return NULL; //return NULL to indicate an error.
}
strcpy(dataPointer, data);
e->data = dataPointer;
e->size = size;
e->next = NULL;
return e;
}
//Prints out each element in the list
void traverse(listElement* start){
listElement* current = start;
while(current != NULL){
printf("%s\n", current->data);
current = current->next;
}
}
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* el, char* data, size_t size){
listElement* newEl = createEl(data, size);
listElement* next = el->next;
newEl->next = next;
el->next = newEl;
return newEl;
}
//Delete the element after the given el
void deleteAfter(listElement* after){
listElement* delete = after->next;
listElement* newNext = delete->next;
after->next = newNext;
//need to free the memory because we used malloc
free(delete->data);
free(delete);
}
// returns the number of elements in the list
int length(listElement* list) {
int length = 0;
listElement* current = list;
// traversing the list and counting each element
while(current != NULL){
length++;
current = current->next;
}
return length;
}
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, char* data, size_t size) {
// create the new element
listElement* newElement = createEl(data, size);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// pop an element from the head of a list and update the list reference using side effects
// assuming that the desired return value here is the popped element, as is standard for POP operations
listElement* pop(listElement** list) {
// don't bother if list is non existent
if (*list == NULL) { return NULL; }
;
// getting reference to the element to be popped
listElement* poppedElement = *list;
// make the the second element the new head of the list -- this could be NULL, so the list would be NULL also
*list = (*list)->next;
// detach the popped element from the list
poppedElement->next = NULL;
return poppedElement;
}
// enque a new element onto the head of the list and update the list reference using side effects
// essentially the same as push
void enqueue(listElement** list, char* data, size_t size) {
// create the new element
listElement* newElement = createEl(data, size);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// dequeue an element from the tail of the list by removing the element from the list via side effects, and returning the removed item
// assuming that we want to return the dequeued element rather than the list itself, as enqueue returns nothing and uses side effects, so dequeue should also use side effects
listElement* dequeue(listElement* list) {
// there are three cases that we must consider: a list with 0 elements, a list with 1 element, & a list with >=2 elements
// don't bother if list is non existent
if (list == NULL) { return NULL; }
// if there is only one element in the list, i.e. the head element is also the tail element, just returning this element
// this means that the listElement pointer that was passed to this function won't be updated
// ideally, we would set it to NULL but we can't do that since `list` is a pointer that has been passed by value, so we can't update the pointer itself. we would need a pointer to a pointer to have been passed
if (list->next == NULL) {
return list;
}
// traversing the list to find the second-to-last element
listElement* current = list;
while (current->next->next != NULL) {
current = current->next;
}
// get reference to the element to be dequeued
listElement* dequeuedElement = current->next;
// make the penultimate element the tail by removing reference to the old tail
current->next = NULL;
return list;
}

View File

@ -0,0 +1,36 @@
#ifndef CT331_ASSIGNMENT_LINKED_LIST
#define CT331_ASSIGNMENT_LINKED_LIST
typedef struct listElementStruct listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(char* data, size_t size);
//Prints out each element in the list
void traverse(listElement* start);
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* after, char* data, size_t size);
//Delete the element after the given el
void deleteAfter(listElement* after);
// returns the number of elements in the list
int length(listElement* list);
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, char* data, size_t size);
// pop an element from the head of a list and update the list reference using side effects
listElement* pop(listElement** list);
// enque a new element onto the head of the list and update the list reference using side effects
void enqueue(listElement** list, char* data, size_t size);
// dequeue an element from the tail of the list
listElement* dequeue(listElement* list);
#endif

View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include "tests.h"
#include "linkedList.h"
void runTests(){
printf("Tests running...\n");
listElement* l = createEl("Test String (1).", sizeof("Test String (1)."));
//printf("%s\n%p\n", l->data, l->next);
//Test create and traverse
traverse(l);
printf("\n");
//Test insert after
printf("Testing insertAfter()\n");
listElement* l2 = insertAfter(l, "another string (2)", sizeof("another test string(2)"));
insertAfter(l2, "a final string (3)", sizeof("a final string(3)"));
traverse(l);
printf("\n");
// test length function
printf("Testing length()\n");
int l_length = length(l);
printf("The length of l is %d\n\n", l_length);
// test push
printf("Testing push()\n");
push(&l, "yet another test string", sizeof("yet another test string"));
traverse(l);
printf("\n\n");
// test pop
printf("Testing pop()\n");
listElement* popped = pop(&l);
traverse(l);
printf("\n\n");
// Test delete after
printf("Testing deleteAfter()\n");
deleteAfter(l);
traverse(l);
printf("\n");
// test enqueue
printf("Testing enqueue()\n");
enqueue(&l, "enqueued test string", sizeof("enqueued test string"));
traverse(l);
printf("\n");
// test dequeue
printf("Testing dequeue()\n");
dequeue(l);
traverse(l);
printf("\n");
printf("\nTests complete.\n");
}

View File

@ -0,0 +1,6 @@
#ifndef CT331_ASSIGNMENT_TESTS
#define CT331_ASSIGNMENT_TESTS
void runTests();
#endif

View File

@ -0,0 +1,8 @@
#include <stdio.h>
#include "genericLinkedList.h"
#include "tests.h"
int main(int argc, char* argv[]){
runTests();
return 0;
}

View File

@ -0,0 +1,167 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "genericLinkedList.h"
typedef struct listElementStruct{
void* data;
void (*printFunction)(void*);
size_t size;
struct listElementStruct* next;
} listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(void* data, size_t size, void (*printFunction)(void*)) {
listElement* e = malloc(sizeof(listElement));
if(e == NULL){
//malloc has had an error
return NULL; //return NULL to indicate an error.
}
void* dataPointer = malloc(sizeof(void)*size);
if(dataPointer == NULL){
//malloc has had an error
free(e); //release the previously allocated memory
return NULL; //return NULL to indicate an error.
}
strcpy(dataPointer, data);
e->data = dataPointer;
e->printFunction = printFunction;
e->size = size;
e->next = NULL;
return e;
}
//Prints out each element in the list
void traverse(listElement* start){
listElement* current = start;
while(current != NULL){
current->printFunction(current->data);
// printf("%s\n", current->data);
current = current->next;
}
}
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* el, void* data, size_t size, void (*printFunction)(void*)){
listElement* newEl = createEl(data, size, printFunction);
listElement* next = el->next;
newEl->next = next;
el->next = newEl;
return newEl;
}
//Delete the element after the given el
void deleteAfter(listElement* after){
listElement* delete = after->next;
listElement* newNext = delete->next;
after->next = newNext;
//need to free the memory because we used malloc
free(delete->data);
free(delete);
}
// returns the number of elements in the list
int length(listElement* list) {
int length = 0;
listElement* current = list;
// traversing the list and counting each element
while(current != NULL){
length++;
current = current->next;
}
return length;
}
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, void* data, size_t size, void (*printFunction)(void*)) {
// create the new element
listElement* newElement = createEl(data, size, printFunction);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// pop an element from the head of a list and update the list reference using side effects
// assuming that the desired return value here is the popped element, as is standard for POP operations
listElement* pop(listElement** list) {
// don't bother if list is non existent
if (*list == NULL) { return NULL; }
;
// getting reference to the element to be popped
listElement* poppedElement = *list;
// make the the second element the new head of the list -- this could be NULL, so the list would be NULL also
*list = (*list)->next;
// detach the popped element from the list
poppedElement->next = NULL;
return poppedElement;
}
// enque a new element onto the head of the list and update the list reference using side effects
// essentially the same as push
void enqueue(listElement** list, void* data, size_t size, void (*printFunction)(void*)) {
// create the new element
listElement* newElement = createEl(data, size, printFunction);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// dequeue an element from the tail of the list by removing the element from the list via side effects, and returning the removed item
// assuming that we want to return the dequeued element rather than the list itself, as enqueue returns nothing and uses side effects, so dequeue should also use side effects
listElement* dequeue(listElement* list) {
// there are three cases that we must consider: a list with 0 elements, a list with 1 element, & a list with >=2 elements
// don't bother if list is non existent
if (list == NULL) { return NULL; }
// if there is only one element in the list, i.e. the head element is also the tail element, just returning this element
// this means that the listElement pointer that was passed to this function won't be updated
// ideally, we would set it to NULL but we can't do that since `list` is a pointer that has been passed by value, so we can't update the pointer itself. we would need a pointer to a pointer to have been passed
if (list->next == NULL) {
return list;
}
// traversing the list to find the second-to-last element
listElement* current = list;
while (current->next->next != NULL) {
current = current->next;
}
// get reference to the element to be dequeued
listElement* dequeuedElement = current->next;
// make the penultimate element the tail by removing reference to the old tail
current->next = NULL;
return list;
}

View File

@ -0,0 +1,35 @@
#ifndef CT331_ASSIGNMENT_LINKED_LIST
#define CT331_ASSIGNMENT_LINKED_LIST
typedef struct listElementStruct listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(void* data, size_t size, void (*printFunction)(void*));
//Prints out each element in the list
void traverse(listElement* start);
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* after, void* data, size_t size, void (*printFunction)(void*));
//Delete the element after the given el
void deleteAfter(listElement* after);
// returns the number of elements in the list
int length(listElement* list);
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, void* data, size_t size, void (*printFunction)(void*));
// pop an element from the head of a list and update the list reference using side effects
listElement* pop(listElement** list);
// enque a new element onto the head of the list and update the list reference using side effects
void enqueue(listElement** list, void* data, size_t size, void (*printFunction)(void*));
// dequeue an element from the tail of the list
listElement* dequeue(listElement* list);
#endif

View File

@ -0,0 +1,79 @@
#include <stdio.h>
#include "tests.h"
#include "genericLinkedList.h"
// functions to print out different data types
// a more professional design might be to put these in the genericLinkedList header file but i only need these for testing purposes
void printChar(void* data) {
printf("%c\n", *(char*) data);
}
void printStr(void* data) {
printf("%s\n", (char*) data);
}
void printInt(void* data) {
printf("%d\n", *(int*) data);
}
void runTests(){
printf("Tests running...\n");
listElement* l = createEl("Test String (1).", sizeof("Test String (1)."), printStr);
//printf("%s\n%p\n", l->data, l->next);
//Test create and traverse
traverse(l);
printf("\n");
//Test insert after
printf("Testing insertAfter()\n");
listElement* l2 = insertAfter(l, "another string (2)", sizeof("another string (2)"), printStr);
insertAfter(l2, "a final string (3)", sizeof("a final string (3)"), printStr);
traverse(l);
printf("\n");
// test length function
printf("Testing length()\n");
int l_length = length(l);
printf("The length of l is %d\n\n", l_length);
// test push
printf("Testing push()\n");
push(&l, "yet another test string", sizeof("yet another test string"), printStr);
traverse(l);
printf("\n\n");
// test pop
printf("Testing pop()\n");
listElement* popped = pop(&l);
traverse(l);
printf("\n\n");
// Test delete after
printf("Testing deleteAfter()\n");
deleteAfter(l);
traverse(l);
printf("\n");
// test enqueue
printf("Testing enqueue()\n");
enqueue(&l, "enqueued test string", sizeof("enqueued test string"), printStr);
traverse(l);
printf("\n");
// test dequeue
printf("Testing dequeue()\n");
dequeue(l);
traverse(l);
printf("\n");
printf("Testing pushing different data types\n");
int myint = 42;
push(&l, &myint, sizeof(myint), printInt);
char mychar = 'c';
push(&l, &mychar, sizeof(mychar), printChar);
traverse(l);
printf("\n\n");
printf("\nTests complete.\n");
}

View File

@ -0,0 +1,6 @@
#ifndef CT331_ASSIGNMENT_TESTS
#define CT331_ASSIGNMENT_TESTS
void runTests();
#endif

View File

@ -0,0 +1,343 @@
%! TeX program = lualatex
\documentclass[a4paper]{article}
% packages
\usepackage{microtype} % Slightly tweak font spacing for aesthetics
\usepackage[english]{babel} % Language hyphenation and typographical rules
\usepackage[final, colorlinks = false, urlcolor = cyan]{hyperref}
\usepackage{changepage} % adjust margins on the fly
\usepackage{fontspec}
\usepackage{minted}
\usepackage{xcolor}
\usepackage{pgfplots}
\pgfplotsset{width=\textwidth,compat=1.9}
\usepackage{caption}
\newenvironment{code}{\captionsetup{type=listing, skip=0pt}}{}
% \captionsetup{skip=0pt}
% \setlength{\abovecaptionskip}{3pt}
% \setlength{\belowcaptionskip}{5pt}
\usepackage[yyyymmdd]{datetime}
\renewcommand{\dateseparator}{--}
\setmainfont{EB Garamond}
\setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono}
\usepackage{titlesec}
% \titleformat{\section}{\LARGE\bfseries}{}{}{}[\titlerule]
% \titleformat{\subsection}{\Large\bfseries}{}{0em}{}
% \titlespacing{\subsection}{0em}{-0.7em}{0em}
%
% \titleformat{\subsubsection}{\large\bfseries}{}{0em}{$\bullet$ }
% \titlespacing{\subsubsection}{1em}{-0.7em}{0em}
% margins
\addtolength{\hoffset}{-2.25cm}
\addtolength{\textwidth}{4.5cm}
\addtolength{\voffset}{-3.25cm}
\addtolength{\textheight}{5cm}
\setlength{\parskip}{0pt}
\setlength{\parindent}{0in}
% \setcounter{secnumdepth}{0}
\begin{document}
\hrule \medskip
\begin{minipage}{0.295\textwidth}
\raggedright
\footnotesize
Name: Andrew Hayes \\
E-mail: \href{mailto://a.hayes18@universityofgalway.ie}{\texttt{a.hayes18@universityofgalway.ie}} \hfill\\
ID: 21321503 \hfill
\end{minipage}
\begin{minipage}{0.4\textwidth}
\centering
\vspace{0.4em}
\Large
\textbf{CT331} \\
\end{minipage}
\begin{minipage}{0.295\textwidth}
\raggedleft
\today
\end{minipage}
\medskip\hrule
\begin{center}
\normalsize
Assignment 1: Procedural Programming with C
\end{center}
\hrule
\section{Question 1}
\subsection{Part (A): Code}
\begin{code}
\inputminted[texcl, mathescape, linenos, breaklines, frame=single]{C}{../code/question1/question1.c}
\caption{\texttt{question1.c}}
\end{code}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{./images/question1.png}
\caption{Console Output of \texttt{question1.c}}
\end{figure}
\subsection{Part (B): Comments}
The amount of memory allocated to variables of different types in C is determined at compile-time, and is dependent on the architecture of
the machine for which it is being compiled and the compiler used.
\begin{itemize}
\item On my machine, using GCC, an \verb|int| is allocated 4 bytes. This is the usual amount allocated on both 32-bit and 64-bit systems (my machine being of the
latter kind), although older 32-bit systems used 2 bytes for an \verb|int| (the same amount as for a \verb|short|).
4 bytes is used even on 64-bit machines to maintain backwards compatibility with older 32-bit architectures.
\item An \verb|int*| (a pointer to a variable of type \verb|int|) is allocated 8 bytes on my machine.
This is because that my machine has a 64-bit architecture, and therefore an address in memory is represented using 64 bits (8 bytes).
If this were compiled for a 32-bit machine, the size of an pointer would be 4 bytes since addresses are 32-bit.
\item A \verb|long| is allocated 8 bytes on my machine. This is because my machine is 64-bit and a \verb|long| is typically 8 bytes in length on such machines.
On 32-bit machines, a \verb|long| is typically 4 bytes.
\item The size of a pointer to a \verb|double| is the same as the size of any other pointer on the same machine; on 64-bit machines, pointers are 8 bytes, and on
32-bit machines, they are 4 bytes.
The type of data to which a pointer points has no effect on the size of the pointer, as the pointer is just a memory address.
\item A pointer to a \verb|char| pointer is the same size as any other pointer: 8 bytes on a 64-bit machine and 4 bytes on a 32-bit machine.
Note: it might be more intuitive to refer to a ``character pointer pointer'' as a pointer to a string in certain situations, as strings are character arrays,
and an array variable acts as a pointer to the first element in the array.
\end{itemize}
\section{Question 2}
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{C}
// returns the number of elements in the list
int length(listElement* list);
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, char* data, size_t size);
// pop an element from the head of a list and update the list reference using side effects
listElement* pop(listElement** list);
// enque a new element onto the head of the list and update the list reference using side effects
void enqueue(listElement** list, char* data, size_t size);
// dequeue an element from the tail of the list
listElement* dequeue(listElement* list);
\end{minted}
\caption{My Additions to \texttt{linkedList.h}}
\end{code}
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{C}
// returns the number of elements in the list
int length(listElement* list) {
int length = 0;
listElement* current = list;
// traversing the list and counting each element
while(current != NULL){
length++;
current = current->next;
}
return length;
}
// push a new element onto the head of a list and update the list reference using side effects
void push(listElement** list, char* data, size_t size) {
// create the new element
listElement* newElement = createEl(data, size);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// pop an element from the head of a list and update the list reference using side effects
// assuming that the desired return value here is the popped element, as is standard for POP operations
listElement* pop(listElement** list) {
// don't bother if list is non existent
if (*list == NULL) { return NULL; }
;
// getting reference to the element to be popped
listElement* poppedElement = *list;
// make the the second element the new head of the list -- this could be NULL, so the list would be NULL also
*list = (*list)->next;
// detach the popped element from the list
poppedElement->next = NULL;
return poppedElement;
}
// enque a new element onto the head of the list and update the list reference using side effects
// essentially the same as push
void enqueue(listElement** list, char* data, size_t size) {
// create the new element
listElement* newElement = createEl(data, size);
// handle malloc errors
if (newElement == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
// make the the new element point to the current head of the list
newElement->next = *list;
// make the list reference to point to the new head element
*list = newElement;
}
// dequeue an element from the tail of the list by removing the element from the list via side effects, and returning the removed item
// assuming that we want to return the dequeued element rather than the list itself, as enqueue returns nothing and uses side effects, so dequeue should also use side effects
listElement* dequeue(listElement* list) {
// there are three cases that we must consider: a list with 0 elements, a list with 1 element, & a list with >=2 elements
// don't bother if list is non existent
if (list == NULL) { return NULL; }
// if there is only one element in the list, i.e. the head element is also the tail element, just returning this element
// this means that the listElement pointer that was passed to this function won't be updated
// ideally, we would set it to NULL but we can't do that since `list` is a pointer that has been passed by value, so we can't update the pointer itself. we would need a pointer to a pointer to have been passed
if (list->next == NULL) {
return list;
}
// traversing the list to find the second-to-last element
listElement* current = list;
while (current->next->next != NULL) {
current = current->next;
}
// get reference to the element to be dequeued
listElement* dequeuedElement = current->next;
// make the penultimate element the tail by removing reference to the old tail
current->next = NULL;
return list;
}
\end{minted}
\caption{My Additions to \texttt{linkedList.c}}
\end{code}
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{C}
// test length function
printf("Testing length()\n");
int l_length = length(l);
printf("The length of l is %d\n\n", l_length);
// test push
printf("Testing push()\n");
push(&l, "yet another test string", sizeof("yet another test string"));
traverse(l);
printf("\n\n");
// test pop
printf("Testing pop()\n");
listElement* popped = pop(&l);
traverse(l);
printf("\n\n");
// Test delete after
printf("Testing deleteAfter()\n");
deleteAfter(l);
traverse(l);
printf("\n");
// test enqueue
printf("Testing enqueue()\n");
enqueue(&l, "enqueued test string", sizeof("enqueued test string"));
traverse(l);
printf("\n");
// test dequeue
printf("Testing dequeue()\n");
dequeue(l);
traverse(l);
printf("\n");
printf("\nTests complete.\n");
\end{minted}
\caption{My Additions to \texttt{tests.c}}
\end{code}
\begin{figure}[H]
\centering
\includegraphics[width=0.9\textwidth]{./images/question2.png}
\caption{Console Output for Question 2}
\end{figure}
\section{Question 3}
\begin{code}
\inputminted[linenos, breaklines, frame=single]{C}{../code/question3/genericLinkedList.h}
\caption{\texttt{genericLinkedList.h}}
\end{code}
\begin{code}
\inputminted[linenos, breaklines, frame=single]{C}{../code/question3/genericLinkedList.c}
\caption{\texttt{genericLinkedList.c}}
\end{code}
\begin{code}
\inputminted[linenos, breaklines, frame=single]{C}{../code/question3/tests.c}
\caption{\texttt{tests.c}}
\end{code}
\begin{figure}[H]
\centering
\includegraphics[width=0.9\textwidth]{./images/question3.png}
\caption{Console Output for Question 3}
\end{figure}
\section{Question 4}
\subsection{Part 1}
Any algorithm for traversing a singly linked list in reverse will always first require traversing the list forwards, and will therefore be \emph{at least} somewhat
less efficient than a forwards traversal.
One of the simplest ways to traverse a linked list in reverse is to use a recursive function.
\begin{code}
\begin{minted}[linenos, breaklines, frame=single]{C}
void reverse_traverse(listElement* current){
if (current == NULL) { return; }
reverse_traverse(current->next);
current->printFunction(current->data);
}
\end{minted}
\caption{Recursive Function to Traverse a Singly Linked List in Reverse}
\end{code}
This is quite inefficient as it requires that the function call for each node persists on the stack until the last node is reached, using a lot of stack memory.
Another approach would be to iteratively reverse the linked list, by making some kind of data structure, linked list or otherwise, that contains the data of the
original linked list but in reverse, and then iterating over that forwards.
This would likely be more efficient in terms of memory \& computation.
\\\\
Because traversing a linked list in reverse always requires traversing it forwards first, any reverse algorithm will take at least twice as much memory \& computation
as traversing it forwards, which is $O(n)$.
It will also require that some way of storing the data in reverse in memory, either explicitly with a data, like in the iterative approach, or in the same manner
as the recursive approach, wherein the data is stored in reverse by the nested structure of the function calls: as each function call returns, the call structure
is iterated through in reverse.
Therefore, we also have at least $O(n)$ memory usage, as we have to store some sort of reverse data structure.
\subsection{Part 2}
The simplest way in which the structure of a linked list could be changed to make backwards traversal less intensive is to change it from a singly linked list to a
doubly linked list, i.e. instead of each node in the list containing a pointer to just the next node, make each node contain a pointer to both the next node \& the
previous node.
The backwards traversal of a doubly linked list is no more intensive than the forwards traversal of a linked list.
The drawback of using a doubly linked list is that it requires slightly more memory per node than a singly linked list, as you're storing an additional pointer
for every node.
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -0,0 +1,13 @@
#include <stdio.h>
int main(int arg, char* argc[]){
printf("Hello assignment1.\n");
int my_integer;
int* my_integer_pointer;
long my_long;
double *my_double_pointer;
char **my_char_pointer_pointer;
return 0;
}

View File

@ -0,0 +1,8 @@
#include <stdio.h>
#include "linkedList.h"
#include "tests.h"
int main(int arg, char* argc[]){
runTests();
return 0;
}

View File

@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkedList.h"
typedef struct listElementStruct{
char* data;
size_t size;
struct listElementStruct* next;
} listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(char* data, size_t size){
listElement* e = malloc(sizeof(listElement));
if(e == NULL){
//malloc has had an error
return NULL; //return NULL to indicate an error.
}
char* dataPointer = malloc(sizeof(char)*size);
if(dataPointer == NULL){
//malloc has had an error
free(e); //release the previously allocated memory
return NULL; //return NULL to indicate an error.
}
strcpy(dataPointer, data);
e->data = dataPointer;
e->size = size;
e->next = NULL;
return e;
}
//Prints out each element in the list
void traverse(listElement* start){
listElement* current = start;
while(current != NULL){
printf("%s\n", current->data);
current = current->next;
}
}
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* el, char* data, size_t size){
listElement* newEl = createEl(data, size);
listElement* next = el->next;
newEl->next = next;
el->next = newEl;
return newEl;
}
//Delete the element after the given el
void deleteAfter(listElement* after){
listElement* delete = after->next;
listElement* newNext = delete->next;
after->next = newNext;
//need to free the memory because we used malloc
free(delete->data);
free(delete);
}

View File

@ -0,0 +1,21 @@
#ifndef CT331_ASSIGNMENT_LINKED_LIST
#define CT331_ASSIGNMENT_LINKED_LIST
typedef struct listElementStruct listElement;
//Creates a new linked list element with given content of size
//Returns a pointer to the element
listElement* createEl(char* data, size_t size);
//Prints out each element in the list
void traverse(listElement* start);
//Inserts a new element after the given el
//Returns the pointer to the new element
listElement* insertAfter(listElement* after, char* data, size_t size);
//Delete the element after the given el
void deleteAfter(listElement* after);
#endif

View File

@ -0,0 +1,25 @@
#include <stdio.h>
#include "tests.h"
#include "linkedList.h"
void runTests(){
printf("Tests running...\n");
listElement* l = createEl("Test String (1).", 30);
//printf("%s\n%p\n", l->data, l->next);
//Test create and traverse
traverse(l);
printf("\n");
//Test insert after
listElement* l2 = insertAfter(l, "another string (2)", 30);
insertAfter(l2, "a final string (3)", 30);
traverse(l);
printf("\n");
// Test delete after
deleteAfter(l);
traverse(l);
printf("\n");
printf("\nTests complete.\n");
}

View File

@ -0,0 +1,6 @@
#ifndef CT331_ASSIGNMENT_TESTS
#define CT331_ASSIGNMENT_TESTS
void runTests();
#endif

View File

@ -0,0 +1,22 @@
#lang racket
;; a cons pair of two numbers
(cons 1 2)
;; a list of 3 numbers using only the cons function
;; this could be more easily done using the single quote `'` (i.e., `'(1 2 3)`) but i don't use it as it seemed against the spirit of the question
(cons 1 (cons 2 (cons 3 empty)))
;; a list containing a string, a number, and a nested list of three numbers using only the cons function
(cons "a string"
(cons 0
(cons (cons 1 (cons 2 (cons 3 empty))) empty)
)
)
;; a list containing a string, a number, and a nested list of three numbers, using only the list function
(list "a string" 0 (list 1 2 3))
;; a list containing a string, a number, and a nested list of three numbers, using only the append function
;; using `'` as the arguments of the `append` function must be themselves lists
(append '("a string") '(0) '((1 2 3)))

View File

@ -0,0 +1,93 @@
#lang racket
(provide ins_beg)
(provide ins_end)
(provide count_top_level)
(provide count_instances)
(provide count_instances_tr)
(provide count_instances_deep)
;; function to insert an element at the beginning of a list
(define (ins_beg el lst)
;; assuming that the second element is always a list
(cons el lst)
)
;; function to insert an element at the end of a list
(define (ins_end el lst)
;; making el into a list if it isn't already
(append lst (cons el empty))
)
;; function to count the number of top-level items in a list
(define (count_top_level lst)
(if (null? lst)
0 ;; return 0 if we've reached the end of the list
(+ 1 (count_top_level (cdr lst))) ;; return 1 plus the count_top_level of the second element of the cons pair (the rest of the list)
)
)
;; non-tail recursive function to count the number of times a given item occurs in a list (assuming items are atomic)
(define (count_instances item lst)
(if (null? lst)
0 ;; return 0 if at the end of the list
(+
(if (equal? item (car lst))
1 ;; if the item is equal to the first element of the list, add 1
0 ;; if the item is not equal to the first element of the list, add 0
)
(count_instances item (cdr lst)) ;; recurse with the remainder of the list
)
)
)
;; helper function for count_instances_tr
(define (count_instances_tr_helper item lst cnt)
(cond
;; return the count if the end of the list is reached (0 for empty list)
((null? lst)
cnt
)
;; if the first element of the list is equal to the item
((eq? (car lst) item)
;; recurse with the remainder of the list and an incremented count
(count_instances_tr_helper item (cdr lst) (+ cnt 1))
)
;; if the first element of the list is not equal to the item
(else
;; recurse with the remainder of the list and an unchanged count
(count_instances_tr_helper item (cdr lst) cnt)
)
)
)
;; tail recursive function to count the number of times a given item occurs in a list (assuming items are atomic)
(define (count_instances_tr item lst)
;; calling helper function with the list and the count so far (0)
(count_instances_tr_helper item lst 0)
)
;; function to count the number of times an item occurs in a list and its sub-lists
(define (count_instances_deep item lst)
(cond
;; return nothing if we've reached the end of the list
((null? lst)
0
)
;; if the first item is a list, recurse through the first element and then the rest and return the sum of the two results
((pair? (car lst))
(+ (count_instances_deep item (car lst)) (count_instances_deep item (cdr lst)))
)
;; if the first element is equal to the item, add 1 to the count and recurse with the rest of the list
((eq? item (car lst)) ; If the first element is equal to the item, increment count
(+ 1 (count_instances_deep item (cdr lst)))
)
;; else if the first element is not equal to the item, recurse with the rest of the list
(else
(count_instances_deep item (cdr lst))
)
)
)

View File

@ -0,0 +1,145 @@
#lang racket
;; function to display the contents of a binary search tree in sorted order
(define (display_contents bst)
(cond
;; if the binary search tree is null, print an empty string (nothing)
[(null? bst) (display "")]
;; if the binary search tree has nodes
[else
;; display the contents of the left sub-tree of the current node
(display_contents (cadr bst))
;; display the current node
(display (car bst))
(newline)
;; display the contents of the right sub-tree of the current node
(display_contents (caddr bst))
]
)
)
;; function to search a tree and tell whether a given item is presesnt in a given tree
(define (search_tree item bst)
(cond
;; return false if we've reached the end of the tree without finding a match
((null? bst) #f)
;; return true if the current node is equal to the item
((equal? item (car bst)) #t)
;; else return whether the item was found in the left sub-tree or the right sub-tree
(else
(or
(search_tree item (cadr bst)) ;; search left sub-tree
(search_tree item (caddr bst)) ;; search right sub-tree
)
)
)
)
;; function to insert an item into a binary search tree
(define (insert_item item bst)
(cond
;; if there are no nodes in the tree, create a new tree with the item as the root
((null? bst)
(list item '() '())
)
;; if the item is less than the current node, insert it into the left-hand side of the tree
((< item (car bst))
;; create new bst with same root node, same right-hand side, but a left-hand side that has had the item inserted
(list (car bst) (insert_item item (cadr bst)) (caddr bst))
)
;; if the item is greater than the current node, insert it into the right-hand side of the tree
((> item (car bst))
;; create new bst with same root node, same left-hand side, but a right-hand side that has had the item inserted
(list (car bst) (cadr bst) (insert_item item (caddr bst)))
)
;; else the item is equal to the current node, so do nothing
(else bst)
)
)
;; function to insert a list of items into a binary search tree
(define (insert_list lst bst)
(if (null? lst)
;; if the list is null, just return the bst with no changes
bst
;; otherwise, recurse with the remainder of the list and the binary tree produced by inserting the first item of the list into bst
(insert_list (cdr lst) (insert_item (car lst) bst))
)
)
;; tree-sort function
(define (tree_sort lst)
;; inserting the list into a tree structure to sort it and then displaying the contents of that tree
(display_contents (insert_list lst '()))
)
;; function to insert an item into a binary search tree based off a sorting function
;; the sorting function should return accept two items and arguments, and return true if they were passed in order, and false otherwise or if they are equal
(define (insert_item_custom item bst sorter)
(cond
;; if there are no nodes in the tree, create a new tree with the item as the root
((null? bst)
(list item '() '())
)
;; if the item is goes before the current node, insert it into the left-hand side of the tree
((sorter item (car bst))
;; create new bst with same root node, same right-hand side, but a left-hand side that has had the item inserted
(list (car bst) (insert_item_custom item (cadr bst) sorter) (caddr bst))
)
;; if the item goes after the current node, insert it into the right-hand side of the tree
((sorter (car bst) item)
;; create new bst with same root node, same left-hand side, but a right-hand side that has had the item inserted
(list (car bst) (cadr bst) (insert_item_custom item (caddr bst) sorter))
)
;; else the item is equal to the current node, so do nothing
(else bst)
)
)
;; sorter function which states whether the two arguments were supplied in strictly ascending order (i.e., if item == item2, return false)
(define (sort_ascending item1 item2)
(if (< item1 item2)
#t
#f
)
)
;; sorter function which states whether the two arguments were supplied in strictly descending order (i.e., if item == item2, return false)
(define (sort_descending item1 item2)
(if (> item1 item2)
#t
#f
)
)
;; sorter function which states whether the two arguments were supplied in strictly ascending order based on the final digit (i.e., if item == item2, return false)
(define (sort_ascending_last item1 item2)
(if (< (modulo item1 10) (modulo item2 10))
#t
#f
)
)
;; function to insert a list of items into a binary search tree in the order determined by a sorting function
(define (insert_list_custom lst bst sorter)
(if (null? lst)
;; if the list is null, just return the bst with no changes
bst
;; otherwise, recurse with the remainder of the list and the binary tree produced by inserting the first item of the list into bst
(insert_list_custom (cdr lst) (insert_item_custom (car lst) bst sorter) sorter)
)
)

View File

@ -0,0 +1,142 @@
%! TeX program = lualatex
\documentclass[a4paper]{article}
% packages
\usepackage{microtype} % Slightly tweak font spacing for aesthetics
\usepackage[english]{babel} % Language hyphenation and typographical rules
\usepackage[final, colorlinks = false, urlcolor = cyan]{hyperref}
\usepackage{changepage} % adjust margins on the fly
\usepackage{fontspec}
\usepackage{minted}
\usemintedstyle{algol_nu}
\usepackage{xcolor}
\usepackage{pgfplots}
\pgfplotsset{width=\textwidth,compat=1.9}
\usepackage{caption}
\newenvironment{code}{\captionsetup{type=listing}}{}
\captionsetup[listing]{skip=0pt}
\setlength{\abovecaptionskip}{5pt}
\setlength{\belowcaptionskip}{5pt}
\usepackage[yyyymmdd]{datetime}
\renewcommand{\dateseparator}{--}
\setmainfont{EB Garamond}
\setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono}
\usepackage{titlesec}
% \titleformat{\section}{\LARGE\bfseries}{}{}{}[\titlerule]
% \titleformat{\subsection}{\Large\bfseries}{}{0em}{}
% \titlespacing{\subsection}{0em}{-0.7em}{0em}
%
% \titleformat{\subsubsection}{\large\bfseries}{}{0em}{$\bullet$ }
% \titlespacing{\subsubsection}{1em}{-0.7em}{0em}
% margins
\addtolength{\hoffset}{-2.25cm}
\addtolength{\textwidth}{4.5cm}
\addtolength{\voffset}{-3.25cm}
\addtolength{\textheight}{5cm}
\setlength{\parskip}{0pt}
\setlength{\parindent}{0in}
% \setcounter{secnumdepth}{0}
\begin{document}
\hrule \medskip
\begin{minipage}{0.295\textwidth}
\raggedright
\footnotesize
Name: Andrew Hayes \\
E-mail: \href{mailto://a.hayes18@universityofgalway.ie}{\texttt{a.hayes18@universityofgalway.ie}} \hfill\\
ID: 21321503 \hfill
\end{minipage}
\begin{minipage}{0.4\textwidth}
\centering
\vspace{0.4em}
\Large
\textbf{CT331} \\
\end{minipage}
\begin{minipage}{0.295\textwidth}
\raggedleft
\today
\end{minipage}
\medskip\hrule
\begin{center}
\normalsize
Assignment 2: Functional Programming with Scheme
\end{center}
\hrule
\section{Question 1}
\subsection{Part (A): Code}
\begin{code}
\inputminted[texcl, mathescape, breaklines, frame=single]{racket}{../code/assignment_q1.rkt}
\caption{\texttt{assignment\_q1.rkt}}
\end{code}
\subsection{Part (B): Comments}
\begin{figure}[H]
\centering
\includegraphics[width=\textwidth]{./images/question1.png}
\caption{Output of \texttt{assignment\_q1.rkt}}
\end{figure}
Comments on each line of output:
\begin{enumerate}
\item The \mintinline{racket}{cons} function creates a \mintinline{racket}{cons} pair, which is not always a ``list''.
A list is a \mintinline{racket}{cons} pair in which the second element is another itself another list or is \mintinline{racket}{empty}.
When a \mintinline{racket}{cons} pair that is not a list is printed, its elements are delimited by a ``\verb|.|'', as can be seen from the first line of
output.
\item The second section of code produces a list of three numbers using only the \mintinline{racket}{cons} function:
first we create a one-element list with \mintinline{racket}{(cons 3 empty)}, then we create a two-element list by making a \mintinline{racket}{cons} pair
of \mintinline{racket}{2} and the already-created one-element list, and finally we create a three-element list by making a \mintinline{racket}{cons} pair
of \mintinline{racket}{1} and the two-element list.
This could of course be achieved far more simply by just using \mintinline{racket}{(cons 1 '(2 3))} or even justs \mintinline{racket}{'(1 2 3)} but I
felt that this would be against the spirit of the exercise.
\item To create a nested list using only \mintinline{racket}{cons} in the third section of code, we make the \mintinline{racket}{'(1 2 3)} as previously,
\mintinline{racket}{cons} it with \mintinline{racket}{empty} to make a nested list, and then \mintinline{racket}{cons} it with \mintinline{racket}{0}, and
\mintinline{racket}{cons} that with a string literal.
\item Like \mintinline{racket}{cons}, \mintinline{racket}{list} can take either atomics or lists as arguments.
To create the list using only the \mintinline{racket}{list} function, we can simply make a list of \mintinline{racket}{(list 1 2 3)}, and then create a
list consisting of \mintinline{racket}{"a string"}, \mintinline{racket}{0}, \& the aforementioned list.
This is much simpler than using \mintinline{racket}{cons} because \mintinline{racket}{list} can take as many arguments as we want, while
\mintinline{racket}{cons} can only take two arguments.
\item Although I opted not to make use of the ``\mintinline{racket}{'}'' operator to create lists for the previous exercises, I make use of it here as there is
no other way to create a list using only \mintinline{racket}{append} and nothing else, as \mintinline{racket}{append} only accepts lists as arguments.
We make a list consisting of only one element (\mintinline{racket}{"a string"}), another list consisting of only one element (\mintinline{racket}{0}),
and finally a list consisting of three elements \mintinline{racket}{'(1 2 3)} and append them into one to create the desired list.
\end{enumerate}
\section{Question 2}
\begin{code}
\inputminted[breaklines, frame=single]{racket}{../code/assignment_q2.rkt}
\caption{\texttt{assignment\_q2.rkt}}
\end{code}
\section{Question 3}
\begin{code}
\inputminted[breaklines, frame=single]{racket}{../code/assignment_q3.rkt}
\caption{\texttt{assignment\_q3.rkt}}
\end{code}
It is worth noting here that the function \mintinline{racket}{sort_ascending_last} operates in a manner that may be undesirable.
The function determines whether the two numbers passed to it as arguments were passed in strictly ascending order based on the final
digit, i.e. it returns \mintinline{racket}{#t} if the final digit of the first argument is less than the final digit of the second
argument, and \mintinline{racket}{#f} otherwise.
Because this function considers only the final digit of the numbers, it considers two numbers to be equal if they share a final digit,
e.g. it considers the numbers \mintinline{racket}{99} \& \mintinline{racket}{9} to be the same.
Therefore, if one attempts to insert those two values into the binary search tree using this function as the ``sorter'', only the
former value will get inserted, as binary search trees do not allow duplicate values, and the \mintinline{racket}{sort_ascending_last} function
considers those two values to be equal.
However, I thought it would be incorrect for the function to consider the $n-1$\textsuperscript{th} digits in the case of the $n$\textsuperscript{th} digits being identical, as
a) the assignment did not ask for that and b) that would really just be no different to sorting the numbers in ascending order.
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,26 @@
takes(tom, ct331).
takes(mary, ct331).
takes(joe, ct331).
takes(tom, ct345).
takes(mary, ct345).
instructs(bob, ct331).
instructs(ann, ct345).
% 1. rule that returns true if a given instructor teaches a given student
teaches(Instructor, Student) :- instructs(Instructor, Course), takes(Student, Course).
% 2. query that uses the `teaches` rule to show all students instructed by bob
?- teaches(bob, Student).
?- findall(Student, teaches(bob, Student), Students).
% 3. query that uses the `teaches` rule to show all instructors that instruct mary
?- teaches(Instructor, mary).
?- findall(Instructor, teaches(Instructor, mary), Instructors).
% 5. rule that returns true if two students take the same course
takesSameCourse(Student1, Student2) :- takes(Student1, Course), takes(Student2, Course).
contains1(Element, [Element | Tail]).
contains2(Sublist, [Head | Sublist]).

View File

@ -0,0 +1,5 @@
% base case: any element is not in an empty list
isNotElementInList(_, []).
% return true if Element is not the Head of the list and it's not found recursively searching the rest of the list
isNotElementInList(Element, [Head | Tail]) :- Element \= Head, isNotElementInList(Element, Tail).

View File

@ -0,0 +1,16 @@
% predicate to merge two lists
% base case: if the first list is empty, just return the second
mergeTwoLists([], List, List).
% recursive predicate to merge two lists
% split the first list into head and tail, and recurse with its tail and the second list until the first list is empty (base case)
% then merge the original head of the first list with the resulting tail
mergeTwoLists([Head | Tail], List2, [Head | ResultTail]) :- mergeTwoLists(Tail, List2, ResultTail).
% predicate to merge 3 lists
% base case: merging an empty list and two others is the same as merging two lists
mergeLists([], List2, List3, Merged) :- mergeTwoLists(List2, List3, Merged).
% split the first list into head and tail, and recurse with its tail and the other two lists until the first list is empty (base case)
mergeLists([Head1 | Tail1], List2, List3, [Head1 | MergedTail]) :- mergeLists(Tail1, List2, List3, MergedTail).

View File

@ -0,0 +1,8 @@
% call the helper predicate with the list to be reversed and an empty Accumulator to build up
reverseList(List, Reversed) :- reverseListHelper(List, [], Reversed).
% base case fact: when the list to reverse is empty, the accumulator is the reversed list
reverseListHelper([], Accumulator, Accumulator).
% recurse with the tail after prepending the head to the accumulator
reverseListHelper([Head | Tail], Accumulator, Reversed) :- reverseListHelper(Tail, [Head | Accumulator], Reversed).

View File

@ -0,0 +1,8 @@
% base fact: if the list is empty, the list to be returned is just the element
insertInOrder(Element, [], [Element]).
% if the element to be inserted is <= the head of the list, insert it at the head of the list
insertInOrder(Element, [Head | Tail], [Element, Head | Tail]) :- Element =< Head.
% if the element to be inserted is greater than the head of the list, recurse with the tail of the list until
insertInOrder(Element, [Head | Tail], [Head | NewTail]) :- Element > Head, insertInOrder(Element, Tail, NewTail).

View File

@ -0,0 +1,295 @@
%! TeX program = lualatex
\documentclass[a4paper]{article}
% packages
\usepackage{microtype} % Slightly tweak font spacing for aesthetics
\usepackage[english]{babel} % Language hyphenation and typographical rules
\usepackage[final, colorlinks = false, urlcolor = cyan]{hyperref}
\usepackage{changepage} % adjust margins on the fly
\usepackage{fontspec}
\usepackage{minted}
% \usemintedstyle{algol_nu}
\usepackage{xcolor}
\usepackage{pgfplots}
\pgfplotsset{width=\textwidth,compat=1.9}
\usepackage{caption}
\newenvironment{code}{\captionsetup{type=listing}}{}
\captionsetup[listing]{skip=0pt}
\setlength{\abovecaptionskip}{5pt}
\setlength{\belowcaptionskip}{5pt}
\usepackage[yyyymmdd]{datetime}
\renewcommand{\dateseparator}{--}
\setmainfont{EB Garamond}
\setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono}
\usepackage{titlesec}
% \titleformat{\section}{\LARGE\bfseries}{}{}{}[\titlerule]
% \titleformat{\subsection}{\Large\bfseries}{}{0em}{}
% \titlespacing{\subsection}{0em}{-0.7em}{0em}
%
% \titleformat{\subsubsection}{\large\bfseries}{}{0em}{$\bullet$ }
% \titlespacing{\subsubsection}{1em}{-0.7em}{0em}
% margins
\addtolength{\hoffset}{-2.25cm}
\addtolength{\textwidth}{4.5cm}
\addtolength{\voffset}{-3.25cm}
\addtolength{\textheight}{5cm}
\setlength{\parskip}{0pt}
\setlength{\parindent}{0in}
% \setcounter{secnumdepth}{0}
\begin{document}
\hrule \medskip
\begin{minipage}{0.295\textwidth}
\raggedright
\footnotesize
Name: Andrew Hayes \\
E-mail: \href{mailto://a.hayes18@universityofgalway.ie}{\texttt{a.hayes18@universityofgalway.ie}} \hfill\\
ID: 21321503 \hfill
\end{minipage}
\begin{minipage}{0.4\textwidth}
\centering
\vspace{0.4em}
\Large
\textbf{CT331} \\
\end{minipage}
\begin{minipage}{0.295\textwidth}
\raggedleft
\today
\end{minipage}
\medskip\hrule
\begin{center}
\normalsize
Assignment 3: Declarative Programming with Prolog
\end{center}
\hrule
\section{Question 1}
\subsection{Rule that returns true if a given instructor teaches a given student}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
teaches(Instructor, Student) :- instructs(Instructor, Course), takes(Student, Course).
\end{minted}
\subsection{Query that uses the \mintinline{prolog}{teaches} rule to show all students instructed by \mintinline{prolog}{bob}}
For this, I wasn't sure if the desired answer was a query that returned a student instructed by \mintinline{prolog}{bob}, followed by
a couple semi-colons to get every student instructed by \mintinline{prolog}{bob}, or if the desired answer was a single query that
returned a list of students taught by \mintinline{prolog}{bob}, so I did both.
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- teaches(bob, Student).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1.2.png}
\caption{Using the \mintinline{prolog}{teaches} rule to show all students instructed by \mintinline{prolog}{bob}}
\end{figure}
Alternatively, this could be done using the \mintinline{prolog}{findall()} predicate:
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- findall(Student, teaches(bob, Student), Students).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1_2_findall.png}
\caption{Using the \mintinline{prolog}{teaches} rule \& the \mintinline{prolog}{findall} predicate to show all students instructed by \mintinline{prolog}{bob}}
\end{figure}
\subsection{Query that uses the \mintinline{prolog}{teaches} rule to show all instructors that instruct \mintinline{prolog}{mary}}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- teaches(Instructor, mary).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1_3.png}
\caption{Using the \mintinline{prolog}{teaches} rule to show all instructors that instruct \mintinline{prolog}{mary}}
\end{figure}
Alternatively, this could be done using the \mintinline{prolog}{findall()} predicate:
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- findall(Instructor, teaches(Instructor, mary), Instructors).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1_3_findall.png}
\caption{Using the \mintinline{prolog}{teaches()} rule \& the \mintinline{prolog}{findall()} predicate to show all instructors that instruct \mintinline{prolog}{mary}}
\end{figure}
\subsection{Result of query \mintinline{prolog}{teaches(ann,joe).}}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1_4.png}
\caption{Result of query \mintinline{prolog}{teaches(ann,joe).}}
\end{figure}
The result of the query \mintinline{prolog}{teaches(ann,joe).} is \mintinline{prolog}{false.} because \mintinline{prolog}{ann}
only instructs \mintinline{prolog}{ct345} and \mintinline{prolog}{joe} only takes \mintinline{prolog}{ct331}, and therefore
\mintinline{prolog}{ann} does not teach \mintinline{prolog}{joe} because \mintinline{prolog}{ann} does not teach a course
that \mintinline{prolog}{joe} takes.
\subsection{Rule that returns \mintinline{prolog}{true} if two students take the same course}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
takesSameCourse(Student1, Student2) :- takes(Student1, Course), takes(Student2, Course).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q1_5.png}
\caption{Queries to test \mintinline{prolog}{takesSameCourse()}}
\end{figure}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- takesSameCourse(tom,mary).
?- takesSameCourse(joe,mary).
?- takesSameCourse(joe,tom).
?- takesSameCourse(bob, mary).
\end{minted}
\section{Question 2}
\subsection{Query that displays the head \& tail of a list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- [Head | Tail] = [1,2,3].
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q2_1.png}
\caption{Query to display the head \& tail of the list \mintinline{prolog}{[1,2,3]}}
\end{figure}
\subsection{Display the head of a list, the head of the tail of the list, \& the tail of the tail of the list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- [Head | [HeadOfTail | TailOfTail]] = [1,2,3,4,5].
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q2_2.png}
\caption{Query to display the head of the list, the head of the tail of the list, \& the tail of the tail of the list \mintinline{prolog}{[1,2,3,4,5]}}
\end{figure}
\subsection{Rule that returns \mintinline{prolog}{true} if a given element is the first element of a given list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
contains1(Element, [Element | Tail]).
?- contains1(1, [1,2,3,4]).
?- contains1(3, [1,2,3,4]).
?- contains1(1, [2,3,4]).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q2_3.png}
\caption{\mintinline{prolog}{contains1()} testing}
\end{figure}
\subsection{Rule that returns \mintinline{prolog}{true} if a given list is the same as the tail of another given list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
contains2(Sublist, [Head | Sublist]).
?- contains2([2,3,4], [1,2,3,4]).
?- contains2([2,3,4], [1,2,3,4,5]).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q2_4.png}
\caption{\mintinline{prolog}{contains2()} testing}
\end{figure}
\subsection{Query to display the first element of a given list using \mintinline{prolog}{contains1()}}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
?- contains1(FirstElement, [1,2,3,4,5]).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q2_5.png}
\caption{Query to display the first element of a given list using \mintinline{prolog}{contains1()}}
\end{figure}
\section{Determine if a given element is not in a given list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
% base case: any element is not in an empty list
isNotElementInList(_, []).
% return true if Element is not the Head of the list and it's not found recursively searching the rest of the list
isNotElementInList(Element, [Head | Tail]) :- Element \= Head, isNotElementInList(Element, Tail).
% testing
isNotElementInList(1, []).
isNotElementInList(1, [1]).
isNotElementInList(1, [2]).
isNotElementInList(2, [1, 2, 3]).
isNotElementInList(7, [1, 2, 9, 4, 5]).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q3.png}
\caption{Testing \mintinline{prolog}{isNotElementInList()}}
\end{figure}
\section{Facts \& rules to merge three lists}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
% predicate to merge two lists
% base case: if the first list is empty, just return the second
mergeTwoLists([], List, List).
% recursive predicate to merge two lists
% split the first list into head and tail, and recurse with its tail and the second list until the first list is empty (base case)
% then merge the original head of the first list with the resulting tail
mergeTwoLists([Head | Tail], List2, [Head | ResultTail]) :- mergeTwoLists(Tail, List2, ResultTail).
% predicate to merge 3 lists
% base case: merging an empty list and two others is the same as merging two lists
mergeLists([], List2, List3, Merged) :- mergeTwoLists(List2, List3, Merged).
% split the first list into head and tail, and recurse with its tail and the other two lists until the first list is empty (base case)
mergeLists([Head1 | Tail1], List2, List3, [Head1 | MergedTail]) :- mergeLists(Tail1, List2, List3, MergedTail).
?- mergeLists([7],[1,2,3],[6,7,8], X).
?- mergeLists([2], [1], [0], X).
?- mergeLists([1], [], [], X).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q4.png}
\caption{Testing \mintinline{prolog}{mergeLists()}}
\end{figure}
\section{Facts \& rules to reverse a given list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
% call the helper predicate with the list to be reversed and an empty Accumulator to build up
reverseList(List, Reversed) :- reverseListHelper(List, [], Reversed).
% base case fact: when the list to reverse is empty, the accumulator is the reversed list
reverseListHelper([], Accumulator, Accumulator).
% recurse with the tail after prepending the head to the accumulator
reverseListHelper([Head | Tail], Accumulator, Reversed) :- reverseListHelper(Tail, [Head | Accumulator], Reversed).
?- reverseList([1,2,3], X).
?- reverseList([1], X).
?- reverseList([], X).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q5.png}
\caption{Testing \mintinline{prolog}{reverseList()}}
\end{figure}
\section{Facts \& rules to insert an element into its correct position in a given list}
\begin{minted}[linenos, breaklines, frame=single]{prolog}
% base fact: if the list is empty, the list to be returned is just the element
insertInOrder(Element, [], [Element]).
% if the element to be inserted is <= the head of the list, insert it at the head of the list
insertInOrder(Element, [Head | Tail], [Element, Head | Tail]) :- Element =< Head.
% if the element to be inserted is greater than the head of the list, recurse with the tail of the list until
insertInOrder(Element, [Head | Tail], [Head | NewTail]) :- Element > Head, insertInOrder(Element, Tail, NewTail).
\end{minted}
\begin{figure}[H]
\includegraphics[width=\textwidth]{./images/q6.png}
\caption{Testing \mintinline{prolog}{insertInOrder()}}
\end{figure}
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,608 @@
%! TeX program = lualatex
\documentclass[a4paper,11pt]{article}
% packages
\usepackage{fontspec}
\setmainfont{EB Garamond}
% for tironian et fallback
% % \directlua{luaotfload.add_fallback
% % ("emojifallback",
% % {"Noto Serif:mode=harf"}
% % )}
% % \setmainfont{EB Garamond}[RawFeature={fallback=emojifallback}]
\setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono}
\usepackage[a4paper,left=2cm,right=2cm,top=\dimexpr15mm+1.5\baselineskip,bottom=2cm]{geometry}
\setlength{\parindent}{0pt}
\usepackage{fancyhdr} % Headers and footers
\fancyhead[R]{\normalfont \leftmark}
\fancyhead[L]{}
\pagestyle{fancy}
\usepackage{multicol}
\usepackage{microtype} % Slightly tweak font spacing for aesthetics
\usepackage[english]{babel} % Language hyphenation and typographical rules
\usepackage[final, colorlinks = true, urlcolor = blue, linkcolor = black]{hyperref}
\usepackage{changepage} % adjust margins on the fly
\usepackage{minted}
\usemintedstyle{algol_nu}
\usepackage{xcolor}
\usepackage{pgfplots}
\pgfplotsset{width=\textwidth,compat=1.9}
\usepackage{caption}
\newenvironment{code}{\captionsetup{type=listing}}{}
\usepackage[yyyymmdd]{datetime}
\renewcommand{\dateseparator}{-}
\usepackage{titlesec}
\begin{document}
\begin{titlepage}
\begin{center}
\hrule
\vspace*{0.6cm}
\huge \textbf{CT331}
\vspace*{0.6cm}
\hrule
\LARGE
\vspace{0.5cm}
PROGRAMMING PARADIGMS
\vspace{0.5cm}
\hrule
\vfill
\includegraphics[width=0.8\textwidth]{images/lambda.png}
\vfill
\Large
\vspace{0.5cm}
\hrule
\vspace{0.5cm}
\textbf{Andreas Ó hAoḋa}
% \vspace{0.5cm}
% \hrule
% \vspace{0.5cm}
\normalsize
University of Galway
\today
\vspace{0.5cm}
\hrule
\end{center}
\end{titlepage}
\pagenumbering{roman}
\newpage
\tableofcontents
\newpage
\setcounter{page}{1}
\pagenumbering{arabic}
\section{Introduction}
\subsection{Lecturer Contact Information}
\begin{itemize}
\item Finlay Smith, School of Computer Science.
\item \href{mailto://finlay.smith@universityofgalway.ie}{\texttt{finlay.smith@universityofgalway.ie}}
\end{itemize}
\subsection{Syllabus}
This module introduces three different programming paradigms: Procedural, Functional \& Logical.
This will involve 3 programming languages: C (mostly function pointers - knowledge of C is assumed), LISP
(a functional language) and Prolog (a logical language).
Both LISP and Prolog will both be introduced but neither will be fully covered in this module.
There are no books required or recommended for this course.
\subsubsection{Marking}
30\% of the marks for this module will be for the three assignments (one for each paradigm).
The remaining 70\% of the marks will be for the written exam.
\subsection{Programming Paradigms}
A \textbf{paradigm} is a typical example or pattern of something; a pattern or model.
A \textbf{programming paradigm} is a pattern or model of programming.
Various types of programming languages are better suited to solving particular problems.
Programming language implementations differ on semantics \& syntax:
\begin{itemize}
\item \textbf{Syntax} refers to the rules of the language; it allows us to form valid expressions \& statements.
\item \textbf{Semantics} refers to the meaning of those expressions \& statements.
\end{itemize}
Programming languages can be classified according to the features that they have with respect to both the conceptual \& implementation
level.
An alternative definition for a \textbf{programming paradigm} is a collection of abstract features that categorise a group of
languages.
``\textit{The popularity of a paradigm is due to one community deciding which problems are important to solve and then supporting the
most promising paradigm for attacking these problems.}'' -- Thomas Kuhn.
\subsection{Influences on Paradigms}
\begin{itemize}
\item Computer Capabilities.
\item Applications.
\item Programming Methods: Language designs have evolved to reflect changing understanding of good methods for writing
large \& complex programs.
\item Implementation Methods: Early compilers to optimised compilers; structured engineering to software engineering; data
abstraction to OO.
\item Theoretical Studies: Formal maths methods have deepened our understanding of strengths \& weaknesses of language
features and thus influenced the choice \& inclusion of those features.
\item Standardisation (has proved to be a strong conservative influence on the evolution of programming language design).
\end{itemize}
\subsection{Why Learn Different Paradigms?}
\begin{itemize}
\item Different paradigms make different trade-offs; What's tricky in one paradigm is ``baked in'' in another.
\item Changing paradigms forces you to ``change gears''.
\item It will prepare you for learning languages that you've never heard of or that may not exist yet.
\item Helps you to decide what the best tool for the job is.
\item Helps you to understand languages at a deeper level.
\end{itemize}
\subsubsection{Why Learn Functional Programming?}
\begin{itemize}
\item It's one of the oldest paradigm (Lisp: 1958, still widely used today).
\item Heavily based on mathematical concepts (proofs, lambda calculations).
\item Elegant solutions (recursion).
\item Other paradigms can be interpreted in terms of functional programming.
\end{itemize}
\subsubsection{Why Learn Logical Programming?}
\begin{itemize}
\item Long history.
\item ALlows implementation of things that are difficult in other paradigms.
\item \emph{Very} different
\item Helps to conceptualise logical problems.
\end{itemize}
\subsubsection{Why Learn Imperative Programming?}
\begin{itemize}
\item The oldest paradigm -- goes back as far as punch cards \& magnetic loops.
\item Much closer representation of how the machine actually works, i.e. ``closer to the metal''.
\item Can help to recognise optimisation issues / computational bottlenecks.
\item Contextualises many other systems (UNIX, Linux, etc.).
\end{itemize}
\subsubsection{Why Learn Object-Oriented Programming?}
\begin{itemize}
\item Tries to represent the real world.
\item Abstraction \& inheritance.
\item Object-Oriented is everywhere.
\end{itemize}
\section{Overview of Object-Oriented Programming}
Object-Oriented languages include:
\begin{multicols}{2}
\begin{itemize}
\item Java.
\item C\#.
\item VB.NET.
\item Scala.
\item JavaScript.
\item Python.
\item PHP.
\item Smalltalk.
\item Ruby.
\end{itemize}
\end{multicols}
\subsection{Fundamentals of Object-Oriented Programming}
\begin{itemize}
\item Everything is an object.
\item Computation is performed by message-passing.
\item Every \textbf{object} is an \textbf{instance} of a \textbf{class} which is a grouping of similar objects.
\item \textbf{Inheritance} describes the relationships between classes.
\end{itemize}
Object-Oriented Programming focuses on the objects that the program represents and allows them to exhibit ``behaviour''.
\subsection{Four Major Principles of OOP}
\subsubsection{Encapsulation}
Data is hidden as if \textbf{encapsulated} within the object.
Direct access to the data is restricted, instead we use methods to get, set, \& manipulate data.
Manipulation of data is hidden.
The object caller doesn't need to know what's actually going on behind the scenes.
We can be (fairly) sure that nobody else is fiddling with our data.
\subsubsection{Abstraction}
Functionality can be defined without actually being implemented.
High-level interfaces provide method types/names without implementation.
This allows case-specific implementation, allows one person to define the functionality \& another to implement, and
allows the representation to be changed without affecting ``public'' view of the class.
This is helpful when designing large systems.
\subsubsection{Inheritance}
Classes can \textbf{inherit} functionality without re-implementing.
This prevents the duplication of code.
This is also helpful when designing large systems; it encourages a well-structured codebase.
\subsubsection{Polymorphism}
Objects of one class can be treated like objects of other classes.
\section{Imperative \& Procedural Programming}
\subsection{Imperative Programming}
\textbf{Imperative programming} involves telling the computer to perform a set of actions, one after the other.
Most programming languages have imperative aspects.
Imperative programming consists of a list of instructions, \verb|GOTO| statements, and little or no structure.
E.g., Assembly.
\subsection{Procedural Progamming}
\textbf{Procedural progamming} splits actions into \textbf{procedures} or tasks.
Procedures can be made up of other procedures (composition, recursion).
The code is structured, uses ``functions'' or procedures, encourages code re-use, and encourages encapsulation \&
composition.
Note that procedural functions are not to be confused with Functional Programming.
\subsubsection{Structured Programming}
Examples of structured programming languages include basically everything except Assembly.
\begin{itemize}
\item Code is structured.
\item \verb|while|, \verb|for|, \verb|if|, \verb|else,| \verb|switch|, \verb|class|, \verb|function|, etc.
\item Less emphasis on \verb|GOTO| statements.
\item Creating a structure to manage instructions.
\item Allows more complex programs to be built.
\item Easier to understand.
\item Helps to avoid \verb|GOTO| bugs \& spaghetti code.
\end{itemize}
\subsection{The C Programming Language}
\textbf{C} is a procedural, imperative, structured ``systems language''.
It came into being around 1969-1973 in parallel with the development of the UNIX operating system.
Basic Compiled Programming Language (BCPL) \rightarrow B \rightarrow C...
C has had an ANSI standard since the 1980s.
Now one of the most popular \& powerful languages in use today.
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
// header inclusion: functionally defined in stdio.h is added into the program by the compiler, specifically the Linker step of the compiler
// "stdio" is short for "Standard Input / Output"
#include <stdio.h>
// function prototype: tells the compiler that the function exists before it has been implemented
// allows the compiler to handle recursion, or functions calling each other
void sayHello();
// function definition: implements the function
// note: data type, arguments, return
void sayHello() {
// calling a function: printf takes a char* argument
printf("Hello World!\n");
}
// main function: the entry point to the progam
// returns int
// takes two arguments: argc (the number of command-line arguments) & argv (an array of the arguments)
int main(int argc, char* argv[]) {
// calling a function: sayhello takes no argument. nothing is returned
sayHello();
return 0;
}
\end{minted}
\caption{Example C Program: \texttt{helloWorld.c}}
\end{code}
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
#include <stdio.h>
int add(int a, int b);
int add(int a, int b) {
return a+b;
}
int main(int argc, char* argv[]) {
printf("Let's add some numbers...\n");
int first = 8;
int second = 4;
printf("The first number is %d\n", first);
printf("The second number is %d\n", second);
// "add" is a function that returns an int
// the returned int is stored in the "result" variable - they must have the same data type
int result = add(first, second);
// "%d" is for ints - strictly decimal ints
// "%i" is any int including octal and hexadecimal
printf("When we add them together we get: %d\n", result);
return 0;
}
\end{minted}
\caption{Example C Program: \texttt{addNumbers.c}}
\end{code}
\subsubsection{Pointers}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
int* p; // variable p is a pointer to an integer value
int i; // integer value
\end{minted}
You can \textbf{dereference} a pointer into a value with \verb|*|.
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
// ineger i2 is assigned the integer value that the pointer p is pointing to
int i2 = *p;
\end{minted}
You can get a pointer to a value with \verb|&|.
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
// pointer p2 points to the address of integer i
int* p2 = &i;
\end{minted}
A function effectively breaking the convention that arguments are not changed in a function is a \textbf{side effect}.
This is done by passing addresses.
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
#include<stdio.h>
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
int main(int argc, char* arv[]) {
int a = 8;
int b = 4;
swap(&a, &b); // this should make a=4 & b=8
}
\end{minted}
\subsubsection{Arrays \& Pointers}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
int intArr[5]; // an integer array of size 5
// intArr is a pointer to the 0th element of the array - the same as &intArr[0]
intArr[2] = 3; // same as *(intArr+2) = 3;
// (intArr + 2) is of type (int*) while intArr[2] is of type int
// in the latter case, the pointer is dereferenced
// (intArr + 2) is the same as (&(intArr[2]))
// note that the + operator here is not simple addition - it moves the pointer by the size of the type
\end{minted}
\subsubsection{Generic Swap function?}
What about a swap function that works on any data type?
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
void swap(void* x, void* y) {
void temp = *x; // won't work!
// we don't know what size data *x points to, so void temp can't work
// it is impossible to have a variable of type void for this reason
// but we can have a pointer of type void*
*x = *y;
*y = temp;
}
\end{minted}
\caption{(Non-functional) Attempt at a Generic \texttt{swap} Function}
\end{code}
\mintinline{c}{void*} is a specific pointer type which points to some location in memory.
It has no specific type and therefore no specific size.
\\\\
\mintinline{c}{sizeof(<type>)} returns the size in bytes of the object representation of \verb|<type>|.
\verb|sizeof()| is built-in to the C langauge.
\\\\
\mintinline{c}{void* memcpy(void* to, const void* from, size_t size)}.
The \verb|memcpy()| function copies \verb|size| number of bytes from the object beginning at location \verb|from| into
the object beginning at location \verb|to|.
The value returned by \verb|memcpy()| is the value of \verb|to|.
The \verb|memcpy()| function is defined in \verb|string.h|.
\begin{code}
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
#include <string.h>
void generic_swap(void* vp1, void* vp2, int size) {
char temp_buff[size]; // need malloc?
memcpy(temp_buff, vp1, size);
memcpy(vp1, vp2, size);
memcpy(vp2, temp_buff, size);
}
\end{minted}
\caption{Generic Swap Function}
\end{code}
\subsection{Stacks vs Heaps}
A \textbf{stack} is a LIFO data structure of limited size \& limited access.
It supports only two operations: PUSH \& POP.
Stacks are very fast.
The limited size of stacks can result in stack overflow, and you cannot free memory in a stack except by POPping.
To continue the \verb|swap()| function from above:
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
// first, a, b, & c are pushed onto the stack
char a = 'a';
int b = 100;
int c = 50;
// when swap() is called, x, y, & temp are pushed onto the stack
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
// when swap returns, x, y, & temp are popped from the stack and \textbf{their memory is no longer in use}
}
swap(b, c);
\end{minted}
But what if we want to keep track of \verb|temp| and use it later?
\\\\
A \textbf{heap} is an unordered data structure of (theoretically) unlimited size and global access.
The heap operations are allocate \& free.
Heaps are slower than stacks.
Heaps are also harder to manage than stacks as they can get memory leaks.
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{c}
// first, b & c are pushed onto the stack
int b = 100;
int c = 50;
// when swap() is called, x, y, & temp are pushed onto the stack
void* swap(int* x, int* y) {
int temp = *x;
// we allocate space in memory to perm using malloc
int* perm = malloc(int);
perm = &temp;
x = y;
y = *perm;
// when swap returns, x, y, & temp are popped from the stack
// the memory allocated to perm is still in use
return perm;
}
void* p = swap(b, c);
free(p);
\end{minted}
Why not just return \verb|temp| in the same way?
\begin{itemize}
\item Even when this function terminates, another function can access perm using that pointer.
\item If we need to store a large or undeterminable amount of data, we can safely use the heap as there is no risk
of stack overflow and no risk of losing reference or accidental de-allocation of memory.
\end{itemize}
\section{Dynamic Memory}
FINISH OFF
\section{Functional Programming}
Given the same problem to solve, a program for said problem in any programming language can be considered
equivalent to any other at the machine level in that the programs will result in changes to values contained in
memory cells.
However, there can be quite significant differences at both the conceptual \& implementation level.
\subsection{Lisp, Racket, \& Scheme}
\textbf{LISP} (more commonly referred to as \textbf{Lisp}) is a contraction of \textbf{List Processing}.
\textbf{Scheme} is a dialect of Lisp, and \textbf{Racket} is an implementation of Scheme.
Lisp uses prefix (Polish) notation, e.g.: \verb|(+ 3 4)|, \verb|(* 5 6)|, \verb|(- 4 (* 5 6))|, etc.
\subsubsection{Function vs Literal}
Parentheses are used to represent a \textbf{function}:
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{lisp}
(+ 3 4) ; = 7
(* 5 6) ; = 30
(- 4 (* 5 6)) ; = -26
\end{minted}
A single quote is used to represent a \textbf{literal}:
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{lisp}
(+ 3 4) ; = 7
'(+ 3 4) ; = '(+ 3 4)
\end{minted}
Rather than considering \verb|+| as the name of a function, the quote means to take everything literally, i.e.
``\verb|+|'' is just a word.
Nothing is evaluated.
\subsubsection{S-Expressions}
Both code \& data are structured as nested lists in Lisp.
\textbf{Symbolic Expressions} or s-expressions, sexprs, or sexps are a notation for nested list structures.
They are defined with a very simple recursive grammar, but produce a very flexible framework for computing.
An s-expression is defined as:
\begin{enumerate}
\item An \textbf{atom}.
Atoms are considered to be ``indivisible''.
Primitive data types like numbers, strings, booleans, etc. are atoms.
Lists \& pairs (s-expressions) are not.
\item An expression in the form \verb|(X . Y)|, where \verb|X| \& \verb|Y| are s-expressions.
\end{enumerate}
A \textbf{pair} is two pieces of data together.
They are created by the \verb|cons| function, which is short for ``construct'', e.g. \verb|(cons 1 2)|.
The two values joined with \verb|cons| are printed between parentheses interspaced by a \verb|.| (a period):
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (cons "banana" "split")
'("banana" . "split")'
\end{minted}
\subsection{Lists}
A \textbf{list} is an ordered group of data.
List elements are separated by a space.
The list syntax is a shorthand for an s-expression.
Lists are displayed between parentheses using the \verb|'| (single quote character).
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
'(1 2 3) ; list of numbers
'("this" "that" "the other") ; list of strings
'(1 2 "three" 4) ; list of mixed data types
\end{minted}
Lisp uses nested lists (which are essentially linked lists).
We can access the first element of a list using the \verb|car| function:
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (car '(1 2 3))
1
\end{minted}
We can access the rest of the list using the \verb|cdr| function:
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (cdr '(1 2 3))
'(2 3)
\end{minted}
\verb|cdr| is analogous to \verb|element->rest| in our C linked list.
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (car (cdr '(1 2 3)))
2
\end{minted}
There is a shorthand for a combination of \verb|car|s \& \verb|cdr|s (up to 4 operations usually but it depends
on the Scheme environment), where \verb|*| is \verb|a| or \verb|d| or a combination (if supported).
For example, write a sequence of \verb|car|s \& \verb|cdr|s to extract: ``\verb|d|'' from list
\verb|(a b c d e f)| named \verb|lis|:
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{lisp}
;;;; these two are equivalent
(car (cdr (cdr (cdr lis))))
cadddr(lis)
\end{minted}
Lists are really just \verb|cons| pairs where these second element is another list or \verb|empty|;
\verb|empty| is a special word, similar to \verb|NULL| in other languages.
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (cons 2 empty)
'(2)
> (cons 1 (cons 2 empty))
'(1 2)
\end{minted}
The built-in functions \verb|list| \& \verb|append| provide a more convenient way to create lists.
\subsubsection{\texttt{define}}
\textbf{\texttt{define}} binds a variable to some data.
Its format is \mintinline{lisp}{(define variable value)}.
\verb|define| is used for user-defined functions.
Note that user-defined functions can be used within other use defined functions as long as the functions are
defined before they are invoked.
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{lisp}
(define (function_name parameter-list)
Function-body
)
;;; calculates the absolute addition of two numbers where the function abs returns the absolute value of a number
(define (sumabs num1 num2)
(+ (abs num1) (abs num2))
)
\end{minted}
\begin{minted}[texcl, mathescape, breaklines, frame=single]{lisp}
> (sumabs 2 -3)
5
\end{minted}
\subsubsection{\texttt{list} \& \texttt{append}}
The \verb|list| function constructs a list from components.
It takes the form \mintinline{lisp}{(list el-1 el-2 el-n)}.
These components can be symbols, numbers, or lists.
\\\\
\verb|append| collects components from several lists into one list.
Its arguments must be lists.
\verb|append| takes the form \mintinline{lisp}{(append list1 list2 listn)}.
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB