Initial Commit

This commit is contained in:
Marc
2025-09-13 14:40:16 +02:00
commit ded01301c2
383 changed files with 71046 additions and 0 deletions

14
OU4/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"files.associations": {
"array": "c",
"chrono": "c",
"deque": "c",
"string": "c",
"unordered_map": "c",
"vector": "c",
"iterator": "c",
"string_view": "c",
"format": "c",
"span": "c"
}
}

10
OU4/airmap1.map Normal file
View File

@@ -0,0 +1,10 @@
# Some airline network
896.7
BMA MMX #hrjraiwefguil
#BMA UME # Bromma-Umea
1BMA MMX # Bromma-Malmo
1MMX BMA # Malmo-Bromma
1BMA GOT # Bromma-Goteborg
1GOT BMA # Goteborg-Bromma
1LLA PJA # Lulea-Pajala
1PJA LLA # Pajala-Lulea

3
OU4/changes.txt Normal file
View File

@@ -0,0 +1,3 @@
Inlämning 2: Saknades en reset av seen status efter att "no path found" printades, vilket orsakade att nästa testade nodpar där path finns kunde returnera "no path" ifall pathen gick igenom redan sedda noder.
Inlämning 3: Vi fixade så att den ger felmedelanden vid felaktig kartfil.

7
OU4/compile.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
#gcc -Wall -I include/ -g -o graph2-marctest marctest.c graph2.c src/dlist/dlist.c
gcc -Wall -std=c99 -I include/ -g -o graph2 is_connected.c graph2.c src/dlist/dlist.c src/queue/queue.c src/list/list.c
#table/table2.c
gcc -Wall -I include/ -g -o graph is_connected.c graph.c src/dlist/dlist.c src/queue/queue.c src/list/list.c src/array_2d/array_2d.c
#gcc -Wall -I include/ -g -o arraytabletest tabletest.c arraytable.c src/array_1d/array_1d.c

BIN
OU4/graph Executable file

Binary file not shown.

484
OU4/graph.c Normal file
View File

@@ -0,0 +1,484 @@
#include <stdio.h>
#include <array_2d.h> // ska innehålla array_2d implementation
#include <graph.h>
#include <dlist.h>
#include <stdlib.h>
#include <string.h>
/*
* graph.c: Implementation of a 2-dimensional array based graph for "Obligatorisk uppgift 4" in the "Datastructures and
* algorithms" course at the Department of Computing Science, Umea University.
*
* Authors: Jakob Nyström tfy22jnm
* Ellen Horneij tfy22ehj
* Marc Meunier tfy22mmr
*
* Version information:
* v1.0 2025-05-25: First public version.
*
*/
// ===========INTERNAL DATA TYPES ============
// Graph contains the matrix with nodes and edges, total number of nodes ans edges and
struct graph
{
array_2d *entries;
int nr_of_nodes;
int nr_of_edges;
int max_nodes;
};
/**
* Node entry contains the value of the node, it's position and it's seen status
*/
struct node
{
const char *value;
int position;
bool seen;
};
// =================== NODE COMPARISON FUNCTION ======================
/**
* nodes_are_equal() - Check whether two nodes are equal.
* @n1: Pointer to node 1.
* @n2: Pointer to node 2.
*
* Returns: true if the nodes are considered equal, otherwise false.
*
*/
bool nodes_are_equal(const node *n1, const node *n2)
{
// Uses strcomp to compare the nodes
int cmp = strcmp(n1->value, n2->value);
// Returns true if strcomp returns 0 meaning that the nodes are equal, if else false
if (cmp == 0)
{
return true;
}
else
{
return false;
}
}
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* node_create() - Allocates the memory and creates a node entry
* @s: the value of the node
*
* Returns: The pointer to node entry with value s
*/
node *node_create(const char *s)
{
// Allocate the memory for the node entry
node *n = calloc(1, sizeof(*n));
// Populate the entry.
n->seen = false;
char *tmp = malloc(strlen(s) + 1);
if (tmp != NULL)
{
strcpy(tmp, s);
n->value = tmp;
}
else
{
// Handle memory allocation failure
free(n);
return NULL;
}
return n;
}
/**
* table_entry_kill() - Return the memory allocated to a table entry.
* @e: The table entry to deallocate.
*
* Returns: Nothing.
*/
void node_kill(node *v)
{
//node *n = v; // Convert the pointer (useful if debugging the code)
if (v == NULL) {
return; // Nothing to free if v is NULL
}
// free strings
free((void*)v->value);
// All we need to do is to deallocate the struct.
free(v);
}
// =================== GRAPH STRUCTURE INTERFACE ======================
/**
* graph_empty() - Create an empty graph.
* @max_nodes: The maximum number of nodes the graph can hold.
*
* Returns: A pointer to the new graph
*/
graph *graph_empty(int max_nodes)
{
// Allocate the graph memory
graph *g = calloc(1, sizeof(graph));
// Create the array for the entries
g->entries = array_2d_create(0, max_nodes, 0, max_nodes + 1, NULL);
g->nr_of_nodes = 0;
g->nr_of_edges = 0;
g->max_nodes = max_nodes;
return g;
}
/**
* graph_is_empty() - Check if a graph is empty, i.e. has no nodes.
* @g: Graph to check.
*
* Returns: True if graph is empty, otherwise false.
*/
bool graph_is_empty(const graph *g)
{
// Returns true if nr_of_nodes is empty
return g->nr_of_nodes == 0;
}
/**
* graph_has_edges() - Check if a graph has any edges.
* @g: Graph to check.
*
* Returns: True if graph has any edges, otherwise false.
*/
bool graph_has_edges(const graph *g)
{
// Returns true if nr_of_edges is not empty
return g->nr_of_edges != 0;
}
/**
* graph_insert_node() - Inserts a node with the given name into the graph.
* @g: Graph to manipulate.
* @s: Node name.
*
* Creates a new node with a copy of the given name and puts it into
* the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_node(graph *g, const char *s)
{
// Define variables and create a node entry with s for comparisons
int index = 0;
int count = 0;
node *m = node_create(s);
// Check for duplicates among the already taken slots
while (index < g->max_nodes && count < g->nr_of_nodes)
{
// Inspect the table entry
node *n = array_2d_inspect_value(g->entries, index, 0);
// Check if the node already exists
if (n != NULL && nodes_are_equal(n, m))
{
// If the node is a duplicate, exit the loop and skips the insertion loop
node_kill(m);
return g;
}
if (n != NULL)
{
// Update how many taken slots that have been checked
count++;
}
// Continue with the next position.
index++;
}
// If no duplicate is found, insert the node in the first available slot
while (index < g->max_nodes)
{
// Check for empty slot
node *n = array_2d_inspect_value(g->entries, index, 0);
if (n == NULL)
{
// Input node in the empty slot and update variables before exiting the loop
m->position = index;
m->seen = false;
array_2d_set_value(g->entries, m, index, 0);
g->nr_of_nodes++;
break;
}
index++;
}
// Return the modified graph
return g;
}
/**
* graph_find_node() - Find a node stored in the graph.
* @g: Graph to manipulate.
* @s: Node identifier, e.g. a char *.
*
* Returns: A pointer to the found node, or NULL.
*/
node *graph_find_node(const graph *g, const char *s)
{
int index = 0;
int count = 0;
node *m = node_create(s);
// Loop over the node list
while (index < g->max_nodes && count < g->nr_of_nodes)
{
// Check if a node with value s exists and return it, if not continue to next node
node *n = array_2d_inspect_value(g->entries, index, 0);
if (n != NULL && nodes_are_equal(n, m))
{
// Deallocate comparison node
node_kill(m);
return n;
}
if (n != NULL)
{
count++;
}
index++;
}
// If no match is found, deallocate comparison node and return NULL
node_kill(m);
return NULL;
}
/**
* graph_node_is_seen() - Return the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to return seen status for.
*
* Returns: The seen status for the node.
*/
bool graph_node_is_seen(const graph *g, const node *n)
{
// Check if node exists and return its seen-status
node *m = graph_find_node(g, n->value);
if (m != NULL)
{
return m->seen;
}
// Return NULL if the node is not found
return false;
}
/**
* graph_node_set_seen() - Set the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to set seen status for.
* @s: Status to set.
*
* Returns: The modified graph.
*/
graph *graph_node_set_seen(graph *g, node *n, bool seen)
{
// Check if node exists and update its seen-status
node *m = graph_find_node(g, n->value);
if (m != NULL)
{
m->seen = seen;
}
// Return the modified graph
return g;
}
/**
* graph_reset_seen() - Reset the seen status on all nodes in the graph.
* @g: Graph to modify.
*
* Returns: The modified graph.
*/
graph *graph_reset_seen(graph *g)
{
int index = 0;
int count = 0;
// Iterates over all nodes and sets the seen-status to FALSE
while (index < g->max_nodes && count < g->nr_of_nodes)
{
node *n = array_2d_inspect_value(g->entries, index, 0);
if (n != NULL)
{
n->seen = false;
count++;
}
index++;
}
return g;
}
/**
* graph_insert_edge() - Insert an edge into the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* NOTE: Undefined unless both nodes are already in the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_edge(graph *g, node *n1, node *n2)
{
// Checks if both source and destination exists
if (graph_find_node(g, n1->value) != NULL && graph_find_node(g, n2->value) != NULL)
{
// Inserts n2 into the edge list of n1 and updates the nr_of_edges
array_2d_set_value(g->entries, n2, n1->position, n2->position + 1);
g->nr_of_edges++;
}
return g;
}
/**
* graph_delete_node() - Remove a node from the graph.
* @g: Graph to manipulate.
* @n: Node to remove from the graph.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the node is not in the graph.
*/
graph *graph_delete_node(graph *g, node *n)
{
// Removes the node and all of its destinations
for (int i = 0; i < g->max_nodes; i++)
{
array_2d_set_value(g->entries, NULL, n->position, 1);
}
// Updatess the nr_of_nodes and returns the modified graph
g->nr_of_nodes--;
return g;
}
/**
* graph_delete_edge() - Remove an edge from the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the edge is not in the graph.
*/
graph *graph_delete_edge(graph *g, node *n1, node *n2)
{
// Removes n2 from n1's destination list
array_2d_set_value(g->entries, NULL, n1->position, n2->position + 1);
g->nr_of_edges--;
return g;
}
/**
* graph_neighbours() - Return a list of neighbour nodes.
* @g: Graph to inspect.
* @n: Node to get neighbours for.
*
* Returns: A pointer to a list of nodes. Note: The list must be
* dlist_kill()-ed after use.
*/
dlist *graph_neighbours(const graph *g, const node *n)
{
// Creates the return list and gets its first position
dlist *l = dlist_empty(NULL);
dlist_pos pos = dlist_first(l);
if (n != NULL)
{
for (int i = 1; i <= g->max_nodes + 1; i++)
{
// If a destination exists add it to the list of neigbours and update the list position
node *m = array_2d_inspect_value(g->entries, n->position, i);
if (m != NULL)
{
dlist_insert(l, m, pos);
pos = dlist_next(l, pos);
}
}
}
// Return the list of neigbours
return l;
}
/**
* graph_kill() - Destroy a given graph.
* @g: Graph to destroy.
*
* Return all dynamic memory used by the graph.
*
* Returns: Nothing.
*/
void graph_kill(graph *g)
{
// Iterate over the list of nodes and deallocate them
for (int i = 0; i < g->max_nodes; i++)
{
node *n = array_2d_inspect_value(g->entries, i, 0);
node_kill(n);
}
// free the array and the graph
array_2d_kill(g->entries);
free(g);
}
/**
* graph_print() - Iterate over the graph elements and print their values.
* @g: Graph to inspect.
*
* Iterates over the graph and prints its contents.
*
* Returns: Nothing.
*/
void graph_print(const graph *g)
{
// Itirate over the list and print the value
for (int i = 0; i < g->max_nodes; i++)
{
for (int j = 0; j < g->max_nodes + 1; j++)
{
node *n = array_2d_inspect_value(g->entries, i, j);
// Check if there is a value to print
if (n != NULL && j == 0)
{
// Print the value
printf("[%s] -> ", n->value);
}
else if (j == 0)
{
// Print no value
printf("[###] -> ");
}
else if (n != NULL)
{
// Print the value
printf("[%s] ", n->value);
}
else
{
// Print no value
printf("[###] ");
}
}
printf("\n");
}
}

200
OU4/graph.h Normal file
View File

@@ -0,0 +1,200 @@
#ifndef __GRAPH_H
#define __GRAPH_H
#include <stdbool.h>
#include "util.h"
#include "dlist.h"
/*
* Declaration of a generic graph for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The graph stores nodes and edges of a directed or
* undirected graph. After use, the function graph_kill() must
* be called to de-allocate the dynamic memory used by the graph
* itself. The de-allocation of any dynamic memory allocated for the
* node names is the responsibility of the user of the graph.
*
* Author: Niclas Borlin (niclas.borlin@cs.umu.se)
*
* Version information:
* v1.0 2019-02-21: First public version.
* v1.01 2019-02-26: Modified include directives for header files
* from the codebase to use "" to handle case when
* student stores all header files in the current
* directory. See
* https://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename.
* v1.02 2019-03-01: Doc update in graph_node_is_seen().
* v1.1 2019-03-06: Changed several const node * to node *.
* Fixed doc bug to state that any dynamic memory allocated
* to the node NAMES is the resposibility of the user.
*/
// ====================== PUBLIC DATA TYPES ==========================
// Anonymous declarations of node and graph.
typedef struct node node;
typedef struct graph graph;
// =================== NODE COMPARISON FUNCTION ======================
/**
* nodes_are_equal() - Check whether two nodes are equal.
* @n1: Pointer to node 1.
* @n2: Pointer to node 2.
*
* Returns: true if the nodes are considered equal, otherwise false.
*
*/
bool nodes_are_equal(const node *n1,const node *n2);
// =================== GRAPH STRUCTURE INTERFACE ======================
/**
* graph_empty() - Create an empty graph.
* @max_nodes: The maximum number of nodes the graph can hold.
*
* Returns: A pointer to the new graph.
*/
graph *graph_empty(int max_nodes);
/**
* graph_is_empty() - Check if a graph is empty, i.e. has no nodes.
* @g: Graph to check.
*
* Returns: True if graph is empty, otherwise false.
*/
bool graph_is_empty(const graph *g);
/**
* graph_has_edges() - Check if a graph has any edges.
* @g: Graph to check.
*
* Returns: True if graph has any edges, otherwise false.
*/
bool graph_has_edges(const graph *g);
/**
* graph_insert_node() - Inserts a node with the given name into the graph.
* @g: Graph to manipulate.
* @s: Node name.
*
* Creates a new node with a copy of the given name and puts it into
* the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_node(graph *g, const char *s);
/**
* graph_find_node() - Find a node stored in the graph.
* @g: Graph to manipulate.
* @s: Node identifier, e.g. a char *.
*
* Returns: A pointer to the found node, or NULL.
*/
node *graph_find_node(const graph *g, const char *s);
/**
* graph_node_is_seen() - Return the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to return seen status for.
*
* Returns: The seen status for the node.
*/
bool graph_node_is_seen(const graph *g, const node *n);
/**
* graph_node_set_seen() - Set the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to set seen status for.
* @s: Status to set.
*
* Returns: The modified graph.
*/
graph *graph_node_set_seen(graph *g, node *n, bool seen);
/**
* graph_reset_seen() - Reset the seen status on all nodes in the graph.
* @g: Graph to modify.
*
* Returns: The modified graph.
*/
graph *graph_reset_seen(graph *g);
/**
* graph_insert_edge() - Insert an edge into the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* NOTE: Undefined unless both nodes are already in the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_edge(graph *g, node *n1, node *n2);
/**
* graph_delete_node() - Remove a node from the graph.
* @g: Graph to manipulate.
* @n: Node to remove from the graph.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the node is not in the graph.
*/
graph *graph_delete_node(graph *g, node *n);
/**
* graph_delete_edge() - Remove an edge from the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the edge is not in the graph.
*/
graph *graph_delete_edge(graph *g, node *n1, node *n2);
/**
* graph_choose_node() - Return an arbitrary node from the graph.
* @g: Graph to inspect.
*
* Returns: A pointer to an arbitrayry node.
*
* NOTE: The return value is undefined for an empty graph.
*/
node *graph_choose_node(const graph *g);
/**
* graph_neighbours() - Return a list of neighbour nodes.
* @g: Graph to inspect.
* @n: Node to get neighbours for.
*
* Returns: A pointer to a list of nodes. Note: The list must be
* dlist_kill()-ed after use.
*/
dlist *graph_neighbours(const graph *g,const node *n);
/**
* graph_kill() - Destroy a given graph.
* @g: Graph to destroy.
*
* Return all dynamic memory used by the graph.
*
* Returns: Nothing.
*/
void graph_kill(graph *g);
/**
* graph_print() - Iterate over the graph elements and print their values.
* @g: Graph to inspect.
*
* Iterates over the graph and prints its contents.
*
* Returns: Nothing.
*/
void graph_print(const graph *g);
#endif

BIN
OU4/graph2 Executable file

Binary file not shown.

View File

@@ -0,0 +1,228 @@
#include <stdio.h>
#include <dlist.h>
#include <graph.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
struct graph
{
dlist *nodes; // The graph nodes are stored in a directed list
int max_nodes;
// int connected;
};
struct node
{
void *value;
bool seen;
dlist *edge;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* node_create() - Allocate and populate a graph entry.
* @key: A pointer to a function to be used to compare keys.
* @value: A pointer to a function (or NULL) to be called to
* de-allocate memory for keys on remove/kill.
*
* Returns: A pointer to the newly created graph entry.
*/
node *node_create(const void *value, int max_node)
{
// Allocate space for a graph entry. Use calloc as a defensive
// measure to ensure that all pointers are initialized to NULL.
node *e = calloc(1, sizeof(*e));
// Populate the entry.
e->value = value;
e->seen = false;
e->edge = dlist_empty(NULL); // lista med tillhörande edges
return e;
}
/**
* node_kill() - Return the memory allocated to a graph entry.
* @e: The graph entry to deallocate.
*
* Returns: Nothing.
*/
void node_kill(void *v)
{
node *e = v; // Convert the pointer (useful if debugging the code)
// All we need to do is to deallocate the struct.
free(e);
}
/**
* graph_empty() - Create an empty graph.
* @key_cmp_func: A pointer to a function to be used to compare keys.
* @key_kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory for keys on remove/kill.
* @value_kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory for values on remove/kill.
*
* Returns: Pointer to a new graph.
*/
graph *graph_empty(int max_nodes)
{
// Allocate the graph header.
graph *g = calloc(1, sizeof(graph));
// Create the list to hold the node-ies.
g->nodes = dlist_empty(NULL);
g->max_nodes = max_nodes;
// Store the key compare function and key/value kill functions.
return g;
}
/**
* graph_is_empty() - Check if a graph is empty.
* @graph: graph to check.
*
* Returns: True if graph contains no entries, false otherwise.
*/
bool graph_is_empty(const graph *g)
{
return dlist_is_empty(g->nodes);
}
graph *graph_insert_node(graph *g, const char *s)
{
node *e = node_create(s, g->max_nodes);
//e->seen = false;
dlist_insert(g->nodes, e, dlist_first(g->nodes));
return g;
}
bool nodes_are_equal(const node *n1, const node *n2)
{
if (n1 == NULL || n2 == NULL)
{
return n1 == n2;
}
return strcmp(n1->value, n2->value) == 0;
}
bool graph_has_edges(const graph *g)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
if (!dlist_is_empty(e->edge))
{
return true;
}
pos = dlist_next(g->nodes, pos);
}
return false;
}
node *graph_find_node(const graph *g, const char *s)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
if (strcmp(e->value, s) == 0 && !e->edge)
{
return e;
}
pos = dlist_next(g->nodes, pos);
}
return NULL;
}
bool graph_node_is_seen(const graph *g, const node *n)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
if (nodes_are_equal(e, n) && e->edge == false)
{
return e->seen;
}
pos = dlist_next(g->nodes, pos);
}
return false;
}
graph *graph_node_set_seen(graph *g, node *n, bool seen)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
if (nodes_are_equal(e, n) && e->edge == false)
{
e->seen = seen;
break;
}
pos = dlist_next(g->nodes, pos);
}
return g;
}
graph *graph_reset_seen(graph *g)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
if (e->seen == true)
{
e->seen = false;
}
pos = dlist_next(g->nodes, pos);
}
return g;
}
graph *graph_insert_edge(graph *g, node *n1, node *n2)
{
dlist_insert(n1->edge, n2, dlist_first(n1->edge));
return g;
}
dlist *graph_neighbours(const graph *g,const node *n)
{
return n->edge;
}
void graph_print(const graph *g)
{
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
printf("%s to nodes: ", (char *)e->value);
dlist_pos pos_edge = dlist_first(e->edge);
while (!dlist_is_end(e->edge, pos_edge))
{
node *edges = dlist_inspect(e->edge,pos_edge);
printf("%s,", (char *)edges->value);
pos_edge = dlist_next(e->edge, pos_edge);
}
printf("\n");
pos = dlist_next(g->nodes, pos);
}
}

BIN
OU4/graph2-marctest Normal file

Binary file not shown.

407
OU4/graph2.c Normal file
View File

@@ -0,0 +1,407 @@
#include <stdio.h>
#include <dlist.h>
#include <graph.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/*
* graph2.c: Implementation of a dlist based graph for "Obligatorisk uppgift 4" in the "Datastructures and
* algorithms" course at the Department of Computing Science, Umea University.
*
* Authors: Marc Meunier tfy22mmr
* Ellen Horneij tfy22ehj
* Jakob Nyström tfy22jnm
*
* Version information:
* v1.0 2025-05-25: First public version.
*
*/
// ===========INTERNAL DATA TYPES ============
struct graph
{
dlist *nodes; // The graph nodes are stored in a directed list
int max_nodes;
// int connected;
};
struct node
{
const char *value;
bool seen;
dlist *edge;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* node_entry_kill() - Return the memory allocated to a node entry.
* @e: The entry to deallocate.
*
* Returns: Nothing.
*/
void node_entry_kill(void *v)
{
node *n = v;
free((void*)n->value); // Cast away const and free the string
dlist_kill(n->edge); // kills list
free(n); // frees memory
}
/**
* graph_entry_create() - Allocate and populate a graph entry.
* @key: A pointer to a function to be used to compare keys.
* @value: A pointer to a function (or NULL) to be called to
* de-allocate memory for keys on remove/kill.
*
* Returns: A pointer to the newly created graph entry.
*/
node *node_entry_create(const char *value, int max_node)
{
// Allocate space for a graph entry. Use calloc as a defensive
node *n = calloc(1, sizeof(*n));
// Populate the entry.
char *tmp = malloc(strlen(value) + 1);
if (tmp != NULL)
{
strcpy(tmp, value);
n->value = tmp;
}
else
{
// Handle memory allocation failure
free(n);
return NULL;
}
// Set status to false, and create the list of edges
n->seen = false;
n->edge = dlist_empty(NULL);
return n;
}
// =================== GRAPH STRUCTURE INTERFACE ======================
/**
* nodes_are_equal() - Check whether two nodes are equal.
* @n1: Pointer to node 1.
* @n2: Pointer to node 2.
*
* Returns: true if the nodes are considered equal, otherwise false.
*
*/
bool nodes_are_equal(const node *n1, const node *n2)
{
if (n1 == NULL || n2 == NULL)
{
return n1 == n2;
}
// compares string values of nodes
return strcmp(n1->value, n2->value) == 0;
}
/**
* graph_empty() - Create an empty graph.
* @max_nodes: The maximum number of nodes the graph can hold.
*
* Returns: A pointer to the new graph.
*/
graph *graph_empty(int max_nodes)
{
// Allocate the graph
graph *g = calloc(1, sizeof(graph));
// Create the list to hold the graph_entry-ies.
g->nodes = dlist_empty(node_entry_kill);
g->max_nodes = max_nodes;
return g;
}
/*
* graph_is_empty() - Check if a graph is empty, i.e. has no nodes.
* @g: Graph to check.
*
* Returns: True if graph is empty, otherwise false.
*/
bool graph_is_empty(const graph *g)
{
return dlist_is_empty(g->nodes);
}
/**
* graph_insert_node() - Inserts a node with the given name into the graph.
* @g: Graph to manipulate.
* @s: Node name.
*
* Creates a new node with a copy of the given name and puts it into
* the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_node(graph *g, const char *s)
{
// create node
node *n = node_entry_create(s, g->max_nodes);
n->seen = false;
// get start position of list
dlist_pos pos = dlist_first(g->nodes);
// iterate over list
while (!dlist_is_end(g->nodes, pos))
{
// check node already exists
node *m = dlist_inspect(g->nodes, pos);
if (nodes_are_equal(n, m))
{
node_entry_kill(n);
return g;
}
// go to next position
pos = dlist_next(g->nodes, pos);
}
// inserts node into list
dlist_insert(g->nodes, n, dlist_first(g->nodes));
return g;
}
/**
* graph_has_edges() - Check if a graph has any edges.
* @g: Graph to check.
*
* Returns: True if graph has any edges, otherwise false.
*/
bool graph_has_edges(const graph *g)
{
// get start position
dlist_pos pos = dlist_first(g->nodes);
// check for edges for every node
while (!dlist_is_end(g->nodes, pos))
{
node *n = dlist_inspect(g->nodes, pos);
if (!dlist_is_empty(n->edge))
{
return true;
}
// go to next position
pos = dlist_next(g->nodes, pos);
}
return false;
}
/**
* graph_find_node() - Find a node stored in the graph.
* @g: Graph to manipulate.
* @s: Node identifier, e.g. a char *.
*
* Returns: A pointer to the found node, or NULL.
*/
node *graph_find_node(const graph *g, const char *s)
{
// get start position
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *n = dlist_inspect(g->nodes, pos);
// compare value with the one we are looking for
if (strcmp(n->value, s) == 0)
{
return n;
}
// go to next position
pos = dlist_next(g->nodes, pos);
}
return NULL;
}
/**
* graph_node_is_seen() - Return the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to return seen status for.
*
* Returns: The seen status for the node.
*/
bool graph_node_is_seen(const graph *g, const node *n)
{
// get start position
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
// if node is one we are looking for, check seen status
if (nodes_are_equal(e, n))
{
return e->seen;
}
// increment position
pos = dlist_next(g->nodes, pos);
}
return false;
}
/**
* graph_node_set_seen() - Set the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to set seen status for.
* @s: Status to set.
*
* Returns: The modified graph.
*/
graph *graph_node_set_seen(graph *g, node *n, bool seen)
{
// get beginning position
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
node *e = dlist_inspect(g->nodes, pos);
// check if nodes are same as one we look for
if (nodes_are_equal(e, n))
{
// set node to seen
e->seen = seen;
break;
}
// increment pos in list
pos = dlist_next(g->nodes, pos);
}
return g;
}
/**
* graph_reset_seen() - Reset the seen status on all nodes in the graph.
* @g: Graph to modify.
*
* Returns: The modified graph.
*/
graph *graph_reset_seen(graph *g)
{
// get starting position
dlist_pos pos = dlist_first(g->nodes);
while (!dlist_is_end(g->nodes, pos))
{
// if node is seen, reset
node *n = dlist_inspect(g->nodes, pos);
if (n->seen == true)
{
n->seen = false;
}
// increment over list
pos = dlist_next(g->nodes, pos);
}
return g;
}
/**
* graph_insert_edge() - Insert an edge into the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* NOTE: Undefined unless both nodes are already in the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_edge(graph *g, node *n1, node *n2)
{
// get starting position
dlist_pos pos = dlist_first(n1->edge);
while (!dlist_is_end(n1->edge, pos))
{
node *n = dlist_inspect(n1->edge, pos);
// check if node already is in edge list
if (nodes_are_equal(n2, n))
{
return g;
}
// increment to next position
pos = dlist_next(n1->edge, pos);
}
// inserts the edge in node list.
dlist_insert(n1->edge, n2, dlist_first(n1->edge));
return g;
}
/**
* graph_neighbours() - Return a list of neighbour nodes.
* @g: Graph to inspect.
* @n: Node to get neighbours for.
*
* Returns: A pointer to a list of nodes. Note: The list must be
* dlist_kill()-ed after use.
*/
dlist *graph_neighbours(const graph *g, const node *n)
{
// Create a new list
dlist *copy = dlist_empty(NULL);
if (n == NULL || n->edge == NULL) {
return copy;
}
// Copy nodes to new list, so list can be dlost_kill-ed outside.
dlist_pos pos = dlist_first(n->edge);
while (!dlist_is_end(n->edge, pos)) {
void *node = dlist_inspect(n->edge, pos);
dlist_insert(copy, node, dlist_first(copy));
pos = dlist_next(n->edge, pos);
}
return copy;
}
/**
* graph_kill() - Destroy a given graph.
* @g: Graph to destroy.
*
* Return all dynamic memory used by the graph.
*
* Returns: Nothing.
*/
void graph_kill(graph *g)
{
dlist_kill(g->nodes);
free(g);
}
/**
* graph_print() - Iterate over the graph elements and print their values.
* @g: Graph to inspect.
*
* Iterates over the graph and prints its contents.
*
* Returns: Nothing.
*/
void graph_print(const graph *g)
{
// get first position
dlist_pos pos = dlist_first(g->nodes);
// iterate and prints node
while (!dlist_is_end(g->nodes, pos))
{
node *n = dlist_inspect(g->nodes, pos);
printf("%s to nodes: ", (char *)n->value);
// get edges pos, and print edges of node.
dlist_pos pos_edge = dlist_first(n->edge);
while (!dlist_is_end(n->edge, pos_edge))
{
node *e = dlist_inspect(n->edge, pos_edge);
printf("%s,", (char *)e->value);
// goes to next edge in list
pos_edge = dlist_next(n->edge, pos_edge);
}
printf("\n");
// goes to next node in list.
pos = dlist_next(g->nodes, pos);
}
}

33
OU4/implementation.txt Normal file
View File

@@ -0,0 +1,33 @@
Vad som ska göras
1. Huvudprogram som löser inmatning från användaren
* Ska läsa in grafen från kartfilen interagera med användaren och köra sökalgoritmen se punkt 3
* Efter start ska "origin" och "destination" efterfrågas
* Om de två noderna är sammanlänkade ska programmet meddela det
* Om "origin" och "destination" är samma anses de vara sammanlänkade
* Om "quit" skrivs ska programmet avslutas
* Om felaktig indata anges ska ett lämpligt felmeddelande skrivas ut
* Utskrifterna ska följa specifikiationen exakt och göras med printf()
'Enter origin and destination (quit to exit): '
* Om kart-filen inte har ett korrekt format ska programmet avslutas med exit(EXIT_FAILURE)
2. Uppbyggnad av implementationen av graph1/2
* Gränsytan finns beskriven i graph.h
* Läs noga info om graph_neighbours()
* Valfritt hur noderna representeras
* Två olika implementationer av graph ska göras
* graph.c
* Ska använda sig av array_2d internt
* graph2.c
* Valfri implementation men rekommenderat att använda fält av lista
3. Sorteringsalgoritm
* Två strängar anses lika om hjälpfunktionen bool nodes_are_equal returnerar true

150
OU4/include/array_1d.h Normal file
View File

@@ -0,0 +1,150 @@
#ifndef __ARRAY_1D_H
#define __ARRAY_1D_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic 1D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The array stores void pointers, so it can be used to
* store all types of values. After use, the function array_kill must
* be called to de-allocate the dynamic memory used by the array
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the array,
* unless a kill_function is registered in array_create.
*
* An element value of NULL is considered to be "no" value.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.5 2024-03-13: Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.0 2024-05-10: Added print_internal.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct array_1d array_1d;
// ==========DATA STRUCTURE INTERFACE==========
/**
* array_1d_create() - Create an array without values.
* @lo: low index limit.
* @hi: high index limit.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
array_1d *array_1d_create(int lo, int hi, kill_function kill_func);
/**
* array_1d_low() - Return the low index limit for the array.
* @a: array to inspect.
*
* Returns: The low index limit.
*/
int array_1d_low(const array_1d *a);
/**
* array_1d_high() - Return the high index limit for the array.
* @a: array to inspect.
*
* Returns: The high index limit.
*/
int array_1d_high(const array_1d *a);
/**
* array_1d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: The element value at the specified position. The result is
* undefined if no value are stored at that position.
*/
void *array_1d_inspect_value(const array_1d *a, int i);
/**
* array_1d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool array_1d_has_value(const array_1d *a, int i);
/**
* array_1d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or NULL to clear value.
* @i: index of position to modify.
*
* If the old element value is non-NULL, calls kill_func if it was
* specified at array creation.
*
* Returns: Nothing.
*/
void array_1d_set_value(array_1d *a, void *v, int i);
/**
* array_1d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Iterates over all elements. If kill_func was specified at array
* creation, calls it for every non-NULL element value.
*
* Returns: Nothing.
*/
void array_1d_kill(array_1d *a);
/**
* array_1d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
* @print_func: Function called for each non-NULL element.
*
* Iterates over each position in the array. Calls print_func for each
* non-NULL value.
*
* Returns: Nothing.
*/
void array_1d_print(const array_1d * l, inspect_callback print_func);
/**
* array_1d_print_internal() - Print the internal structure of the array in dot format.
* @a: Array to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void array_1d_print_internal(const array_1d *a, inspect_callback print_func, const char *desc,
int indent_level);
#endif

158
OU4/include/array_2d.h Normal file
View File

@@ -0,0 +1,158 @@
#ifndef __ARRAY_2D_H
#define __ARRAY_2D_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic 2D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The array stores void pointers, so it can be used to
* store all types of values. After use, the function array_kill must
* be called to de-allocate the dynamic memory used by the array
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the array,
* unless a kill_function is registered in array_create.
*
* An element value of NULL is considered to be "no" value.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Moved freehandler to last in create parameter list.
* v1.2 2024-05-10: Added print_internal.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct array_2d array_2d;
// ==========DATA STRUCTURE INTERFACE==========
/**
* array_2d_create() - Create an array without values.
* @lo1: low index limit for first dimension.
* @hi1: high index limit for first dimension.
* @lo2: low index limit for second dimension.
* @hi2: high index limit for second dimension.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
array_2d *array_2d_create(int lo1, int hi1, int lo2, int hi2,
kill_function kill_func);
/**
* array_2d_low() - Return the low index limit for the array.
* @a: array to inspect.
* @d: dimension number, 1 or 2.
*
* Returns: The low index limit for dimension number d.
*/
int array_2d_low(const array_2d *a, int d);
/**
* array_2d_high() - Return the high index limit for the array.
* @a: array to inspect.
* @d: dimension number, 1 or 2.
*
* Returns: The high index limit for dimension number d.
*/
int array_2d_high(const array_2d *a, int d);
/**
* array_2d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: first index of position to inspect.
* @j: second index of position to inspect.
*
* Returns: The element value at the specified position. The result is
* undefined if no value are stored at that position.
*/
void *array_2d_inspect_value(const array_2d *a, int i, int j);
/**
* array_2d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: first index of position to inspect.
* @j: second index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool array_2d_has_value(const array_2d *a, int i, int j);
/**
* array_2d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or NULL to clear value.
* @i: first index of position to inspect.
* @j: second index of position to inspect.
*
* If the old element value is non-NULL, calls kill_func if it was
* specified at array creation.
*
* Returns: Nothing.
*/
void array_2d_set_value(array_2d *a, void *v, int i, int j);
/**
* array_2d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Iterates over all elements. If kill_func was specified at array
* creation, calls it for every non-NULL element value.
*
* Returns: Nothing.
*/
void array_2d_kill(array_2d *a);
/**
* array_2d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
* @print_func: Function called for each non-NULL element.
*
* Iterates over each position in the array. Calls print_func for each
* non-NULL value.
*
* Returns: Nothing.
*/
void array_2d_print(const array_2d * l, inspect_callback print_func);
/**
* array_2d_print_internal() - Print the arrays internal structure.
* @a: Array to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void array_2d_print_internal(const array_2d *a, inspect_callback print_func, const char *desc,
int indent_level);
#endif

199
OU4/include/dlist.h Normal file
View File

@@ -0,0 +1,199 @@
#ifndef __DLIST_H
#define __DLIST_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic, directed list for the "Datastructures
* and algorithms" courses at the Department of Computing Science,
* Umea University. The list stores void pointers, so it can be used
* to store all types of values. After use, the function list_kill
* must be called to de-allocate the dynamic memory used by the list
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the list,
* unless a kill_function is registered in list_empty.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added dlist_pos_equal and dlist_pos_is_valid functions.
* v1.2 2023-01-20: Renamed dlist_pos_equal to dlist_pos_are_equal.
* v1.3 2023-03-23: Renamed dlist_pos_are_equal to dlist_pos_is_equal.
* v2.0 2024-03-14: Added dlist_print_internal to output dot code for visualization.
* Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.1 2024-05-10: updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct dlist dlist;
// List position type.
typedef struct cell *dlist_pos;
// ==========DATA STRUCTURE INTERFACE==========
/**
* dlist_empty() - Create an empty dlist.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new list.
*/
dlist *dlist_empty(kill_function kill_func);
/**
* dlist_is_empty() - Check if a dlist is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool dlist_is_empty(const dlist *l);
/**
* dlist_first() - Return the first position of a dlist, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
dlist_pos dlist_first(const dlist *l);
/**
* dlist_next() - Return the next position in a dlist.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
dlist_pos dlist_next(const dlist *l, const dlist_pos p);
/**
* dlist_is_end() - Check if a given position is at the end of a dlist.
* @l: List to inspect.
* @p: Any valid position in the list.
*
* Returns: True if p is at the end of the list.
*/
bool dlist_is_end(const dlist *l, const dlist_pos p);
/**
* dlist_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: Returns the value at the given position as a void pointer.
* NOTE: The return value is undefined for the last position.
*/
void *dlist_inspect(const dlist *l, const dlist_pos p);
/**
* dlist_insert() - Insert a new element with a given value into a dlist.
* @l: List to manipulate.
* @v: Value (pointer) to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
dlist_pos dlist_insert(dlist *l, void *v, const dlist_pos p);
/**
* dlist_remove() - Remove an element from a dlist.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list. If a kill_func
* was registered at list creation, calls it to deallocate the memory
* held by the element value.
*
* Returns: The position after the removed element.
*/
dlist_pos dlist_remove(dlist *l, const dlist_pos p);
/**
* dlist_kill() - Destroy a given dlist.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements. If a
* kill_func was registered at list creation, also calls it for each
* element to return any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void dlist_kill(dlist *l);
/**
* dlist_print() - Iterate over the list elements and print their values.
* @l: List to inspect.
* @print_func: Function called for each element.
*
* Iterates over the list and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void dlist_print(const dlist *l, inspect_callback print_func);
/**
* dlist_pos_is_valid() - Return true for a valid position in a dlist
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool dlist_pos_is_valid(const dlist *l, const dlist_pos p);
/**
* dlist_pos_is_equal() - Return true if two positions in a dlist are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
* p1 and p2 are assumed to be valid positions in l, no check is performed.
*/
bool dlist_pos_is_equal(const dlist *l, const dlist_pos p1, const dlist_pos p2);
/**
* dlist_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void dlist_print_internal(const dlist *l, inspect_callback print_func, const char *desc,
int indent_level);
#endif

200
OU4/include/graph.h Normal file
View File

@@ -0,0 +1,200 @@
#ifndef __GRAPH_H
#define __GRAPH_H
#include <stdbool.h>
#include "util.h"
#include "dlist.h"
/*
* Declaration of a generic graph for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The graph stores nodes and edges of a directed or
* undirected graph. After use, the function graph_kill() must
* be called to de-allocate the dynamic memory used by the graph
* itself. The de-allocation of any dynamic memory allocated for the
* node names is the responsibility of the user of the graph.
*
* Author: Niclas Borlin (niclas.borlin@cs.umu.se)
*
* Version information:
* v1.0 2019-02-21: First public version.
* v1.01 2019-02-26: Modified include directives for header files
* from the codebase to use "" to handle case when
* student stores all header files in the current
* directory. See
* https://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename.
* v1.02 2019-03-01: Doc update in graph_node_is_seen().
* v1.1 2019-03-06: Changed several const node * to node *.
* Fixed doc bug to state that any dynamic memory allocated
* to the node NAMES is the resposibility of the user.
*/
// ====================== PUBLIC DATA TYPES ==========================
// Anonymous declarations of node and graph.
typedef struct node node;
typedef struct graph graph;
// =================== NODE COMPARISON FUNCTION ======================
/**
* nodes_are_equal() - Check whether two nodes are equal.
* @n1: Pointer to node 1.
* @n2: Pointer to node 2.
*
* Returns: true if the nodes are considered equal, otherwise false.
*
*/
bool nodes_are_equal(const node *n1,const node *n2);
// =================== GRAPH STRUCTURE INTERFACE ======================
/**
* graph_empty() - Create an empty graph.
* @max_nodes: The maximum number of nodes the graph can hold.
*
* Returns: A pointer to the new graph.
*/
graph *graph_empty(int max_nodes);
/**
* graph_is_empty() - Check if a graph is empty, i.e. has no nodes.
* @g: Graph to check.
*
* Returns: True if graph is empty, otherwise false.
*/
bool graph_is_empty(const graph *g);
/**
* graph_has_edges() - Check if a graph has any edges.
* @g: Graph to check.
*
* Returns: True if graph has any edges, otherwise false.
*/
bool graph_has_edges(const graph *g);
/**
* graph_insert_node() - Inserts a node with the given name into the graph.
* @g: Graph to manipulate.
* @s: Node name.
*
* Creates a new node with a copy of the given name and puts it into
* the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_node(graph *g, const char *s);
/**
* graph_find_node() - Find a node stored in the graph.
* @g: Graph to manipulate.
* @s: Node identifier, e.g. a char *.
*
* Returns: A pointer to the found node, or NULL.
*/
node *graph_find_node(const graph *g, const char *s);
/**
* graph_node_is_seen() - Return the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to return seen status for.
*
* Returns: The seen status for the node.
*/
bool graph_node_is_seen(const graph *g, const node *n);
/**
* graph_node_set_seen() - Set the seen status for a node.
* @g: Graph storing the node.
* @n: Node in the graph to set seen status for.
* @s: Status to set.
*
* Returns: The modified graph.
*/
graph *graph_node_set_seen(graph *g, node *n, bool seen);
/**
* graph_reset_seen() - Reset the seen status on all nodes in the graph.
* @g: Graph to modify.
*
* Returns: The modified graph.
*/
graph *graph_reset_seen(graph *g);
/**
* graph_insert_edge() - Insert an edge into the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* NOTE: Undefined unless both nodes are already in the graph.
*
* Returns: The modified graph.
*/
graph *graph_insert_edge(graph *g, node *n1, node *n2);
/**
* graph_delete_node() - Remove a node from the graph.
* @g: Graph to manipulate.
* @n: Node to remove from the graph.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the node is not in the graph.
*/
graph *graph_delete_node(graph *g, node *n);
/**
* graph_delete_edge() - Remove an edge from the graph.
* @g: Graph to manipulate.
* @n1: Source node (pointer) for the edge.
* @n2: Destination node (pointer) for the edge.
*
* Returns: The modified graph.
*
* NOTE: Undefined if the edge is not in the graph.
*/
graph *graph_delete_edge(graph *g, node *n1, node *n2);
/**
* graph_choose_node() - Return an arbitrary node from the graph.
* @g: Graph to inspect.
*
* Returns: A pointer to an arbitrayry node.
*
* NOTE: The return value is undefined for an empty graph.
*/
node *graph_choose_node(const graph *g);
/**
* graph_neighbours() - Return a list of neighbour nodes.
* @g: Graph to inspect.
* @n: Node to get neighbours for.
*
* Returns: A pointer to a list of nodes. Note: The list must be
* dlist_kill()-ed after use.
*/
dlist *graph_neighbours(const graph *g,const node *n);
/**
* graph_kill() - Destroy a given graph.
* @g: Graph to destroy.
*
* Return all dynamic memory used by the graph.
*
* Returns: Nothing.
*/
void graph_kill(graph *g);
/**
* graph_print() - Iterate over the graph elements and print their values.
* @g: Graph to inspect.
*
* Iterates over the graph and prints its contents.
*
* Returns: Nothing.
*/
void graph_print(const graph *g);
#endif

136
OU4/include/int_array_1d.h Normal file
View File

@@ -0,0 +1,136 @@
#ifndef __INT_ARRAY_1D_H
#define __INT_ARRAY_1D_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of an integer 1D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. After use, the function array_kill must be called to
* de-allocate the dynamic memory used by the array itself.
*
* An element value of 0 is considered to be "no" value.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.2 2024-05-10: Added print_internal.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct int_array_1d int_array_1d;
// ==========DATA STRUCTURE INTERFACE==========
/**
* int_array_1d_create() - Create an array without values.
* @lo: low index limit.
* @hi: high index limit.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
int_array_1d *int_array_1d_create(int lo, int hi);
/**
* int_array_1d_low() - Return the low index limit for the array.
* @a: array to inspect.
*
* Returns: The low index limit.
*/
int int_array_1d_low(const int_array_1d *a);
/**
* int_array_1d_high() - Return the high index limit for the array.
* @a: array to inspect.
*
* Returns: The high index limit.
*/
int int_array_1d_high(const int_array_1d *a);
/**
* int_array_1d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: The element value at the specified position, or 0 if no
* value is stored at that position.
*/
int int_array_1d_inspect_value(const int_array_1d *a, int i);
/**
* int_array_1d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool int_array_1d_has_value(const int_array_1d *a, int i);
/**
* int_array_1d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or 0 to clear value.
* @i: index of position to modify.
*
* Returns: Nothing.
*/
void int_array_1d_set_value(int_array_1d *a, int v, int i);
/**
* int_array_1d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Iterates over all elements. If free_func was specified at array
* creation, calls it for every non-NULL element value.
*
* Returns: Nothing.
*/
void int_array_1d_kill(int_array_1d *a);
/**
* int_array_1d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
*
* Iterates over each position in the array. Prints each non-zero element.
*
* Returns: Nothing.
*/
void int_array_1d_print(const int_array_1d *a);
/**
* int_array_1d_print_internal() - Print the arrays internal structure in dot format.
* @a: Array to inspect.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void int_array_1d_print_internal(const int_array_1d *a, const char *desc, int indent_level);
#endif

192
OU4/include/int_list.h Normal file
View File

@@ -0,0 +1,192 @@
#ifndef __INT_LIST_H
#define __INT_LIST_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a undirected list for storing integers for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University. The implementation uses a
* dynamic, linked structure. After use, the function list_kill must
* be called to de-allocate the dynamic memory used by the list
* itself. The implementation is a written a code copy specialization
* of the generic list to provide a simpler starting data structure
* than the generic list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v1.4 2024-05-10: Added print_internal.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct list list;
// List position type.
typedef struct cell *list_pos;
// ==========DATA STRUCTURE INTERFACE==========
/**
* list_empty() - Create an empty list.
*
* Returns: A pointer to the new list.
*/
list *list_empty(void);
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list *l);
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list *l);
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list *l);
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list *l, const list_pos p);
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list *l, const list_pos p);
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The integer value stored in the element at postiion pos.
* NOTE: The return value is undefined for the last position.
*/
int list_inspect(const list *l, const list_pos p);
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @data: Integer value to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list *l, int data, const list_pos p);
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p);
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list.
*
* Returns: Nothing.
*/
void list_kill(list *l);
/**
* list_print() - Iterate over the list elements and print their values.
* @l: List to inspect.
*
* Iterates over the list and prints each stored integer.
*
* Returns: Nothing.
*/
void list_print(const list *l);
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p);
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
* p1 and p2 are assumed to be valid positions in l, no check is performed.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2);
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, const char *desc, int indent_level);
#endif

View File

@@ -0,0 +1,193 @@
#ifndef __INT_LIST_ARRAY_H
#define __INT_LIST_ARRAY_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a undirected list for storing integers for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University. The implementation uses a
* static array. After use, the function list_kill must be called to
* de-allocate the dynamic memory used by the list itself. The
* implementation is a written a code copy specialization of the
* generic list to provide a simpler starting data structure than the
* generic list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-03-26: First public version.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* Bugfix in list_remove.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v1.4 2024-05-10: Added print_internal.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct list list;
// List position type.
typedef int list_pos;
// ==========DATA STRUCTURE INTERFACE==========
/**
* list_empty() - Create an empty list.
*
* Returns: A pointer to the new list.
*/
list *list_empty(void);
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list *l);
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list *l);
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list *l);
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list *l, const list_pos p);
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list *l, const list_pos p);
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The integer value stored in the element at postiion pos.
* NOTE: The return value is undefined for the last position.
*/
int list_inspect(const list *l, const list_pos p);
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @data: Integer value to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list *l, int data, const list_pos p);
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p);
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list.
*
* Returns: Nothing.
*/
void list_kill(list *l);
/**
* list_print() - Iterate over the list elements and print their values.
* @l: List to inspect.
*
* Iterates over the list and prints each stored integer.
*
* Returns: Nothing.
*/
void list_print(const list *l);
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p);
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
* p1 and p2 are assumed to be valid positions in l, no check is performed.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2);
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, const char *desc, int indent_level);
#endif

126
OU4/include/int_queue.h Normal file
View File

@@ -0,0 +1,126 @@
#ifndef __INT_QUEUE_H
#define __INT_QUEUE_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of an integer queue for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The queue stores integers directly and does not use
* dynamic memory. Thus, the clean-up function queue_kill is strictly
* not necessary, but recommended to maintain symmetry with untyped,
* generic queue implementations.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-10: First public version.
*/
// ==========PUBLIC CONSTANTS AND DATA TYPES============
// Maximum size of the queue.
#define MAX_QUEUE_SIZE 100
// We must define the struct publically for the compiler to know its
// size for copying, etc.
typedef struct queue {
int first_free_pos;
int elements[MAX_QUEUE_SIZE];
} queue;
// ==========DATA STRUCTURE INTERFACE==========
/**
* queue_empty() - Create an empty queue.
*
* Returns: A new, empty, queue.
*/
queue queue_empty(void);
/**
* queue_is_empty() - Check if a queue is empty.
* @q: Queue to check.
*
* Returns: True if queue is empty, otherwise false.
*/
bool queue_is_empty(const queue q);
/**
* queue_enqueue() - Put a value at the end of a queue.
* @q: Queue to manipulate.
* @v: Value (integer) to be put in the queue.
*
* Returns: The modified queue.
*/
queue queue_enqueue(queue q, int v);
/**
* queue_dequeue() - Remove the element at the beginning of a queue.
* @q: Queue to manipulate.
*
* NOTE: Undefined for an empty queue.
*
* Returns: The modified queue.
*/
queue queue_dequeue(queue q);
/**
* queue_front() - Inspect the value at the front of the queue.
* @q: Queue to inspect.
*
* Returns: The value at the front of the queue.
* NOTE: The return value is undefined for an empty queue.
*/
int queue_front(const queue q);
/**
* queue_kill() - Destroy a given queue.
* @q: Queue to destroy.
*
* Does nothing since the queue does not use any dynamic
* memory. Included for symmetry with generic queue.h.
*
* Returns: Nothing.
*/
void queue_kill(queue q);
/**
* queue_print() - Iterate over the queue elements and print their values.
* @q: Queue to inspect.
*
* Iterates over the queue and prints each integer.
*
* Returns: Nothing.
*/
void queue_print(const queue q);
/**
* queue_print_internal() - Print the internal structure of the queue in dot format.
* @q: Queue to inspect.
* @desc: String with a description/state of the queue, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost.
* @max_elems: Maximum number of elements to print.
*
* Iterates over the queue and outputs dot code that shows the
* internal structure of the queue. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <queue_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <queue_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void queue_print_internal(const queue q, const char *desc, int indent_level, int max_elems);
#endif

134
OU4/include/int_stack.h Normal file
View File

@@ -0,0 +1,134 @@
#ifndef __INT_STACK_H
#define __INT_STACK_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of an integer stack for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The stack stores integers directly and does not use
* dynamic memory. Thus, the clean-up function stack_kill is strictly
* not necessary, but recommended to maintain symmetry with untyped,
* generic stack implementations.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2024-04-15: Reduced default stack size to 15 to make output
* from print_internal readable.
* v1.2 2024-05-10: Updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// Stack type.
#define MAX_STACK_SIZE 100
// We must define the struct publically for the compiler to know its
// size for copying, etc.
typedef struct stack {
int first_free_pos;
int elements[MAX_STACK_SIZE];
} stack;
// ==========DATA STRUCTURE INTERFACE==========
/**
* stack_empty() - Create an empty stack.
*
* Returns: A new stack.
*/
stack stack_empty(void);
/**
* stack_is_empty() - Check if a stack is empty.
* @s: Stack to check.
*
* Returns: True if stack is empty, otherwise false.
*/
bool stack_is_empty(const stack s);
/**
* stack_push() - Push a value on top of a stack.
* @s: Stack to manipulate.
* @v: Value (integer) to be put on the stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack stack_push(stack s, int v);
/**
* stack_pop() - Remove the element at the top of a stack.
* @s: Stack to manipulate.
*
* NOTE: Undefined for an empty stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack stack_pop(stack s);
/**
* stack_top() - Inspect the value at the top of the stack.
* @s: Stack to inspect.
*
* Returns: The value at the top of the stack.
* NOTE: The return value is undefined for an empty stack.
*/
int stack_top(const stack s);
/**
* stack_kill() - Destroy a given stack.
* @s: Stack to destroy.
*
* Does nothing since the stack does not use any dynamic
* memory. Included for symmetry with generic stack.h.
*
* Returns: Nothing.
*/
void stack_kill(stack s);
/**
* stack_print() - Iterate over the stack elements and print their values.
* @s: Stack to inspect.
*
* Iterates over the stack and prints each integer.
*
* Returns: Nothing.
*/
void stack_print(const stack s);
/**
* stack_print_internal() - Print the internal structure of the stack in dot format.
* @s: Stack to inspect.
* @desc: String with a description/state of the stack, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost.
* @max_elems: Maximum number of elements to print.
*
* Iterates over the stack and outputs dot code that shows the
* internal structure of the stack. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <stack_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <stack_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void stack_print_internal(const stack s, const char *desc, int indent_level, int max_elems);
#endif

207
OU4/include/list.h Normal file
View File

@@ -0,0 +1,207 @@
#ifndef __LIST_H
#define __LIST_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic, undirected list for the "Datastructures
* and algorithms" courses at the Department of Computing Science,
* Umea University. The list stores void pointers, so it can be used
* to store all types of values. After use, the function list_kill
* must be called to de-allocate the dynamic memory used by the list
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the list,
* unless a kill_function is registered in list_empty.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v2.0 2024-03-14: Added list_print_internal to output dot code for visualization.
* v2.1 2024-05-10: Updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// List type.
typedef struct list list;
// List position type.
typedef struct cell *list_pos;
// ==========DATA STRUCTURE INTERFACE==========
/**
* list_empty() - Create an empty list.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new list.
*/
list *list_empty(kill_function kill_func);
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list *l);
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list *l);
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list *l);
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list *l, const list_pos p);
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list *l, const list_pos p);
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: Returns the value at the given position as a void pointer.
* NOTE: The return value is undefined for the last position.
*/
void *list_inspect(const list *l, const list_pos p);
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @v: Value (pointer) to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list *l, void *v, const list_pos p);
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list. If a kill_func
* was registered at list creation, calls it to deallocate the memory
* held by the element value.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p);
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements. If a
* kill_func was registered at list creation, also calls it for each
* element to return any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void list_kill(list *l);
/**
* list_print() - Iterate over the list elements and print their values.
* @l: List to inspect.
* @print_func: Function called for each element.
*
* Iterates over the list and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void list_print(const list *l, inspect_callback print_func);
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p);
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
* p1 and p2 are assumed to be valid positions in l, no check is performed.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2);
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, inspect_callback print_func, const char *desc,
int indent_level);
#endif

131
OU4/include/queue.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef __QUEUE_H
#define __QUEUE_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic queue for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The queue stores void pointers, so it can be used to
* store all types of values. After use, the function queue_kill must
* be called to de-allocate the dynamic memory used by the queue
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the queue,
* unless a kill_function is registered in queue_empty.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2024-05-10: Added/updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// Queue type.
typedef struct queue queue;
// ==========DATA STRUCTURE INTERFACE==========
/**
* queue_empty() - Create an empty queue.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new queue.
*/
queue *queue_empty(kill_function kill_func);
/**
* queue_is_empty() - Check if a queue is empty.
* @q: Queue to check.
*
* Returns: True if queue is empty, otherwise false.
*/
bool queue_is_empty(const queue *q);
/**
* queue_enqueue() - Put a value at the end of the queue.
* @q: Queue to manipulate.
* @v: Value (pointer) to be put in the queue.
*
* Returns: The modified queue.
*/
queue *queue_enqueue(queue *q, void *v);
/**
* queue_dequeue() - Remove the element at the front of a queue.
* @q: Queue to manipulate.
*
* NOTE: Undefined for an empty queue.
*
* Returns: The modified queue.
*/
queue *queue_dequeue(queue *q);
/**
* queue_front() - Inspect the value at the front of the queue.
* @q: Queue to inspect.
*
* Returns: The value at the top of the queue.
* NOTE: The return value is undefined for an empty queue.
*/
void *queue_front(const queue *q);
/**
* queue_kill() - Destroy a given queue.
* @q: Queue to destroy.
*
* Return all dynamic memory used by the queue and its elements. If a
* kill_func was registered at queue creation, also calls it for each
* element to kill any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void queue_kill(queue *q);
/**
* queue_print() - Iterate over the queue elements and print their values.
* @q: Queue to inspect.
* @print_func: Function called for each element.
*
* Iterates over the queue and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void queue_print(const queue *q, inspect_callback print_func);
/**
* queue_print_internal() - Print the internal structure of the queue in dot format.
* @q: Queue to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the queue, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the queue and outputs dot code that shows the internal
* structure of the queue. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <queue_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <queue_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void queue_print_internal(const queue *q, inspect_callback print_func, const char *desc,
int indent_level);
#endif

133
OU4/include/stack.h Normal file
View File

@@ -0,0 +1,133 @@
#ifndef __STACK_H
#define __STACK_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic stack for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The stack stores void pointers, so it can be used to
* store all types of values. After use, the function stack_kill must
* be called to de-allocate the dynamic memory used by the stack
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the stack,
* unless a kill_function is registered in stack_empty.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2024-05-10: Added/updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// Stack type.
typedef struct stack stack;
// ==========DATA STRUCTURE INTERFACE==========
/**
* stack_empty() - Create an empty stack.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new stack.
*/
stack *stack_empty(kill_function kill_func);
/**
* stack_is_empty() - Check if a stack is empty.
* @s: Stack to check.
*
* Returns: True if stack is empty, otherwise false.
*/
bool stack_is_empty(const stack *s);
/**
* stack_push() - Push a value on top of a stack.
* @s: Stack to manipulate.
* @v: Value (pointer) to be put on the stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack *stack_push(stack *s, void *v);
/**
* stack_pop() - Remove the element at the top of a stack.
* @s: Stack to manipulate.
*
* NOTE: Undefined for an empty stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack *stack_pop(stack *s);
/**
* stack_top() - Inspect the value at the top of the stack.
* @s: Stack to inspect.
*
* Returns: The value at the top of the stack.
* NOTE: The return value is undefined for an empty stack.
*/
void *stack_top(const stack *s);
/**
* stack_kill() - Destroy a given stack.
* @s: Stack to destroy.
*
* Return all dynamic memory used by the stack and its elements. If a
* kill_func was registered at stack creation, also calls it for each
* element to kill any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void stack_kill(stack *s);
/**
* stack_print() - Iterate over the stack elements and print their values.
* @s: Stack to inspect.
* @print_func: Function called for each element.
*
* Iterates over the stack and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void stack_print(const stack *s, inspect_callback print_func);
/**
* stack_print_internal() - Print the stacks internal structure in dot format.
* @l: Stack to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the stack, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the stack and outputs dot code that shows the internal
* structure of the stack. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <stack_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <stack_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void stack_print_internal(const stack *s, inspect_callback print_func, const char *desc,
int indent_level);
#endif

157
OU4/include/table.h Normal file
View File

@@ -0,0 +1,157 @@
#ifndef TABLE_H
#define TABLE_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic table for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The table stores void pointers, so it can be used to
* store all types of values. After use, the function table_kill must
* be called to de-allocate the dynamic memory used by the table
* itself. The de-allocation of any dynamic memory allocated for the
* key and/or value values is the responsibility of the user of the
* table, unless a corresponding kill_function is registered in
* table_empty.
*
* The internal handling of duplicates are transparent to the user of
* the table. Depending on the table design, a duplicate may or may
* not be stored internally. The user of the table should not make any
* assumption about which solution is implemented.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-02-06: First public version.
* v1.1 2024-04-15: Changed the comments to leave room for different
* internal handling of duplicates.
* v1.2 2024-05-10: Added/updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// Table type.
typedef struct table table;
// ==========DATA STRUCTURE INTERFACE==========
/**
* table_empty() - Create an empty table.
* @key_cmp_func: A pointer to a function to be used to compare keys. See
* util.h for the definition of compare_function.
* @key_kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory for keys on remove/kill.
* @value_kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory for values on remove/kill.
*
* Returns: Pointer to a new table.
*/
table *table_empty(compare_function key_cmp_func,
kill_function key_kill_func,
kill_function value_kill_func);
/**
* table_is_empty() - Check if a table is empty.
* @t: Table to check.
*
* Returns: True if table contains no key/value pairs, false otherwise.
*/
bool table_is_empty(const table *t);
/**
* table_insert() - Add a key/value pair to a table.
* @t: Table to manipulate.
* @key: A pointer to the key value.
* @value: A pointer to the value value.
*
* Insert the key/value pair into the table. If the key already
* exists, the key/value overwrites the existing pair. The technical
* details are internal to the datatype. At any rate, table_lookup()
* will return the latest added value for a duplicate
* key and table_remove() will remove all duplicates for a given key.
*
* Returns: Nothing.
*/
void table_insert(table *t, void *key, void *value);
/**
* table_lookup() - Look up a given key in a table.
* @t: Table to inspect.
* @key: Key to look up.
*
* Returns: The value corresponding to a given key, or NULL if the key
* is not found in the table. If the table contains duplicate keys,
* the value that was latest inserted will be returned.
*/
void *table_lookup(const table *t, const void *key);
/**
* table_choose_key() - Return an arbitrary key.
* @t: Table to inspect.
*
* Return an arbitrary key stored in the table. Can be used together
* with table_remove() to deconstruct the table. Undefined for an
* empty table.
*
* Returns: An arbitrary key stored in the table.
*/
void *table_choose_key(const table *t);
/**
* table_remove() - Remove a key/value pair in the table.
* @t: Table to manipulate.
* @key: Key for which to remove pair.
*
* Any matching duplicates will be removed. Will call any kill
* functions set for keys/values. Does nothing if key is not found in
* the table.
*
* Returns: Nothing.
*/
void table_remove(table *t, const void *key);
/**
* table_kill() - Destroy a table.
* @t: Table to destroy.
*
* Return all dynamic memory used by the table and its elements. If a
* kill_func was registered for keys and/or values at table creation,
* it is called each element to free any user-allocated memory
* occupied by the element values.
*
* Returns: Nothing.
*/
void table_kill(table *t);
/**
* table_print() - Print the given table.
* @t: Table to print.
* @print_func: Function called for each key/value pair in the table.
*
* Iterates over the key/value pairs in the table and prints them.
* Will print all stored elements, including any duplicates.
*
* Returns: Nothing.
*/
void table_print(const table *t, inspect_callback_pair print_func);
/**
* table_print_internal() - Output the internal structure of the table.
* @t: Table to print.
* @key_print_func: Function called for each key in the table.
* @value_print_func: Function called for each value in the table.
* @desc: String with a description/state of the list.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and prints code that shows its' internal structure.
*
* Returns: Nothing.
*/
void table_print_internal(const table *t, inspect_callback key_print_func,
inspect_callback value_print_func, const char *desc,
int indent_level);
#endif

83
OU4/include/util.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef __UTIL_H
#define __UTIL_H
/*
* Utility function types for deallocating, printing and comparing
* values stored by various data types.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-02-06: Updated explanation for the compare_function.
* v1.2 2023-01-14: Added version define constants and strings.
* v1.3 2024-03-13: Added PTR2ADDR macro.
*/
// Macros to create a version string out of version constants
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
// Version constants
#define CODE_BASE_MAJOR_VERSION 2
#define CODE_BASE_MINOR_VERSION 2
#define CODE_BASE_REVISION 2
#define CODE_BASE_PATCH 2
#define CODE_BASE_RELEASE_DATE "2025-01-24"
// Create a short version string
#define CODE_BASE_VERSION "v" \
STR(CODE_BASE_MAJOR_VERSION) \
"." \
STR(CODE_BASE_MINOR_VERSION) \
"." \
STR(CODE_BASE_REVISION) \
"." \
STR(CODE_BASE_PATCH)
// Create a version string
#define CODE_BASE_LONG_VERSION "Version: " \
STR(CODE_BASE_MAJOR_VERSION) \
"." \
STR(CODE_BASE_MINOR_VERSION) \
"." \
STR(CODE_BASE_REVISION) \
"." \
STR(CODE_BASE_PATCH)
// Type definition for de-allocator function, e.g. free().
typedef void (*kill_function)(void *);
// For backwards compatibility with pre-v2.0 code.
typedef kill_function free_function;
// Type definition for read-only callback for single-value containers,
// used by e.g. print functions.
typedef void (*inspect_callback)(const void *);
// Ditto for dual-value containers.
typedef void (*inspect_callback_pair)(const void *, const void *);
// Type definition for comparison function, used by e.g. table.
//
// Comparison functions should return values that indicate the order
// of the arguments. If the first argument is considered less/lower
// than the second, a negative value should be returned. If the first
// argument is considered more/higher than the second, a positive value
// should be returned. If the arguments are considered equal, a zero
// value should be returned.
typedef int compare_function(const void *,const void *);
// Constant used by ptr2addr, used by various print_internal functions.
#define PTR2ADDR_MASK 0xffff
// Macro that acts as a function to convert the address in the pointer
// p into an unsigned long value, keeping only the part indicated by
// the mask.
#define PTR2ADDR(p) (((unsigned long)p) & PTR2ADDR_MASK)
#endif

359
OU4/is_connected.c Normal file
View File

@@ -0,0 +1,359 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <graph.h>
#include <ctype.h>
#include <queue.h>
#include <dlist.h>
#include <string.h>
#define MAXNODENAME 40
#define BUFSIZE 400
/*
* is:connected.c: The main program for traversing a graph for "Obligatorisk uppgift 4" in the "Datastructures and
* algorithms" course at the Department of Computing Science, Umea University.
*
* Authors: Ellen Horneij tfy22ehj
* Jakob Nyström tfy22jnm
* Marc Meunier tfy22mmr
*
* Version information:
* v1.0 2025-05-25: First public version.
* v2.0 2025-06-02: Fixed traversing
* v3.0 2025-07-29: Fixed error messages
*
*/
// ===========HELP FUNCTIONS ============
/**
* @brief Find position of first non-whitespace character.
*
* @param s - string to search.
* @return int - Returns the position of the first non-whitespace character, or -1 if not found.
*/
int first_non_white_space(const char *s)
{
int i = 0; // Start at first char.
// Advance as long as we're loooking at white-space until we hit EOL.
while (s[i] && isspace(s[i]))
{
i++;
}
// We found a non-whitespace char.
if (s[i])
{
// It was a proper characted. Return its position.
return i;
}
else
{
// It was the null terminator. Return fail.
return -1;
}
}
/**
* @brief Determine if the string is blank.
*
* @param s - string to search.
* @return true if the line contains only whitespace chars.
* @return false if the line contains at least one non-whitespace char.
*/
bool line_is_blank(const char *s)
{
// Line is blank if it only contained white-space chars.
return first_non_white_space(s) < 0;
}
/**
* @brief Determine if the string is a comment line.
*
* @param s - string to search.
* @return true if the line is a comment line.
* @return false if the line is not a comment line.
*
* A comment line has a hash sign '#' as the first non-whitespace char on the line.
*/
bool line_is_comment(const char *s)
{
int i = first_non_white_space(s);
return (i >= 0 && s[i] == '#');
}
/**
* @brief Extract node names from a line from the map file.
*
* @param buf - Input buffer.
* @param n1 - Output buffer for the first node name. Must be at least MAXNODENAME+1 long.
* @param n2 - Ditto for the second node name.
* @return int - Returns the number of correctly parsed node names. If the return value is 2, both n1
* and n2 contain node names. If the return value is less than 2, parsing of at least one node name
* failed, in which case the content of n1 and n2 are undefined.
*/
int parse_map_line(const char *buf, char *n1, char *n2)
{
// Create a format string the will do the work.
char fmt[20];
// This will generate the format string " %40s %40s" if MAXNODENAME is 40.
snprintf(fmt, sizeof(fmt), " %%%ds %%%ds", MAXNODENAME, MAXNODENAME);
// sscanf does all the necessary parsing.
// Node names must be separated by whitespace.
// Whitespace before the first node name is allowed.
// Anything after the second node name is ignored.
int n = sscanf(buf, fmt, n1, n2);
// The return value from sscanf contains the number of properly parsed format codes, i.e. the
// number of node names.
return n;
}
/**
* FUNCTION TO TRAVERSE THE GRAPH
* @g: pointer to the graph
* @src: pointer to source node
* @dest: pointer to destination node
*/
bool find_path(graph *g, node *src, node *dest)
{
// Mark the starting node as seen
g = graph_node_set_seen(g, src, true);
dlist *neighbours = dlist_empty(NULL);
// Put it in an empty queue
queue *q = queue_enqueue(queue_empty(NULL), src);
while (!queue_is_empty(q))
{
// pick the first node from queue
src = queue_front(q);
q = queue_dequeue(q);
// if node equals destinatiom node, return true
if (nodes_are_equal(src, dest))
{
// Deallocate the queue and list
queue_kill(q);
dlist_kill(neighbours);
return true;
}
// remove list before making new.
if (neighbours != NULL)
{
dlist_kill(neighbours);
}
// get the neighbours
neighbours = graph_neighbours(g, src);
dlist_pos p = dlist_first(neighbours);
// Iterate over the lists of neigbours
while (!dlist_is_end(neighbours, p))
{
if (!graph_node_is_seen(g, dlist_inspect(neighbours, p)))
{
// Mark unseen node as seen and put in queue
g = graph_node_set_seen(g, dlist_inspect(neighbours, p), true);
q = queue_enqueue(q, dlist_inspect(neighbours, p));
}
p = dlist_next(neighbours, p);
}
}
// Deallocate the list and the queue
dlist_kill(neighbours);
queue_kill(q);
return false;
}
/**
* check_node_name - function used to find errors in node name
*
* Returns: Exit faliure if error in map file
*/
void check_node_name(char *n1, char *n2, char *data)
{
int k = parse_map_line(data, n1, n2);
//Print error if number of correct node names is not 2
if (k != 2)
{
fprintf(stderr, "Error reading the file\n");
exit(EXIT_FAILURE);
}
//Check for non alphanumeric characters
for (int j = 0; j < strlen(n1); j++)
{
if (isalnum(n1[j])==0)
{
fprintf(stderr, "Error non alphanumeric\n");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < strlen(n2); i++)
{
if (isalnum(n2[i])==0)
{
fprintf(stderr, "Error non alphanumeric\n");
exit(EXIT_FAILURE);
}
}
}
/**
* insert_nodes - insert the nodes to the graph
* Returns: A graph with the input nodes inserted
*/
graph *insert_nodes(graph *g, char *n1, char *n2)
{
g = graph_insert_node(g, n1);
g = graph_insert_node(g, n2);
// Get pointers to the nodes from the graph
node *m1 = graph_find_node(g, n1);
node *m2 = graph_find_node(g, n2);
// Check that both nodes exist
if (m1 == NULL || m2 == NULL)
{
fprintf(stderr, "Error: node not found for edge: %s - %s\n", n1, n2);
exit(EXIT_FAILURE);
}
// Insert the edges between the source and destination nodes and between the nodes themselves
g = graph_insert_edge(g, m1, m1);
g = graph_insert_edge(g, m2, m2);
g = graph_insert_edge(g, m1, m2);
return g;
}
/**
* graph_from_file - reads the file and constructs a graph with it's contents
* Returns: A pointer to the constructed graph
*/
graph *graph_from_file(int argc, char *argv[])
{
char data[40];
// Open the file
if (argc != 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return NULL;
}
const char *filename = argv[1];
// Print error message if file did not read correctly an exit program
FILE *fptr = fopen(filename, "r");
if (fptr == NULL)
{
perror("Error opening file\n");
return NULL;
}
// Read the first line of the map-file
fgets(data, 40, fptr);
// Ignore comments and blank rows
while (line_is_blank(data) || line_is_comment(data))
{
fgets(data, 40, fptr);
}
//Check that first non blank or coment line is a digit
for (int i = 0; i < strlen(data) - 1; i++)
{
if (!isdigit(data[i]))
{
fprintf(stderr, "Error: first row is not a number\n");
exit(EXIT_FAILURE);
}
}
// Read the number of edges in the map-file and create an empty graph
int nr_of_edges = atoi(data);
graph *g = graph_empty(2 * nr_of_edges);
// Iterates over the edge imputs
for (int i = 0; i < nr_of_edges; i++)
{
// Read the data, parse the data and insert it into nodes in the graph
fgets(data, 40, fptr);
char n1[MAXNODENAME + 1];
char n2[MAXNODENAME + 1];
check_node_name(n1,n2,data);
g = insert_nodes(g,n1,n2);
}
// Close the file and return the graph
fclose(fptr);
return g;
}
/**
* main - The main program that handles user inputs and runs all of the help functions
*
* Returns: 0 if program exits normally
*
*/
int main(int argc, char *argv[])
{
// Read the file and insert it into a graph
graph *g = graph_from_file(argc, argv);
// If file opening fails
if (g == NULL)
{
return EXIT_FAILURE;
}
char src[MAXNODENAME + 1];
char dest[MAXNODENAME + 1];
char fmt[20];
char buf[100];
// Print the user interface
printf("Enter origin and destination (quit to exit): ");
// This will generate the format string " %40s %40s" if MAXNODENAME is 40.
snprintf(fmt, sizeof(fmt), " %%%ds %%%ds", MAXNODENAME, MAXNODENAME);
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
// Reads the input from the user
sscanf(buf, fmt, src, dest);
// Quit the program if the user enters "quit"
if (strcmp(src, "quit") == 0)
{
break;
}
// Check that the nodes exist in the graph
node *nsrc = graph_find_node(g, src);
node *ndest = graph_find_node(g, dest);
if (nsrc == NULL || ndest == NULL)
{
printf("One or both nodes not found in the graph.\n");
}
// If the nodes exist check if there is a path and print the result
else if (find_path(g, nsrc, ndest))
{
printf("There is a path from %s to %s.\n\n", src, dest);
g = graph_reset_seen(g);
}
else
{
printf("There is no path from %s to %s.\n\n", src, dest);
g = graph_reset_seen(g);
}
printf("Enter origin and destination (quit to exit): ");
}
// Print exit message and kill the graph
printf("Normal exit.\n");
graph_kill(g);
return 0;
}

BIN
OU4/is_connected2 Normal file

Binary file not shown.

175
OU4/is_connected_backup.c Normal file
View File

@@ -0,0 +1,175 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h> // for EXIT_FAILURE
#include <graph.h>
#include <ctype.h>
#include <queue.h>
#include <dlist.h>
#define MAXNODENAME 40
#define BUFSIZE 400
// ===========HELP FUNCTIONS ============
/**
* @brief Find position of first non-whitespace character.
*
* @param s - string to search.
* @return int - Returns the position of the first non-whitespace character, or -1 if not found.
*/
int first_non_white_space(const char *s)
{
int i = 0; // Start at first char.
// Advance as long as we're loooking at white-space until we hit EOL.
while (s[i] && isspace(s[i])) {
i++;
}
// We found a non-whitespace char.
if (s[i]) {
// It was a proper characted. Return its position.
return i;
} else {
// It was the null terminator. Return fail.
return -1;
}
}
/**
* @brief Determine if the string is blank.
*
* @param s - string to search.
* @return true if the line contains only whitespace chars.
* @return false if the line contains at least one non-whitespace char.
*/
bool line_is_blank(const char *s)
{
// Line is blank if it only contained white-space chars.
return first_non_white_space(s) < 0;
}
/**
* @brief Determina if the string is a comment line.
*
* @param s - string to search.
* @return true if the line is a comment line.
* @return false if the line is not a comment line.
*
* A comment line has a hash sign '#' as the first non-whitespace char on the line.
*/
bool line_is_comment(const char *s)
{
int i = first_non_white_space(s);
return (i >= 0 && s[i] == '#');
}
/**
* @brief Extract node names from a line from the map file.
*
* @param buf - Input buffer.
* @param n1 - Output buffer for the first node name. Must be at least MAXNODENAME+1 long.
* @param n2 - Ditto for the second node name.
* @return int - Returns the number of correctly parsed node names. If the return value is 2, both n1
* and n2 contain node names. If the return value is less than 2, parsing of at least one node name
* failed, in which case the content of n1 and n2 are undefined.
*/
int parse_map_line(const char *buf, char *n1, char *n2)
{
// Create a format string the will do the work.
char fmt[20];
// This will generate the format string " %40s %40s" if MAXNODENAME is 40.
snprintf(fmt, sizeof(fmt), " %%%ds %%%ds", MAXNODENAME, MAXNODENAME);
// sscanf does all the necessary parsing.
// Node names must be separated by whitespace.
// Whitespace before the first node name is allowed.
// Anything after the second node name is ignored.
int n = sscanf(buf, fmt, n1, n2);
// The return value from sscanf contains the number of properly parsed format codes, i.e. the
// number of node names.
return n;
}
/**
* FUNCTION TO TRAVERSE THE GRAPH
* @g: pointer to the graph
* @src: pointer to source node
* @dest: pointer to destination node
*/
bool find_path(graph *g, node *src, node *dest)
{
//Mark the starting node as seen
g = graph_node_set_seen(g,src,true);
//Put it in an empty queue
queue *q = queue_enqueue(queue_empty(NULL),src);
while (!queue_is_empty(q))
{
//pick the first node from queue
src = queue_front(q);
q = queue_dequeue(q);
//if node equals destinatiom node, return true
if (nodes_are_equal(src,dest))
{
return true;
}
//get the neighbours
dlist *neighbours = graph_neighbours(g, src);
dlist_pos p = dlist_first(neighbours);
while (!dlist_is_end(neighbours,p))
{
if (!graph_node_is_seen(g,p))
{
//Mark unseen node as seen and put in queue
g = graph_node_set_seen(g,dlist_inspect(neighbours,p),true);
q = queue_enqueue(q,dlist_inspect(neighbours,p));
}
p = dlist_next(neighbours,p);
}
}
return false;
}
/**
* FUNCTION THAT MAKES A GRAPH FROM FILE
*
*/
graph *graph_from_file()
{
FILE *fptr = fopen("airmap1.map", "r");
graph *g;
if (fptr == NULL)
{
printf("Error reading the file\n");
exit(EXIT_FAILURE);
}
char string[100];
}
//MAIN
int main(void)
{
printf("Enter origin and destination (quit to exit): ");
return 0;
}

View File

@@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#define MAXNODENAME 40
#define BUFSIZE 400
/**
* @brief Find position of first non-whitespace character.
*
* @param s - string to search.
* @return int - Returns the position of the first non-whitespace character, or -1 if not found.
*/
int first_non_white_space(const char *s)
{
int i = 0; // Start at first char.
// Advance as long as we're loooking at white-space until we hit EOL.
while (s[i] && isspace(s[i])) {
i++;
}
// We found a non-whitespace char.
if (s[i]) {
// It was a proper characted. Return its position.
return i;
} else {
// It was the null terminator. Return fail.
return -1;
}
}
/**
* @brief Determine if the string is blank.
*
* @param s - string to search.
* @return true if the line contains only whitespace chars.
* @return false if the line contains at least one non-whitespace char.
*/
bool line_is_blank(const char *s)
{
// Line is blank if it only contained white-space chars.
return first_non_white_space(s) < 0;
}
/**
* @brief Determina if the string is a comment line.
*
* @param s - string to search.
* @return true if the line is a comment line.
* @return false if the line is not a comment line.
*
* A comment line has a hash sign '#' as the first non-whitespace char on the line.
*/
bool line_is_comment(const char *s)
{
int i = first_non_white_space(s);
return (i >= 0 && s[i] == '#');
}
/**
* @brief Extract node names from a line from the map file.
*
* @param buf - Input buffer.
* @param n1 - Output buffer for the first node name. Must be at least MAXNODENAME+1 long.
* @param n2 - Ditto for the second node name.
* @return int - Returns the number of correctly parsed node names. If the return value is 2, both n1
* and n2 contain node names. If the return value is less than 2, parsing of at least one node name
* failed, in which case the content of n1 and n2 are undefined.
*/
int parse_map_line(const char *buf, char *n1, char *n2)
{
// Create a format string the will do the work.
char fmt[20];
// This will generate the format string " %40s %40s" if MAXNODENAME is 40.
snprintf(fmt, sizeof(fmt), " %%%ds %%%ds", MAXNODENAME, MAXNODENAME);
// sscanf does all the necessary parsing.
// Node names must be separated by whitespace.
// Whitespace before the first node name is allowed.
// Anything after the second node name is ignored.
int n = sscanf(buf, fmt, n1, n2);
// The return value from sscanf contains the number of properly parsed format codes, i.e. the
// number of node names.
return n;
}

BIN
OU4/marctest Normal file

Binary file not shown.

95
OU4/marctest.c Normal file
View File

@@ -0,0 +1,95 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "graph.h"
// Helper function to print test results (Sonet Thinking Generated)
void test_result(const char *test_name, bool result) {
printf("%-40s %s\n", test_name, result ? "PASSED" : "FAILED");
}
/*void print_string(const void *s)
{
const char *string = s;
printf("[%s] ", string);
}
*/
int main(void)
{
printf("Testing graph implementation...\n\n");
int max_nodes = 10;
// Test 1: Create an empty graph
graph *g = graph_empty(max_nodes);
test_result("Create empty graph", g != NULL);
// Test 2: Check if graph is empty
test_result("Graph is empty", graph_is_empty(g));
// Test 3: Insert nodes
char *node1 = "AAA";
char *node2 = "BBB";
char *node3 = "CCC";
g = graph_insert_node(g, node1);
test_result("Insert node A", !graph_is_empty(g));
g = graph_insert_node(g, node2);
g = graph_insert_node(g, node3);
// Test 4: Find nodes
node *n1 = graph_find_node(g, node1);
test_result("Find node A", n1 != NULL);
node *n2 = graph_find_node(g, node2);
test_result("Find node B", n2 != NULL);
node *n3 = graph_find_node(g, node3);
test_result("Find node C", n3 != NULL);
node *n4 = graph_find_node(g, "D");
test_result("Find non-existent node D", n4 == NULL);
// Test 5: Insert edges
g = graph_insert_edge(g, n1, n2);
g = graph_insert_edge(g, n1, n3);
g = graph_insert_edge(g, n2, n1);
g = graph_insert_edge(g, n2, n2);
g = graph_insert_edge(g, n1, n1);
test_result("Graph has edges", graph_has_edges(g));
// Test 6: Node seen status
test_result("Node A not seen initially", !graph_node_is_seen(g, n1));
g = graph_node_set_seen(g, n1, true);
test_result("Node A is seen after setting", graph_node_is_seen(g, n1));
g = graph_node_set_seen(g, n2, true);
test_result("Node B is seen after setting", graph_node_is_seen(g, n2));
g = graph_reset_seen(g);
test_result("Node A not seen after reset", !graph_node_is_seen(g, n1));
test_result("Node B not seen after reset", !graph_node_is_seen(g, n2));
// Test 7: Neighbors (if implemented)
/*
dlist *neighbours = graph_neighbours(g, n1);
if (neighbours != NULL) {
printf("Neighbors of A: ");
// Print neighbors
//dlist_print(neighbours, print_string);
printf("\n\n");
dlist_kill(neighbours);
}*/
// Test 8: Print the graph
graph_print(g);
// Test 9: Clean up (if implemented)
graph_kill(g);
printf("Graph destroyed\n");
printf("\nTests completed.\n");
return 0;
}

BIN
OU4/marctest2 Normal file

Binary file not shown.

131
OU4/queue.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef __QUEUE_H
#define __QUEUE_H
#include <stdbool.h>
#include "util.h"
/*
* Declaration of a generic queue for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The queue stores void pointers, so it can be used to
* store all types of values. After use, the function queue_kill must
* be called to de-allocate the dynamic memory used by the queue
* itself. The de-allocation of any dynamic memory allocated for the
* element values is the responsibility of the user of the queue,
* unless a kill_function is registered in queue_empty.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2024-05-10: Added/updated print_internal to enhance encapsulation.
*/
// ==========PUBLIC DATA TYPES============
// Queue type.
typedef struct queue queue;
// ==========DATA STRUCTURE INTERFACE==========
/**
* queue_empty() - Create an empty queue.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new queue.
*/
queue *queue_empty(kill_function kill_func);
/**
* queue_is_empty() - Check if a queue is empty.
* @q: Queue to check.
*
* Returns: True if queue is empty, otherwise false.
*/
bool queue_is_empty(const queue *q);
/**
* queue_enqueue() - Put a value at the end of the queue.
* @q: Queue to manipulate.
* @v: Value (pointer) to be put in the queue.
*
* Returns: The modified queue.
*/
queue *queue_enqueue(queue *q, void *v);
/**
* queue_dequeue() - Remove the element at the front of a queue.
* @q: Queue to manipulate.
*
* NOTE: Undefined for an empty queue.
*
* Returns: The modified queue.
*/
queue *queue_dequeue(queue *q);
/**
* queue_front() - Inspect the value at the front of the queue.
* @q: Queue to inspect.
*
* Returns: The value at the top of the queue.
* NOTE: The return value is undefined for an empty queue.
*/
void *queue_front(const queue *q);
/**
* queue_kill() - Destroy a given queue.
* @q: Queue to destroy.
*
* Return all dynamic memory used by the queue and its elements. If a
* kill_func was registered at queue creation, also calls it for each
* element to kill any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void queue_kill(queue *q);
/**
* queue_print() - Iterate over the queue elements and print their values.
* @q: Queue to inspect.
* @print_func: Function called for each element.
*
* Iterates over the queue and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void queue_print(const queue *q, inspect_callback print_func);
/**
* queue_print_internal() - Print the internal structure of the queue in dot format.
* @q: Queue to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the queue, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the queue and outputs dot code that shows the internal
* structure of the queue. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <queue_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <queue_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void queue_print_internal(const queue *q, inspect_callback print_func, const char *desc,
int indent_level);
#endif

BIN
OU4/rapport_ou4.pdf Normal file

Binary file not shown.

13
OU4/src/Makefile Normal file
View File

@@ -0,0 +1,13 @@
# List of directories containing sub-projects
SUB_DIRS := array_1d array_2d dlist int_array_1d int_list int_list_array int_stack list int_queue queue stack table
# Rule to call 'make all' in each sub-directory
all:
for dir in $(SUB_DIRS); do \
$(MAKE) -C $$dir all; \
done
clean:
for dir in $(SUB_DIRS); do \
$(MAKE) -C $$dir clean; \
done

49
OU4/src/array_1d/Makefile Normal file
View File

@@ -0,0 +1,49 @@
MWE = array_1d_mwe1 array_1d_mwe2 array_1d_mwe3 array_1d_mwe4 array_1d_mwe1i array_1d_mwe2i
SRC = array_1d.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
array_1d_mwe1: array_1d_mwe1.c array_1d.c
gcc -o $@ $(CFLAGS) $^
array_1d_mwe2: array_1d_mwe2.c array_1d.c
gcc -o $@ $(CFLAGS) $^
array_1d_mwe3: array_1d_mwe3.c array_1d.c
gcc -o $@ $(CFLAGS) $^
array_1d_mwe4: array_1d_mwe4.c array_1d.c
gcc -o $@ $(CFLAGS) $^
array_1d_mwe1i: array_1d_mwe1i.c array_1d.c
gcc -o $@ $(CFLAGS) $^
array_1d_mwe2i: array_1d_mwe2i.c array_1d.c
gcc -o $@ $(CFLAGS) $^
memtest1: array_1d_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest2: array_1d_mwe2
valgrind --leak-check=full --show-reachable=yes ./$<
memtest3: array_1d_mwe3
valgrind --leak-check=full --show-reachable=yes ./$<
memtest4: array_1d_mwe4
valgrind --leak-check=full --show-reachable=yes ./$<

491
OU4/src/array_1d/array_1d.c Normal file
View File

@@ -0,0 +1,491 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <array_1d.h>
/*
* Implementation of a generic 1D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.5 2024-03-13: Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.0 2024-05-10: Added print_internal.
*/
// =========== INTERNAL DATA TYPES ============
struct array_1d {
int low; // Low index limit.
int high; // High index limit.
int array_size; // Number of array elements.
void **values; // Pointer to where the actual values are stored.
kill_function kill_func;
};
// =========== INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* array_1d_create() - Create an array without values.
* @lo: low index limit.
* @hi: high index limit.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
array_1d *array_1d_create(int lo, int hi, kill_function kill_func)
{
// Allocate array structure.
array_1d *a = calloc(1, sizeof(*a));
// Store index limit.
a->low = lo;
a->high = hi;
// Number of elements.
a->array_size = hi - lo + 1;
// Store kill function.
a->kill_func = kill_func;
a->values = calloc(a->array_size, sizeof(void *));
// Check whether the allocation succeeded.
if (a->values == NULL) {
free(a);
a = NULL;
}
return a;
}
/**
* array_1d_low() - Return the low index limit for the array.
* @a: array to inspect.
*
* Returns: The low index limit.
*/
int array_1d_low(const array_1d *a)
{
return a->low;
}
/**
* array_1d_high() - Return the high index limit for the array.
* @a: array to inspect.
*
* Returns: The high index limit.
*/
int array_1d_high(const array_1d *a)
{
return a->high;
}
/**
* array_1d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: The element value at the specified position. The result is
* undefined if no value are stored at that position.
*/
void *array_1d_inspect_value(const array_1d *a, int i)
{
int offset = i - array_1d_low(a);
// Return the value.
return a->values[offset];
}
/**
* array_1d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool array_1d_has_value(const array_1d *a, int i)
{
int offset = i - array_1d_low(a);
// Return true if the value is not NULL.
return a->values[offset] != NULL;
}
/**
* array_1d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or NULL to clear value.
* @i: index of position to modify.
*
* If the old element value is non-NULL, calls kill_func if it was
* specified at array creation.
*
* Returns: Nothing.
*/
void array_1d_set_value(array_1d *a, void *v, int i)
{
int offset = i - array_1d_low(a);
// Call kill_func if specified and old element value was non-NULL.
if (a->kill_func != NULL && a->values[offset] != NULL) {
a->kill_func( a->values[offset] );
}
// Set value.
a->values[offset] = v;
}
/**
* array_1d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Iterates over all elements. If kill_func was specified at array
* creation, calls it for every non-NULL element value.
*
* Returns: Nothing.
*/
void array_1d_kill(array_1d *a)
{
if (a->kill_func != NULL) {
// Return user-allocated memory for each non-NULL element.
for (int i = 0; i < a->array_size; i++) {
if (a->values[i] != NULL) {
a->kill_func(a->values[i]);
}
}
}
// Return memory for value pointers.
free(a->values);
// Return memory for array structure.
free(a);
}
/**
* array_1d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
* @print_func: Function called for each non-NULL element.
*
* Iterates over each position in the array. Calls print_func for each
* non-NULL value.
*
* Returns: Nothing.
*/
void array_1d_print(const array_1d *a, inspect_callback print_func)
{
printf("[ ");
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
if (array_1d_has_value(a, i)) {
printf("[");
print_func(array_1d_inspect_value(a, i));
printf("]");
} else {
printf(" []");
}
if (i < array_1d_high(a)) {
printf(", ");
}
}
printf(" ]\n");
}
// ===========INTERNAL FUNCTIONS USED BY array_1d_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the array head struct.
* @indent_level: Indentation level.
* @a: Array to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const array_1d *a)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"kill\\n%04lx|low\\n%d|high\\n%d|array_size\\n%d|<v>values\\n%04lx\"]\n",
PTR2ADDR(a), PTR2ADDR(a->kill_func), a->low, a->high, a->array_size,
PTR2ADDR(a->values));
}
void print_values(int indent_level, const array_1d *a)
{
iprintf(indent_level, "m%04lx [shape=record label=\"", PTR2ADDR(a->values));
for (int i=0; i < a->array_size; i++) {
printf("<%02d>%d\\n%02d\\n%04lx", i, i + a->low, i, PTR2ADDR(a->values[i]));
if (i < a->array_size - 1) {
printf("|");
}
}
printf("\"]\n");
}
// Print edge from the array head to the values array.
static void print_head_edge(int indent_level, const array_1d *a)
{
iprintf(indent_level, "m%04lx:v -> ", PTR2ADDR(a));
if (a->values == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(a->values));
}
printf(" [label=\"values\"]\n");
}
// Print nodes for each value memory block
static void print_value_nodes(int indent_level, const array_1d *a, inspect_callback print_func)
{
for (int i=0; i <= a->array_size; i++) {
if (a->values[i] != NULL) {
iprintf(indent_level, "m%04lx [label=\"", PTR2ADDR(a->values[i]));
if (print_func != NULL) {
print_func(a->values[i]);
}
printf("\" xlabel=\"%04lx\"]\n", PTR2ADDR(a->values[i]));
}
}
}
// Print edges from each value pointer to payload memory
static void print_value_edges(int indent_level, const array_1d *a)
{
for (int i=0; i < a->array_size; i++) {
// Buffer to store port name in. Good for array up to 1e9 elements.
char port[15];
// Create port name
sprintf(port, "%02d", i);
if (a->kill_func) {
print_edge(indent_level, a->values, a->values[i], port, port,
"color=red");
} else {
print_edge(indent_level, a->values, a->values[i], port, port,
"color=red style=dashed");
}
}
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* array_1d_print_internal() - Print the internal structure of the array in dot format.
* @a: Array to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void array_1d_print_internal(const array_1d *a, inspect_callback print_func, const char *desc,
int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph ARRAY_1D_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
iprintf(il, "subgraph cluster_nullspace {\n");
iprintf(il+1, "NULL\n");
iprintf(il, "}\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "cluster_array_1d_%d_description [label=\"%s\"]\n", graph_number,
escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "a [label=\"%04lx\" xlabel=\"a\"]\n", PTR2ADDR(a));
iprintf(il, "a -> m%04lx\n", PTR2ADDR(a));
}
// Print the subgraph to surround the Array content
iprintf(il, "subgraph cluster_array_1d_%d { label=\"Array_1d\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, a);
// Output the values array
print_values(il, a);
// Close the subgraph
il--;
iprintf(il, "}\n");
if (indent_level == 0) {
// Put the user nodes in userspace
iprintf(il, "subgraph cluster_userspace { label=\"User space\"\n");
il++;
}
// Print nodes for each value memory block
print_value_nodes(il, a, print_func);
if (indent_level == 0) {
// Close userspace
il--;
iprintf(il, "}\n");
}
// Output the edges from the head
print_head_edge(il, a);
// Print edges from each value pointer to payload memory
print_value_edges(il, a);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,77 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 1 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into simpler, shorter versions.
* Removed use of automatic, magic, free_handler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-13: Added explicit create/kill functions.
* v1.31 2024-04-05: Bugfix: Remove call to array_1d_print_internal
* that shouldn't be here.
*/
#define VERSION "v1.31"
#define VERSION_DATE "2024-04-05"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer array without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create an array with 6 positions.
array_1d *a = array_1d_create(1, 6, NULL);
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a, v, i);
}
printf("Array after inserting i^2, i=1,...,6:\n");
array_1d_print(a, print_int);
// Empty the array.
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
if (array_1d_has_value(a, i)) {
int *v = array_1d_inspect_value(a, i);
int_kill(v);
}
}
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,146 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 1 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-05: Adapted from array_1d_mwe1.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-05"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(const array_1d *a, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
array_1d_print_internal(a, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create integer array without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create an array with 6 positions.
array_1d *a = array_1d_create(1, 6, NULL);
printf("Empty array from the outside:\n");
array_1d_print(a, print_int);
print_internal_with_cut_lines(a, "Empty array showing the internal structure");
int i;
// Set values of 50% of the elements
for (i = array_1d_low(a); i <= array_1d_high(a)/2; i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a,v,i);
}
printf("Array from the outside after setting half the values:\n");
array_1d_print(a, print_int);
const char *long_desc = __FILE__
": Internal structure of the Array after setting 3 values.\n"
"Red lines are used for the array payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the array, i.e., the payload\n"
"memory will NOT be deallocated by the array.\n\n"
"See array_1d_mwe2i for an array example\nthat owns the payload memory.";
print_internal_with_cut_lines(a, long_desc);
// Set the rest of the element values.
// Note: The empty initialization is on purpose.
for ( ; i <= array_1d_high(a) ; i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a,v,i);
}
printf("Array from the outside after setting all the values:\n");
array_1d_print(a, print_int);
const char *long_desc2 = __FILE__
": Internal structure of the Array after setting all 6 values.\n"
"Red lines are used for the array payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the array, i.e., the payload\n"
"memory will NOT be deallocated by the array.\n\n"
"See array_1d_mwe2i for an array example\nthat owns the payload memory.";
print_internal_with_cut_lines(a, long_desc2);
// Empty the array.
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
if (array_1d_has_value(a, i)) {
int *v=array_1d_inspect_value(a,i);
int_kill(v);
}
}
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,67 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 2 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into simpler, shorter versions.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-13: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-13"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer array with kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create an array with 6 positions.
array_1d *a = array_1d_create(1, 6, int_kill);
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a, v, i);
}
printf("Array after inserting i^2, i=1,...,6:\n");
array_1d_print(a, print_int);
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,140 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 1 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-05: Adapted from array_1d_mwe1i.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-05"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(const array_1d *a, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
array_1d_print_internal(a, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create integer array with kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create an array with 6 positions.
array_1d *a = array_1d_create(1, 6, int_kill);
printf("Empty array from the outside:\n");
array_1d_print(a, print_int);
print_internal_with_cut_lines(a, "Empty array showing the internal structure");
int i;
// Set values of 50% of the elements
for (i = array_1d_low(a); i <= array_1d_high(a)/2; i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a,v,i);
}
printf("Array from the outside after setting half the values:\n");
array_1d_print(a, print_int);
const char *long_desc = __FILE__
": Internal structure of the Array after setting 3 values.\n"
"Red lines are used for the array payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the array, i.e., the payload\n"
"memory WILL be deallocated by the array.\n\n"
"See array_1d_mwe1i for an array example\nthat borrows the payload memory.";
print_internal_with_cut_lines(a, long_desc);
// Set the rest of the element values.
// Note: The empty initialization is on purpose.
for ( ; i <= array_1d_high(a) ; i++) {
// Allocate memory for an integer.
int *v=int_create(i * i);
array_1d_set_value(a,v,i);
}
printf("Array from the outside after setting all the values:\n");
array_1d_print(a, print_int);
const char *long_desc2 = __FILE__
": Internal structure of the Array after setting all 6 values.\n"
"Red lines are used for the array payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the array, i.e., the payload\n"
"memory WILL be deallocated by the array.\n\n"
"See array_1d_mwe1i for an array example\nthat borrows the payload memory.";
print_internal_with_cut_lines(a, long_desc2);
// Clean up the array.
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,99 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 3 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into simpler, shorter versions.
* Removed use of automatic, magic, free_handler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-13"
// Struct with month name and number of days.
typedef struct month {
char *name;
int days;
} month;
// Months are stored via void pointers. Convert the given pointer and
// print the dereferenced values.
void print_month(const void *data)
{
// Convert void pointer to pointer to month.
const month *m=data;
printf("(%s, %d)", m->name, m->days);
}
// Allocate space for and populate a month structure
month *month_create(const char *name, int days)
{
// Allocate memory for a month structure.
month *m = malloc(sizeof(*m));
// Allocate memory for the month name.
m->name = calloc(strlen(name) + 1, sizeof(char));
// Copy the string.
strcpy(m->name, name);
// Set days.
m->days = days;
return m;
}
// Function to free both month structure and char * with name.
void month_kill(void *data)
{
// Convert void pointer to pointer to month.
month *m=data;
free(m->name);
free(m);
}
int main(void)
{
printf("%s, %s %s: Create month array without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
const char *month_names[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
int month_days[12] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
// Create an array with 12 positions.
array_1d *a = array_1d_create(1, 12, NULL);
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
// Allocate and populate a month structure.
month *m=month_create(month_names[i - 1], month_days[i - 1]);
// Set value in array.
array_1d_set_value(a,m,i);
}
printf("Array after inserting 12 month structures (Jan, 31), ..., (Dec, 31):\n");
array_1d_print(a, print_month);
// Empty the array.
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
if (array_1d_has_value(a,i)) {
month *v=array_1d_inspect_value(a,i);
month_kill(v);
}
}
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,91 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_1d.h>
/*
* Minimum working example 4 for array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into simpler, shorter versions.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-13"
// Struct with month name and number of days.
typedef struct month {
char *name;
int days;
} month;
// Months are stored via void pointers. Convert the given pointer and
// print the dereferenced values.
void print_month(const void *data)
{
// Convert void pointer to pointer to month.
const month *m=data;
printf("(%s, %d)", m->name, m->days);
}
// Allocate space for and populate a month structure
month *month_create(const char *name, int days)
{
// Allocate memory for a month structure.
month *m = malloc(sizeof(*m));
// Allocate memory for the month name.
m->name = calloc(strlen(name) + 1, sizeof(char));
// Copy the string.
strcpy(m->name, name);
// Set days.
m->days = days;
return m;
}
// Function to free both month structure and char * with name.
void month_kill(void *data)
{
// Convert void pointer to pointer to month.
month *m=data;
free(m->name);
free(m);
}
int main(void)
{
printf("%s, %s %s: Create month array with kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
const char *month_names[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
int month_days[12] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
// Create an array with 12 positions.
array_1d *a = array_1d_create(1, 12, month_kill);
for (int i=array_1d_low(a); i<=array_1d_high(a); i++) {
// Allocate and populate a month structure.
month *m=month_create(month_names[i - 1], month_days[i - 1]);
// Set value in array.
array_1d_set_value(a,m,i);
}
printf("Array after inserting 12 month structures (Jan, 31), ..., (Dec, 31):\n");
array_1d_print(a, print_month);
array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

37
OU4/src/array_2d/Makefile Normal file
View File

@@ -0,0 +1,37 @@
MWE = array_2d_mwe1 array_2d_mwe2 array_2d_mwe1i array_2d_mwe2i
SRC = array_2d.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
array_2d_mwe1: array_2d_mwe1.c array_2d.c
gcc -o $@ $(CFLAGS) $^
array_2d_mwe2: array_2d_mwe2.c array_2d.c
gcc -o $@ $(CFLAGS) $^
array_2d_mwe1i: array_2d_mwe1i.c array_2d.c
gcc -o $@ $(CFLAGS) $^
array_2d_mwe2i: array_2d_mwe2i.c array_2d.c
gcc -o $@ $(CFLAGS) $^
memtest1: array_2d_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest2: array_2d_mwe2
valgrind --leak-check=full --show-reachable=yes ./$<

526
OU4/src/array_2d/array_2d.c Normal file
View File

@@ -0,0 +1,526 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <array_2d.h>
/*
* Implementation of a generic 2D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Moved freehandler to last in create parameter list.
* v1.2 2024-05-10: Added print_internal.
* v1.21 2024-05-15: Bugfix to get rid of sprintf warning.
*/
// ===========INTERNAL DATA TYPES ============
struct array_2d {
int low[2]; // Low index limits.
int high[2]; // High index limits.
int array_size; // Number of array elements.
void **values; // Pointer to where the actual values are stored.
kill_function kill_func;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* array_2d_create() - Create an array without values.
* @lo1: low index limit for first dimension.
* @hi1: high index limit for first dimension.
* @lo2: low index limit for second dimension.
* @hi2: high index limit for second dimension.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
array_2d *array_2d_create(int lo1, int hi1, int lo2, int hi2,
kill_function kill_func)
{
// Allocate array structure.
array_2d *a = calloc(1, sizeof(*a));
// Store index limit.
a->low[0] = lo1;
a->low[1] = lo2;
a->high[0] = hi1;
a->high[1] = hi2;
// Number of elements.
a->array_size = (hi1 - lo1 + 1) * (hi2 - lo2 + 1);
// Store kill function.
a->kill_func = kill_func;
a->values=calloc(a->array_size, sizeof(void *));
// Check whether the allocation succeeded.
if (a->values == NULL) {
free(a);
a = NULL;
}
return a;
}
/**
* array_2d_low() - Return the low index limit for the array.
* @a: array to inspect.
* @d: dimension number, 1 or 2.
*
* Returns: The low index limit for dimension number d.
*/
int array_2d_low(const array_2d *a, int d)
{
return a->low[d - 1];
}
/**
* array_2d_high() - Return the high index limit for the array.
* @a: array to inspect.
* @d: dimension number, 1 or 2.
*
* Returns: The high index limit for dimension number d.
*/
int array_2d_high(const array_2d *a, int d)
{
return a->high[d - 1];
}
/**
* array_2d_linear_index() - Internal function to compute linear index from list
* of indices.
* @a: array to inspect.
* @i: First index.
* @j: Second index.
*
* Returns: The linear index corresponding to the list of indices.
* NOTE: The result is undefined if the number of arguments
* or index value are out of bounds.
*/
static int array_2d_linear_index(const array_2d *a, int i, int j)
{
int rows = a->high[0] - a->low[0] + 1;
int ix=(i - a->low[0]) + (j - a->low[1]) * rows;
return ix;
}
/**
* array_2d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: First index of position to inspect.
* @j: Second index of position to inspect.
*
* Returns: The element value at the specified position. The result is
* undefined if no value are stored at that position.
*/
void *array_2d_inspect_value(const array_2d *a, int i, int j)
{
int ix = array_2d_linear_index(a, i, j);
// Return the value.
return a->values[ix];
}
/**
* array_2d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: First index of position to inspect.
* @j: Second index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool array_2d_has_value(const array_2d *a, int i, int j)
{
int ix = array_2d_linear_index(a, i, j);
// Return true if the value is not NULL.
return a->values[ix] != NULL;
}
/**
* array_2d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or NULL to clear value.
* @i: First index of position to modify.
* @j: Second index of position to modify.
*
* If the old element value is non-NULL, calls kill_func if it was
* specified at array creation.
*
* Returns: Nothing.
*/
void array_2d_set_value(array_2d *a, void *v, int i, int j)
{
int ix = array_2d_linear_index(a, i, j);
// Call kill_func if specified and old element value was non-NULL.
if (a->kill_func != NULL && a->values[ix] != NULL) {
a->kill_func(a->values[ix]);
}
// Set value.
a->values[ix]=v;
}
/**
* array_2d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Iterates over all elements. If kill_func was specified at array
* creation, calls it for every non-NULL element value.
*
* Returns: Nothing.
*/
void array_2d_kill(array_2d *a)
{
if (a->kill_func) {
// Return user-allocated memory for each non-NULL element.
for (int i=0; i<a->array_size; i++) {
if (a->values[i] != NULL) {
a->kill_func(a->values[i]);
}
}
}
// Free actual storage.
free(a->values);
// Free array structure.
free(a);
}
/**
* array_2d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
* @print_func: Function called for each non-NULL element.
*
* Iterates over each position in the array. Calls print_func for each
* non-NULL value.
*
* Returns: Nothing.
*/
void array_2d_print(const array_2d *a, inspect_callback print_func)
{
printf("[\n");
for (int i=array_2d_low(a,1); i<=array_2d_high(a,1); i++) {
printf(" [ ");
for (int j=array_2d_low(a,2); j<=array_2d_high(a,2); j++) {
if (array_2d_has_value(a,i,j)) {
printf("[");
print_func(array_2d_inspect_value(a,i,j));
printf("]");
} else {
printf("[ ]");
}
if (j<array_2d_high(a,2)) {
printf(", ");
}
}
printf(" ]\n");
}
printf(" ]\n");
}
// ===========INTERNAL FUNCTIONS USED BY array_1d_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the array head struct.
* @indent_level: Indentation level.
* @a: Array to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const array_2d *p)
{
iprintf(indent_level, "m%04lx [shape=record label=\"func\\n%04lx|low[0]\\n%d|high[0]\\n%d"
"|low[1]\\n%d|high[1]\\n%d|array_size\\n%d|<v>values\\n%04lx\"]\n",
PTR2ADDR(p), PTR2ADDR(p->kill_func), p->low[0], p->high[0],
p->low[1], p->high[1], p->array_size, PTR2ADDR(p->values));
}
static void print_values(int indent_level, const array_2d *a)
{
iprintf(indent_level, "m%04lx [shape=record label=\"", PTR2ADDR(a->values));
for (int j=array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
for (int i=array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
int li=array_2d_linear_index(a, i, j);
printf("<%02d>(%d,%d)\\n%02d\\n%04lx",
li, i, j, li, PTR2ADDR(a->values[li]));
if (li < a->array_size - 1) {
printf("|");
}
}
}
printf("\"]\n");
}
// Print edge from the array head to the values array.
static void print_head_edge(int indent_level, const array_2d *a)
{
iprintf(indent_level, "m%04lx:v -> ", PTR2ADDR(a));
if (a->values == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(a->values));
}
printf(" [label=\"values\"]\n");
}
// Print nodes for each value memory block
static void print_value_nodes(int indent_level, const array_2d *a, inspect_callback print_func)
{
for (int i=0; i <= a->array_size; i++) {
if (a->values[i] != NULL) {
iprintf(indent_level, "m%04lx [label=\"", PTR2ADDR(a->values[i]));
if (print_func != NULL) {
print_func(a->values[i]);
}
printf("\" xlabel=\"%04lx\"]\n", PTR2ADDR(a->values[i]));
}
}
}
// Print edges from each value pointer to payload memory
static void print_value_edges(int indent_level, const array_2d *a)
{
for (int i=0; i < a->array_size; i++) {
// Buffer to store port name in. Good for array up to 1e9 elements.
char port[15];
// Create port name
sprintf(port, "%02d", i);
if (a->kill_func) {
print_edge(indent_level, a->values, a->values[i], port, port,
"color=red");
} else {
print_edge(indent_level, a->values, a->values[i], port, port,
"color=red style=dashed");
}
}
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* array_2d_print_internal() - Print the arrays internal structure.
* @a: Array to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void array_2d_print_internal(const array_2d *a, inspect_callback print_func, const char *desc,
int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph ARRAY_2D_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
iprintf(il, "subgraph cluster_nullspace {\n");
iprintf(il+1, "NULL\n");
iprintf(il, "}\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_array_2d_%d_description [label=\"%s\"]\n", graph_number,
escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "a [label=\"%04lx\" xlabel=\"a\"]\n", PTR2ADDR(a));
iprintf(il, "a -> m%04lx\n", PTR2ADDR(a));
}
// Print the subgraph to surround the Array content
iprintf(il, "subgraph cluster_array_1d_%d { label=\"Array_1d\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, a);
// Output the values array
print_values(il, a);
// Close the subgraph
il--;
iprintf(il, "}\n");
if (indent_level == 0) {
// Put the user nodes in userspace
iprintf(il, "subgraph cluster_userspace { label=\"User space\"\n");
il++;
}
// Print nodes for each value memory block
print_value_nodes(il, a, print_func);
if (indent_level == 0) {
// Close userspace
il--;
iprintf(il, "}\n");
}
// Output the edges from the head
print_head_edge(il, a);
// Print edges from each value pointer to payload memory
print_value_edges(il, a);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,77 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_2d.h>
/*
* Minimum working example for array_2d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
*/
#define VERSION "v1.2"
#define VERSION_DATE "2023-01-14"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create 4-by-3 array of integers without kill function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create a 4-by-3 array.
array_2d *a = array_2d_create(1, 4, 1, 3, NULL);
for (int i = array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("After filling the array with values:\n");
array_2d_print(a, print_int);
// Empty the array.
for (int i = array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
if (array_2d_has_value(a, i, j)) {
int *v=array_2d_inspect_value(a, i, j);
int_kill(v);
}
}
}
// Return remaining memory.
array_2d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,152 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_2d.h>
/*
* Minimum working example for array_2d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-07: Adapted from array_2d_mwe1.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-07"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v;
free(p);
}
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(const array_2d *a, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
array_2d_print_internal(a, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create 4-by-3 array of integers without kill function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create a 4-by-3 array.
array_2d *a = array_2d_create(1, 4, 1, 3, NULL);
printf("Empty array from the outside:\n");
array_2d_print(a, print_int);
print_internal_with_cut_lines(a, "Empty array showing the internal structure");
int i;
// Set values of 50% of the elements
for (i = array_2d_low(a, 1); i <= array_2d_high(a, 1)/2; i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("Array from the outside after setting half the values:\n");
array_2d_print(a, print_int);
const char *long_desc = __FILE__
": Internal structure of the Array after setting half of the values.\n"
"Red lines are used for the array payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the array, i.e., the payload\n"
"memory will NOT be deallocated by the array.\n\n"
"See array_2d_mwe2i for an array example\nthat owns the payload memory.";
print_internal_with_cut_lines(a, long_desc);
// Set the rest of the element values.
// Note: The empty initialization is on purpose.
for ( ; i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("Array from the outside after setting all the values:\n");
array_2d_print(a, print_int);
const char *long_desc2 = __FILE__
": Internal structure of the Array after setting all the values.\n"
"Red lines are used for the array payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the array, i.e., the payload\n"
"memory will NOT be deallocated by the array.\n\n"
"See array_2d_mwe2i for an array example\nthat owns the payload memory.";
print_internal_with_cut_lines(a, long_desc2);
// Empty the array.
for (int i = array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
if (array_2d_has_value(a, i, j)) {
int *v=array_2d_inspect_value(a, i, j);
int_kill(v);
}
}
}
// Return remaining memory.
array_2d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,68 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_2d.h>
/*
* Minimum working example for array_2d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
*/
#define VERSION "v1.2"
#define VERSION_DATE "2023-01-14"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create 4-by-3 array of integers with kill function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create a 4-by-3 array.
array_2d *a = array_2d_create(1, 4, 1, 3, int_kill);
for (int i = array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("After filling the array with values:\n");
array_2d_print(a, print_int);
// Return remaining memory.
array_2d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,152 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <array_2d.h>
/*
* Minimum working example for array_2d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-07: Adapted from array_2d_mwe1i.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-07"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(const array_2d *a, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
array_2d_print_internal(a, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create 4-by-3 array of integers with kill function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create a 4-by-3 array.
array_2d *a = array_2d_create(1, 4, 1, 3, int_kill);
printf("Empty array from the outside:\n");
array_2d_print(a, print_int);
print_internal_with_cut_lines(a, "Empty array showing the internal structure");
int i;
// Set values of 50% of the elements
for (i = array_2d_low(a, 1); i <= array_2d_high(a, 1)/2; i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("Array from the outside after setting half the values:\n");
array_2d_print(a, print_int);
const char *long_desc = __FILE__
": Internal structure of the Array after setting half of the values.\n"
"Red lines are used for the array payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the array, i.e., the payload\n"
"memory WILL be deallocated by the array.\n\n"
"See array_2d_mwe1i for an array example\nthat borrows the payload memory.";
print_internal_with_cut_lines(a, long_desc);
// Set the rest of the element values.
// Note: The empty initialization is on purpose.
for ( ; i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
// Allocate memory for an integer.
int *v=int_create(i * 10 + j);
array_2d_set_value(a, v, i, j);
}
}
printf("Array from the outside after setting all the values:\n");
array_2d_print(a, print_int);
const char *long_desc2 = __FILE__
": Internal structure of the Array after setting all the values.\n"
"Red lines are used for the array payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the array, i.e., the payload\n"
"memory WILL be deallocated by the array.\n\n"
"See array_2d_mwe1i for an array example\nthat borrows the payload memory.";
print_internal_with_cut_lines(a, long_desc2);
// Empty the array.
for (int i = array_2d_low(a, 1); i <= array_2d_high(a, 1); i++) {
for (int j = array_2d_low(a, 2); j <= array_2d_high(a, 2); j++) {
if (array_2d_has_value(a, i, j)) {
int *v=array_2d_inspect_value(a, i, j);
int_kill(v);
}
}
}
// Return remaining memory.
array_2d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

42
OU4/src/dlist/Makefile Normal file
View File

@@ -0,0 +1,42 @@
MWE = dlist_mwe1 dlist_mwe2 dlist_mwe1i dlist_mwe2i
SRC = dlist.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
clean:
-rm -f $(MWE) $(OBJ)
dlist_mwe1: dlist_mwe1.c dlist.c
gcc -o $@ $(CFLAGS) $^
dlist_mwe2: dlist_mwe2.c dlist.c
gcc -o $@ $(CFLAGS) $^
dlist_mwe1i: dlist_mwe1i.c dlist.c
gcc -o $@ $(CFLAGS) $^
dlist_mwe2i: dlist_mwe2i.c dlist.c
gcc -o $@ $(CFLAGS) $^
memtest1: dlist_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest2: dlist_mwe2
valgrind --leak-check=full --show-reachable=yes ./$<
memtest3: dlist_mwe1i
valgrind --leak-check=full --show-reachable=yes ./$<
memtest4: dlist_mwe2i
valgrind --leak-check=full --show-reachable=yes ./$<

9
OU4/src/dlist/README.md Normal file
View File

@@ -0,0 +1,9 @@
# Riktad lista
En implementation av ADTn _Riktad Lista_ baserad på en enkel-länkad lista.
## Minneshantering och utskrift
Det mesta av hur gränsytan används med avseende på minneshantering och
utskrifter är analogt för hur [listimplementationen](../list/) fungerar.

588
OU4/src/dlist/dlist.c Normal file
View File

@@ -0,0 +1,588 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dlist.h>
/*
* Implementation of a generic, undirected list for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added dlist_pos_are_equal and dlist_pos_is_valid functions.
* v1.2 2023-03-23: Renamed dlist_pos_are_equal to dlist_pos_is_equal.
* v1.3 2023-03-23: Renamed dlist_pos_are_equal to dlist_pos_is_equal.
* v2.0 2024-03-14: Added dlist_print_internal to output dot code for visualization.
* Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.1 2024-05-10: Updated print_internal with improved encapsulation.
*/
// ===========INTERNAL DATA TYPES============
/*
* The list elements are implemented as one-cells with a forward link.
* The list position is a pointer to the internal cell before the cell
* with the value.
*/
typedef struct cell {
struct cell *next;
void *val;
} cell;
struct dlist {
cell *head;
kill_function kill_func;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS============
/**
* dlist_empty() - Create an empty dlist.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new list.
*/
dlist *dlist_empty(kill_function kill_func)
{
// Allocate memory for the list structure.
dlist *l = calloc(1, sizeof(*l));
// Allocate memory for the list head.
l->head = calloc(1, sizeof(cell));
// No elements in list so far.
l->head->next = NULL;
// Store the kill function.
l->kill_func = kill_func;
return l;
}
/**
* dlist_is_empty() - Check if a dlist is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool dlist_is_empty(const dlist *l)
{
return (l->head->next == NULL);
}
/**
* dlist_first() - Return the first position of a dlist, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
dlist_pos dlist_first(const dlist *l)
{
return l->head;
}
/**
* dlist_next() - Return the next position in a dlist.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
dlist_pos dlist_next(const dlist *l, const dlist_pos p)
{
if (dlist_is_end(l, p)) {
// This should really throw an error.
fprintf(stderr,"dlist_next: Warning: Trying to navigate "
"past end of list!");
}
return p->next;
}
/**
* dlist_is_end() - Check if a given position is at the end of a dlist.
* @l: List to inspect.
* @p: Any valid position in the list.
*
* Returns: True if p is at the end of the list.
*/
bool dlist_is_end(const dlist *l, const dlist_pos p)
{
return p->next == NULL;
}
/**
* dlist_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: Returns the value at the given position as a void pointer.
* NOTE: The return value is undefined for the last position.
*/
void *dlist_inspect(const dlist *l, const dlist_pos p)
{
if (dlist_is_end(l, p)) {
// This should really throw an error.
fprintf(stderr,"dlist_inspect: Warning: Trying to inspect "
"position at end of list!\n");
}
return p->next->val;
}
/**
* dlist_insert() - Insert a new element with a given value into a dlist.
* @l: List to manipulate.
* @v: Value (pointer) to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
dlist_pos dlist_insert(dlist *l, void *v, const dlist_pos p)
{
// Create new element.
dlist_pos new_pos=calloc(1, sizeof(cell));
// Set value.
new_pos->val=v;
// Set links.
new_pos->next=p->next;
p->next=new_pos;
return p;
}
/**
* dlist_remove() - Remove an element from a dlist.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list. If a kill_func
* was registered at list creation, calls it to deallocate the memory
* held by the element value.
*
* Returns: The position after the removed element.
*/
dlist_pos dlist_remove(dlist *l, const dlist_pos p)
{
// Cell to remove.
dlist_pos c=p->next;
// Link past cell to remove.
p->next=c->next;
// Call kill_func if registered.
if(l->kill_func != NULL) {
// Return any user-allocated memory for the value.
l->kill_func(c->val);
}
// Free the memory allocated to the cell itself.
free(c);
// Return the position of the next element.
return p;
}
/**
* dlist_kill() - Destroy a given dlist.
* @l: List to destroy.
*
* Return all dynamic memory used by the list and its elements. If a
* kill_func was registered at list creation, also calls it for each
* element to return any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void dlist_kill(dlist *l)
{
// Use public functions to traverse the list.
// Start with the first element (will be defined even for an
// empty list).
dlist_pos p = dlist_first(l);
// Remove first element until list is empty.
while(!dlist_is_empty(l)) {
p = dlist_remove(l, p);
}
// Free the head and the list itself.
free(l->head);
free(l);
}
/**
* dlist_print() - Iterate over the list element and print their values.
* @l: List to inspect.
* @print_func: Function called for each element.
*
* Iterates over the list and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void dlist_print(const dlist *l, inspect_callback print_func)
{
// Start at the beginning of the list.
dlist_pos p = dlist_first(l);
printf("( ");
while (!dlist_is_end(l, p)) {
// Call print_func with the element value at the
// current position.
print_func(dlist_inspect(l, p));
// Advance to next position.
p = dlist_next(l, p);
// Print separator unless at element.
if (!dlist_is_end(l, p)) {
printf(", ");
}
}
printf(" )\n");
}
/**
* dlist_pos_is_equal() - Return true if two positions in a dlist are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
*/
bool dlist_pos_is_equal(const dlist *l, const dlist_pos p1, const dlist_pos p2)
{
// Since we don't need to check whether p1 or p2 are valid, we
// only need to compare them directly.
return p1 == p2;
}
/**
* dlist_pos_is_valid() - Return true for a valid position in a dlist.
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool dlist_pos_is_valid(const dlist *l, const dlist_pos p)
{
// Iterate over all positions in l.
dlist_pos q = dlist_first(l);
while (!dlist_is_end(l, q)) {
if (dlist_pos_is_equal(l, p, q)) {
// We found the position in the list.
return true;
}
// Advance to the next valid position,
q = dlist_next(l, q);
}
// p was not among valid positions in l.
return false;
}
// ===========INTERNAL FUNCTIONS USED BY dlist_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the dlist head struct.
* @indent_level: Indentation level.
* @l: List to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const dlist *l)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"kill\\n%04lx|<h>head\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(l), PTR2ADDR(l->kill_func), PTR2ADDR(l->head), PTR2ADDR(l));
}
// Print edges from the list head to the head cell.
static void print_head_edges(int indent_level, const dlist *l)
{
print_edge(indent_level, l, l->head, "h", "head", NULL);
}
// Print a node corresponding to the cell at position p.
static void print_elem_node(int indent_level, const dlist_pos p)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<v>val\\n%04lx|<n>next\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(p), PTR2ADDR(p->val), PTR2ADDR(p->next), PTR2ADDR(p));
}
// Print edges from the cell at position p to the next and previous
// cells and the value. The value pointer is red, the others are
// black. If the list owns the memory, the edge is solid, otherwise
// dashed.
static void print_elem_edges(int indent_level, const dlist *l, const dlist_pos p)
{
print_edge(indent_level, p, p->next, "n", "next", NULL);
// Ignore val ptr for head and tail nodes.
if (p == l->head) {
return;
}
if (l->kill_func) {
print_edge(indent_level, p, p->val, "v", "val", "color=red");
} else {
print_edge(indent_level, p, p->val, "v", "val", "color=red style=dashed");
}
}
// Print the node for the memory block at p using the user-supplied
// print_func to print the label.
static void print_value_node(int indent_level, const void *p, inspect_callback print_func)
{
iprintf(indent_level, "m%04lx [label=\"", PTR2ADDR(p));
if (print_func != NULL) {
print_func(p);
}
printf("\" xlabel=\"%04lx\"]\n", PTR2ADDR(p));
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* dlist_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void dlist_print_internal(const dlist *l, inspect_callback print_func, const char *desc,
int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph DLIST_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
iprintf(il, "subgraph cluster_nullspace {\n");
iprintf(il+1, "NULL\n");
iprintf(il, "}\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "cluster_dlist_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "l [label=\"%04lx\" xlabel=\"l\"]\n", PTR2ADDR(l));
iprintf(il, "l -> m%04lx\n", PTR2ADDR(l));
}
// Print the subgraph to surround the DList content
iprintf(il, "subgraph cluster_dlist_%d { label=\"DList\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, l);
// Output the element nodes
dlist_pos p = l->head;
while (p != NULL) {
print_elem_node(il, p);
p = p->next;
}
// Close the subgraph
il--;
iprintf(il, "}\n");
if (indent_level == 0) {
// Put the user nodes in userspace
iprintf(il, "subgraph cluster_userspace { label=\"User space\"\n");
il++;
}
// Output the value nodes
p = l->head;
while (p != NULL) {
if (p->val) {
print_value_node(il, p->val, print_func);
}
p = p->next;
}
if (indent_level == 0) {
// Close userspace
il--;
iprintf(il, "}\n");
}
// Output the edges from the head
print_head_edges(il, l);
// Output the edges from each element
p = l->head;
while (p != NULL) {
print_elem_edges(il, l, p);
p = p->next;
}
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,79 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlist.h>
/*
* Minimum working example 1 for dlist.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit copy/kill string functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-14"
// Make a dynamic copy of the input string.
char *copy_string(char *str)
{
char *copy = calloc(strlen(str) + 1, sizeof(char));
strcpy(copy, str);
return copy;
}
// String print function.
void print_string(const void *value)
{
const char *s=value;
printf("\"%s\"", s);
}
// Return the memory occupied by the string
void kill_string(void *v)
{
char *p = v; // Convert to a char ptr, useful in a debugger
free(p);
}
// Test program.
int main(void)
{
printf("%s, %s %s: Create list of strings without memfreehandler.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Names to insert in the list.
char *names[] = {"Alfons", "Bengt", "Cia", "David", "Florian", "Gunnar"};
// Create the list
dlist *l = dlist_empty(NULL);
dlist_pos p = dlist_first(l);
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
// Insert dynamic copies of strings at last position.
p = dlist_insert(l, copy_string(names[i]), p);
p = dlist_next(l, p);
}
// Print the list.
printf("DList after inserting 6 strings:\n");
dlist_print(l, print_string);
// Traverse the list and deallocate each value.
p = dlist_first(l);
while (!dlist_is_end(l,p)) {
char *v=dlist_inspect(l,p);
kill_string(v);
p=dlist_remove(l,p);
}
// Destroy the list.
dlist_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

142
OU4/src/dlist/dlist_mwe1i.c Normal file
View File

@@ -0,0 +1,142 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlist.h>
/*
* Minimum working example for dlist.c that shows how the internal
* structure of a list can be visualized. In this version, the list
* "borrows" the payload memory, i.e., the user of the list is
* responsible for deallocating the payload memory. See dlist_mwe2i.c
* for a version where the list takes over the responsibility.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-03-14: First public version.
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2024-03-15"
// Make a dynamic copy of the input string.
char *copy_string(char *str)
{
char *copy = calloc(strlen(str) + 1, sizeof(char));
strcpy(copy, str);
return copy;
}
// Return the memory occupied by the string
void kill_string(void *v)
{
char *p = v; // Convert to a char ptr, useful in a debugger
free(p);
}
// String print function.
void print_string(const void *value)
{
const char *s=value;
printf("\"%s\"", s);
}
void print_string_internal(const void *value)
{
const char *s=value;
// We must double-escape the double quotes since the output will
// be parsed a second time by graphviz.
printf("\\\"%s\\\"", s);
}
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const dlist *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
dlist_print_internal(l, print_string_internal, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
// Test program.
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create list of strings without memfreehandler.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Names to insert in the list.
char *names[] = {"Alfons", "Bengt", "Cia", "David", "Florian", "Gunnar"};
// Create the list
dlist *l = dlist_empty(NULL);
printf("Empty list from the outside:\n");
dlist_print(l, print_string);
print_internal_with_cut_lines(l, "Empty list showing the internal structure");
dlist_pos p = dlist_first(l);
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
// Insert dynamic copies of strings at last position.
p = dlist_insert(l, copy_string(names[i]), p);
p = dlist_next(l, p);
}
// Print the list.
printf("DList from the outside after inserting 6 strings:\n");
dlist_print(l, print_string);
const char *long_desc = __FILE__
": Internal structure of the DList after inserting 6 strings.\n"
"Red lines are used for the list payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the list, i.e., the payload\n"
"memory will NOT be deallocated by the list.\n\n"
"See dlist_mwe2i for a list example\nthat owns the payload memory.";
print_internal_with_cut_lines(l, long_desc);
// Traverse the list and deallocate each value.
p = dlist_first(l);
while (!dlist_is_end(l,p)) {
char *v=dlist_inspect(l,p);
kill_string(v);
p=dlist_remove(l,p);
}
// Destroy the list.
dlist_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlist.h>
/*
* Minimum working example 2 for dlist.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit copy/kill string functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-14"
// Make a dynamic copy of the input string.
char *copy_string(char *str)
{
char *copy = calloc(strlen(str) + 1, sizeof(char));
strcpy(copy, str);
return copy;
}
// String print function.
void print_string(const void *value)
{
const char *s=value;
printf("\"%s\"", s);
}
// Return the memory occupied by the string
void kill_string(void *v)
{
char *p = v; // Convert to a char ptr, useful in a debugger
free(p);
}
// Test program.
int main(void)
{
printf("%s, %s %s: Create list of strings with standard memfreehandler.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Names to insert in the list.
char *names[] = {"Alfons", "Bengt", "Cia", "David", "Florian", "Gunnar"};
// Create the list
dlist *l = dlist_empty(kill_string);
dlist_pos p = dlist_first(l);
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
// Insert dynamic copies of strings at last position.
p = dlist_insert(l, copy_string(names[i]), p);
p = dlist_next(l, p);
}
// Print the list.
printf("DList after inserting 6 strings:\n");
dlist_print(l, print_string);
// Destroy the list.
dlist_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

136
OU4/src/dlist/dlist_mwe2i.c Normal file
View File

@@ -0,0 +1,136 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlist.h>
/*
* Minimum working example for dlist.c that shows how the internal
* structure of a list can be visualized. In this version, the list
* "owns" the payload memory, i.e., the list takes over the
* responsibility to deallocate the payload memory when the
* corresponding elements are removed. See list_mwe1i.c for a version
* where the list does not take over the responsibility.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-03-14: First public version.
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2024-03-15"
// Make a dynamic copy of the input string.
char *copy_string(char *str)
{
char *copy = calloc(strlen(str) + 1, sizeof(char));
strcpy(copy, str);
return copy;
}
// Return the memory occupied by the string
void kill_string(void *v)
{
char *p = v; // Convert to a char ptr, useful in a debugger
free(p);
}
// String print function.
void print_string(const void *value)
{
const char *s=value;
printf("\"%s\"", s);
}
void print_string_internal(const void *value)
{
const char *s=value;
// We must double-escape the double quotes since the output will
// be parsed a second time by graphviz.
printf("\\\"%s\\\"", s);
}
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const dlist *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
dlist_print_internal(l, print_string_internal, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
// Test program.
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create list of strings without memfreehandler.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Names to insert in the list.
char *names[] = {"Alfons", "Bengt", "Cia", "David", "Florian", "Gunnar"};
// Create the list
dlist *l = dlist_empty(kill_string);
printf("Empty list from the outside:\n");
dlist_print(l, print_string);
print_internal_with_cut_lines(l, "Empty list showing the internal structure");
dlist_pos p = dlist_first(l);
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
// Insert dynamic copies of strings at last position.
p = dlist_insert(l, copy_string(names[i]), p);
p = dlist_next(l, p);
}
// Print the list.
printf("DList from the outside after inserting 6 strings:\n");
dlist_print(l, print_string);
const char *long_desc = __FILE__
": Internal structure of the DList after inserting 6 strings.\n"
"Red lines are used for the list payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the list, i.e., the payload\n"
"memory WILL be deallocated by the list.\n\n"
"See dlist_mwe1i for a list example\nthat borrows the payload memory.";
print_internal_with_cut_lines(l, long_desc);
// Destroy the list.
dlist_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,28 @@
MWE = int_array_1d_mwe1 int_array_1d_mwe1i
SRC = int_array_1d.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
int_array_1d_mwe1: int_array_1d_mwe1.c int_array_1d.c
gcc -o $@ $(CFLAGS) $^
int_array_1d_mwe1i: int_array_1d_mwe1i.c int_array_1d.c
gcc -o $@ $(CFLAGS) $^
memtest: int_array_1d_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<

View File

@@ -0,0 +1,424 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <int_array_1d.h>
/*
* Implementation of a generic 1D array for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2024-05-10: Added print_internal.
*/
// =========== INTERNAL DATA TYPES ============
struct int_array_1d {
int low; // Low index limit.
int high; // High index limit.
int array_size; // Number of array elements.
int *values; // Pointer to where the actual values are stored.
};
// =========== INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* int_array_1d_create() - Create an array without values.
* @lo: low index limit.
* @hi: high index limit.
*
* The index limits are inclusive, i.e. all indices i such that low <=
* i <= high are defined.
*
* Returns: A pointer to the new array, or NULL if not enough memory
* was available.
*/
int_array_1d *int_array_1d_create(int lo, int hi)
{
// Allocate array structure.
int_array_1d *a = calloc(1, sizeof(*a));
// Store index limit.
a->low = lo;
a->high = hi;
// Number of elements.
a->array_size = hi - lo + 1;
a->values=calloc(a->array_size, sizeof(a->values[0]));
// Check whether the allocation succeeded.
if (a->values == NULL) {
free(a);
a = NULL;
}
return a;
}
/**
* int_array_1d_low() - Return the low index limit for the array.
* @a: array to inspect.
*
* Returns: The low index limit.
*/
int int_array_1d_low(const int_array_1d *a)
{
return a->low;
}
/**
* int_array_1d_high() - Return the high index limit for the array.
* @a: array to inspect.
*
* Returns: The high index limit.
*/
int int_array_1d_high(const int_array_1d *a)
{
return a->high;
}
/**
* int_array_1d_inspect_value() - Inspect a value at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: The element value at the specified position. The result is
* undefined if no value are stored at that position.
*/
int int_array_1d_inspect_value(const int_array_1d *a, int i)
{
int offset=i - int_array_1d_low(a);
// Return the value.
return a->values[offset];
}
/**
* int_array_1d_has_value() - Check if a value is set at a given array position.
* @a: array to inspect.
* @i: index of position to inspect.
*
* Returns: True if a value is set at the specified position, otherwise false.
*/
bool int_array_1d_has_value(const int_array_1d *a, int i)
{
int offset=i - int_array_1d_low(a);
// Return true if the value is not 0.
return a->values[offset] != 0;
}
/**
* int_array_1d_set_value() - Set a value at a given array position.
* @a: array to modify.
* @v: value to set element to, or 0 to clear value.
* @i: index of position to modify.
*
* Returns: Nothing.
*/
void int_array_1d_set_value(int_array_1d *a, int v, int i)
{
int offset=i - int_array_1d_low(a);
// Set value.
a->values[offset] = v;
}
/**
* int_array_1d_kill() - Return memory allocated by array.
* @a: array to kill.
*
* Returns: Nothing.
*/
void int_array_1d_kill(int_array_1d *a)
{
// Free actual storage.
free(a->values);
// Free array structure.
free(a);
}
/**
* int_array_1d_print() - Iterate over the array element and print their values.
* @a: Array to inspect.
* @print_func: Function called for each non-NULL element.
*
* Iterates over each position in the array. Calls print_func for each
* non-NULL value.
*
* Returns: Nothing.
*/
void int_array_1d_print(const int_array_1d *a)
{
printf("[ ");
for (int i=int_array_1d_low(a); i<=int_array_1d_high(a); i++) {
if (int_array_1d_has_value(a, i)) {
printf("[%d]", int_array_1d_inspect_value(a, i));
} else {
printf(" []");
}
if (i<int_array_1d_high(a)) {
printf(", ");
}
}
printf(" ]\n");
}
// ===========INTERNAL FUNCTIONS USED BY int_array_1d_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the array head struct.
* @indent_level: Indentation level.
* @a: Array to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const int_array_1d *a)
{
iprintf(indent_level, "m%04lx [shape=record label=\"low\\n%d|high\\n%d"
"|array_size\\n%d|<v>values\\n%04lx\"]\n", PTR2ADDR(a),
a->low, a->high, a->array_size, PTR2ADDR(a->values));
}
/**
* print_values() - Print a node containing all positions in the array.
* @indent_level: Indentation level.
* @a: Array to inspect.
* @max_values_to_print: Maximum number of values to output.
*
* Will print dot code to display each value in the array, up to
* max_values_to_print. If there are more values to print, adds an
* ellipsis (...) at the end.
*
* Returns: Nothing.
*/
void print_values(int indent_level, const int_array_1d *a, int max_values_to_print)
{
int values_to_print = a->array_size;
int truncated = false;
if (values_to_print > max_values_to_print) {
values_to_print = max_values_to_print;
truncated = true;
}
iprintf(indent_level, "m%04lx [shape=record label=\"", PTR2ADDR(a->values));
for (int i=0; i < values_to_print; i++) {
printf("%d\\n%02d\\n%d", i + a->low, i, a->values[i]);
if (i < values_to_print - 1) {
printf("|");
}
}
if (truncated) {
// Add ellipsis
printf("|\\n...\\n");
}
printf("\"]\n");
}
// Print edge from the array head to the values array.
static void print_head_edge(int indent_level, const int_array_1d *a)
{
print_edge(indent_level, a, a->values, "v", "values", NULL);
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* int_array_1d_print_internal() - Print the arrays internal structure in dot format.
* @a: Array to inspect.
* @desc: String with a description/state of the array, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the array and outputs dot code that shows the internal
* structure of the array. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <array_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <array_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void int_array_1d_print_internal(const int_array_1d *a, const char *desc, int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph ARRAY_1D_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "cluster_int_array_1d_%d_description [label=\"%s\"]\n", graph_number,
escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "a [label=\"%04lx\" xlabel=\"a\"]\n", PTR2ADDR(a));
iprintf(il, "a -> m%04lx\n", PTR2ADDR(a));
}
// Print the subgraph to surround the Array content
iprintf(il, "subgraph cluster_int_array_1d_%d { label=\"Array_1d\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, a);
// Output the values array. Limit output to 20 elements.
print_values(il, a, 20);
// Close the subgraph
il--;
iprintf(il, "}\n");
// Output the edges from the head
print_head_edge(il, a);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,38 @@
#include <stdio.h>
#include <int_array_1d.h>
/*
* Minimum working example for int_array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2023-01-14"
int main(void)
{
printf("%s, %s %s: Create typed integer array.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create an array with 6 positions.
int_array_1d *a = int_array_1d_create(1, 6);
for (int i=int_array_1d_low(a); i<=int_array_1d_high(a); i++) {
// Store square of index.
int_array_1d_set_value(a, i*i, i);
// Print array after setting each value.
printf("After setting value at index %d:\n", i);
int_array_1d_print(a);
}
int_array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,83 @@
#include <stdio.h>
#include <int_array_1d.h>
/*
* Minimum working example for int_array_1d.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-08: Adapted from int_array_1d_mwe1.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-08"
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(const int_array_1d *a, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
int_array_1d_print_internal(a, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create typed integer array.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create an array with 6 positions.
int_array_1d *a = int_array_1d_create(1, 6);
printf("Empty array from the outside:\n");
int_array_1d_print(a);
print_internal_with_cut_lines(a, "Empty array");
for (int i=int_array_1d_low(a); i<=int_array_1d_high(a); i++) {
// Store square of index.
int_array_1d_set_value(a, i*i, i);
}
// Print array after setting all values.
printf("Full array from the outside:\n");
int_array_1d_print(a);
print_internal_with_cut_lines(a, "Full array from the inside");
int_array_1d_kill(a);
printf("\nNormal exit.\n\n");
return 0;
}

44
OU4/src/int_list/Makefile Normal file
View File

@@ -0,0 +1,44 @@
MWE = int_list_mwe1 int_list_mwe1i
TEST = int_list_test
SRC = int_list.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe test
# Minimum working examples.
mwe: $(MWE)
# Test programs.
test: $(TEST)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(TEST) $(OBJ)
int_list_mwe1: int_list_mwe1.c int_list.c
gcc -o $@ $(CFLAGS) $^
int_list_mwe1i: int_list_mwe1i.c int_list.c
gcc -o $@ $(CFLAGS) $^
int_list_test: int_list_test.c int_list.c
gcc -o $@ $(CFLAGS) $^
test_run: test
# Run the test
./$(TEST)
memtest_mwe: int_list_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_test: int_list_test
valgrind --leak-check=full --show-reachable=yes ./$<
memtest: memtest_mwe memtest_test

542
OU4/src/int_list/int_list.c Normal file
View File

@@ -0,0 +1,542 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <int_list.h>
/*
* Implementation of a typed, undirected list of integers for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University. The implementation uses linked
* 2-cells.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.01 2018-03-26: Bugfix: Corrected const declaration in remove.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v2.0 2024-05-10: Added print_internal.
*/
// ===========INTERNAL DATA TYPES============
/*
* The list elements are implemented as two-cells with forward and
* backward links and place to store one integer. The list uses two
* border cells at the start and end of the list.
*/
typedef struct cell {
struct cell *next;
struct cell *prev;
int val;
} cell;
struct list {
cell *head;
cell *tail;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS============
/**
* list_empty() - Create an empty list.
*
* Returns: A pointer to the new list.
*/
list *list_empty(void)
{
// Allocate memory for the list head.
list *l = calloc(1, sizeof(list));
// Allocate memory for the border cells.
l->head = calloc(1, sizeof(cell));
l->tail = calloc(1, sizeof(cell));
// Set consistent links between border elements.
l->head->next = l->tail;
l->tail->prev = l->head;
return l;
}
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list * l)
{
// List is empty if there are no cells between head and tail.
return (l->head->next == l->tail);
}
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list * l)
{
// First position is position of first element.
return l->head->next;
}
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list * l)
{
// Last position is position *after* last element.
return l->tail;
}
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_next: Warning: Trying to navigate past end of list!");
}
return p->next;
}
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_first(l))) {
// This should really throw an error.
fprintf(stderr,"list_prev: Warning: Trying to navigate "
"past beginning of list!\n");
}
return p->prev;
}
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The integer value stored in the element at postiion pos.
* NOTE: The return value is undefined for the last position.
*/
int list_inspect(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_inspect: Warning: Trying to inspect "
"position at end of list!\n");
}
return p->val;
}
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @v: Integer value to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list * l, int v, const list_pos p)
{
// Allocate memory for a new cell.
list_pos e = malloc(sizeof(cell));
// Store the value.
e->val = v;
// Add links to/from the new cell.
e->next = p;
e->prev = p->prev;
p->prev = e;
e->prev->next = e;
// Return the position of the new cell.
return e;
}
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p)
{
// Remember return position.
list_pos next_pos = p->next;
// Link past this element.
p->prev->next = p->next;
p->next->prev = p->prev;
// Free the memory allocated to the cell itself.
free(p);
// Return the position of the next element.
return next_pos;
}
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements.
*
* Returns: Nothing.
*/
void list_kill(list * l)
{
// Use public functions to traverse the list.
// Start with the first element (will be defined even for an
// empty list).
list_pos p = list_first(l);
// Remove first element until list is empty.
while (!list_is_empty(l)) {
p = list_remove(l, p);
}
// Free border elements and the list head.
free(l->head);
free(l->tail);
free(l);
}
/**
* list_print() - Iterate over the list element and print their values.
* @l: List to inspect.
*
* Iterates over the list and print each stored integer.
*
* Returns: Nothing.
*/
void list_print(const list * l)
{
// Start at the beginning of the list.
list_pos p = list_first(l);
while (!list_pos_is_equal(l, p, list_end(l))) {
// Call print_func with the element value at the
// current position.
printf("[%d]\n", list_inspect(l, p));
p = list_next(l, p);
}
}
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2)
{
// Since we don't need to check whether p1 or p2 are valid, we
// only need to compare them directly.
return p1 == p2;
}
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p)
{
// Iterate over all positions in l.
list_pos q = list_first(l);
while (!list_pos_is_equal(l, q, list_end(l))) {
if (list_pos_is_equal(l, p, q)) {
// We found the position in the list.
return true;
}
// Advance to the next valid position,
q = list_next(l, q);
}
// p was not among valid positions in l.
return false;
}
// ===========INTERNAL FUNCTIONS USED BY int_list_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the list head struct.
* @indent_level: Indentation level.
* @l: List to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const list *l)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<h>head\\n%04lx|<t>tail\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(l), PTR2ADDR(l->head), PTR2ADDR(l->tail), PTR2ADDR(l));
}
// Print edges from the list head to the head and tail cells.
static void print_head_edges(int indent_level, const list *l)
{
print_edge(indent_level, l, l->head, "h", "head", NULL);
print_edge(indent_level, l, l->tail, "t", "tail", NULL);
}
// Print a node corresponding to the cell at position p.
static void print_elem_node(int indent_level, const list_pos p)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<v>val\\n%d|<n>next\\n%04lx|<p>prev\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(p), p->val, PTR2ADDR(p->next), PTR2ADDR(p->prev), PTR2ADDR(p));
}
// Print edges from the cell at position p to the next and previous
// cells and the value. The value pointer is red, the others are
// black. If the list owns the memory, the edge is solid, otherwise
// dashed.
static void print_elem_edges(int indent_level, const list *l, const list_pos p)
{
print_edge(indent_level, p, p->next, "n", "next", NULL);
print_edge(indent_level, p, p->prev, "p", "prev", NULL);
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, const char *desc, int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph LIST_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_int_list_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "l [label=\"%04lx\" xlabel=\"l\"]\n", PTR2ADDR(l));
iprintf(il, "l -> m%04lx\n", PTR2ADDR(l));
}
// Print the subgraph to surround the DList content
iprintf(il, "subgraph cluster_int_list_%d { label=\"List\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, l);
// Output the element nodes
list_pos p = l->head;
while (p != NULL) {
print_elem_node(il, p);
p = p->next;
}
// Close the subgraph
il--;
iprintf(il, "}\n");
// Output the edges from the head
print_head_edges(il, l);
// Output the edges from each element
p = l->head;
while (p != NULL) {
print_elem_edges(il, l, p);
p = p->next;
}
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,60 @@
#include <stdlib.h>
#include <stdio.h>
#include <int_list.h>
/*
* Minimum working example for int_list.c. Create a list, insert two
* elements, print list, free list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
* v1.11 2024-01-16: Fix include to be with brackets, not citation marks.
*/
#define VERSION "v1.11"
#define VERSION_DATE "2024-01-16"
int main(void)
{
printf("%s, %s %s: Create typed integer list.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty();
// Insert the value 5 first in the list.
list_insert(l, 5, list_first(l));
printf("List after inserting one value:\n");
list_print(l);
// Insert the value 8 last in the list.
list_insert(l, 8, list_end(l));
printf("List after inserting second value at the end:\n");
list_print(l);
// Insert the value 2 at the second position in the list.
list_insert(l, 2, list_next(l, list_first(l)));
printf("List after inserting a third value in the middle:\n");
list_print(l);
// Remove first element.
list_remove(l, list_first(l));
printf("List after removing first element:\n");
list_print(l);
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stdio.h>
#include <int_list.h>
/*
* Minimum working example for int_list.c. Create a list, insert two
* elements, print list, free list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
* v1.11 2024-01-16: Fix include to be with brackets, not citation marks.
*/
#define VERSION "v1.11"
#define VERSION_DATE "2024-01-16"
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const list *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
list_print_internal(l, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(void)
{
printf("%s, %s %s: Create typed integer list.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty();
printf("Empty list from the outside.\n");
list_print(l);
print_internal_with_cut_lines(l, "Empty list showing the internals");
// Insert the value 5 first in the list.
list_insert(l, 5, list_first(l));
printf("List from the outside after inserting one value:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after inserting one value showing the internals");
// Insert the value 8 last in the list.
list_insert(l, 8, list_end(l));
printf("List from the outside after inserting second value at the end:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after inserting second value at the end showing the internals");
printf("List after removing first element:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after removing first element showing the internals");
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
MWE = int_list_array_mwe1 int_list_array_mwe1i
TEST = int_list_array_test
SRC = int_list_array.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe test
# Minimum working examples.
mwe: $(MWE)
# Test programs.
test: $(TEST)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(TEST) $(OBJ)
int_list_array_mwe1: int_list_array_mwe1.c int_list_array.c
gcc -o $@ $(CFLAGS) $^
int_list_array_mwe1i: int_list_array_mwe1i.c int_list_array.c
gcc -o $@ $(CFLAGS) $^
int_list_array_test: int_list_array_test.c int_list_array.c
gcc -o $@ $(CFLAGS) $^
test_run: test
# Run the test
./$(TEST)
memtest_mwe1: int_list_array_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_test: int_list_array_test
valgrind --leak-check=full --show-reachable=yes ./$<
memtest: memtest_mwe1 memtest_test

View File

@@ -0,0 +1,515 @@
#include <stdio.h>
#include <stdlib.h>
#include <strings.h> // For bcopy
#include <stdarg.h>
#include <int_list_array.h>
/*
* Implementation of a typed, undirected list of integers for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University. The implementation uses a
* static array.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions. Bugfix
* in list_remove.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v1.4 2024-05-10: Added print_internal.
*/
// ===========INTERNAL DATA TYPES============
/*
* The list is implemented as a static array.
*/
struct list {
int last_used_pos;
int *values;
int array_size;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS============
#define ARRAY_MAX_SIZE 100
/**
* list_empty() - Create an empty list.
*
* Returns: A pointer to the new list.
*/
list *list_empty(void)
{
// Allocate memory for the list head.
list *l=malloc(sizeof(list));
// Set the size
l->array_size = ARRAY_MAX_SIZE;
// Allocate memory for the elements.
l->values=calloc(l->array_size,sizeof(l->values[0]));
// Set last used position.
l->last_used_pos=-1;
return l;
}
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list * l)
{
// List is empty if no elements are used.
return l->last_used_pos < 0;
}
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list * l)
{
// First position is always 0.
return 0;
}
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list * l)
{
// Last position is position *after* last used element.
return l->last_used_pos + 1;
}
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_next: Warning: Trying to navigate "
"past end of list!");
}
return p + 1;
}
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_first(l))) {
// This should really throw an error.
fprintf(stderr,"list_prev: Warning: Trying to navigate "
"past beginning of list!\n");
}
return p - 1;
}
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The integer value stored in the element at postiion pos.
* NOTE: The return value is undefined for the last position.
*/
int list_inspect(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_inspect: Warning: Trying to inspect "
"position at end of list!\n");
}
return l->values[p];
}
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @v: Integer value to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list * l, int v, const list_pos p)
{
// Move elements at position pos and later forward.
bcopy(l->values + p, l->values + p + 1,
sizeof(int) * (l->last_used_pos - p + 1));
// Set value.
l->values[p] = v;
// Increment number of used elements.
l->last_used_pos++;
// Return the position of the new value.
return p;
}
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p)
{
// Move elements at position pos and later forward.
bcopy(l->values + p + 1, l->values + p, sizeof(int) * (l->last_used_pos - p));
// Decrement number of used elements.
l->last_used_pos--;
// p now refers to the position after the removed element.
return p;
}
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements.
*
* Returns: Nothing.
*/
void list_kill(list * l)
{
free(l->values);
free(l);
}
/**
* list_print() - Iterate over the list element and print their values.
* @l: List to inspect.
*
* Iterates over the list and print each stored integer.
*
* Returns: Nothing.
*/
void list_print(const list * l)
{
// Start at the beginning of the list.
list_pos p = list_first(l);
while (!list_pos_is_equal(l, p, list_end(l))) {
// Call print_func with the element value at the
// current position.
printf("[%d]\n",list_inspect(l, p));
p = list_next(l, p);
}
}
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2)
{
// Since we don't need to check whether p1 or p2 are valid, we
// only need to compare them directly.
return p1 == p2;
}
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p)
{
// The position is valid if it is between 0 and last_used_pos + 1, inclusive.
return p >= 0 && p <= l->last_used_pos+1;
}
// ===========INTERNAL FUNCTIONS USED BY int_list_array_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the list head struct.
* @indent_level: Indentation level.
* @l: List to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const list *l)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"last_used_pos\\n%d|array_size\\n%d|<v>values\\n%04lx\"]\n",
PTR2ADDR(l), l->last_used_pos, l->array_size, PTR2ADDR(l->values));
}
/**
* print_values() - Print a node containing all positions in the array.
* @indent_level: Indentation level.
* @l: List to inspect.
* @max_values_to_print: Maximum number of values to output.
*
* Will print dot code to display each value in the array, up to
* max_values_to_print. If there are more values to print, adds an
* ellipsis (...) at the end.
*
* Returns: Nothing.
*/
void print_values(int indent_level, const list *l, int max_values_to_print)
{
int values_to_print = l->array_size;
int truncated = false;
if (values_to_print > max_values_to_print) {
values_to_print = max_values_to_print;
truncated = true;
}
iprintf(indent_level, "m%04lx [shape=record label=\"", PTR2ADDR(l->values));
for (int i=0; i < values_to_print; i++) {
printf("%02d\\n%d", i, l->values[i]);
if (i < values_to_print - 1) {
printf("|");
}
}
if (truncated) {
// Add ellipsis
printf("|\\n...\\n");
}
printf("\"]\n");
}
// Print edges from the list head to the head and tail cells.
static void print_head_edge(int indent_level, const list *l)
{
print_edge(indent_level, l, l->values, "v", "values", NULL);
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, const char *desc, int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph LIST_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_int_list_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "l [label=\"%04lx\" xlabel=\"l\"]\n", PTR2ADDR(l));
iprintf(il, "l -> m%04lx\n", PTR2ADDR(l));
}
// Print the subgraph to surround the List content
iprintf(il, "subgraph cluster_int_list_%d { label=\"List\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, l);
// Output the values array. Limit the output to 10 elements.
print_values(il, l, 10);
// Close the subgraph
il--;
iprintf(il, "}\n");
// Output the edges from the head
print_head_edge(il, l);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,60 @@
#include <stdlib.h>
#include <stdio.h>
#include <int_list_array.h>
/*
* Minimum working example for int_list.c. Create a list, insert two
* elements, print list, free list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
* v1.11 2024-01-16: Fix include to be with brackets, not citation marks.
*/
#define VERSION "v1.11"
#define VERSION_DATE "2024-01-16"
int main(void)
{
printf("%s, %s %s: Create typed integer list, implemented as an array.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty();
// Insert the value 5 first in the list.
list_insert(l, 5, list_first(l));
printf("List after inserting one value:\n");
list_print(l);
// Insert the value 8 last in the list.
list_insert(l, 8, list_end(l));
printf("List after inserting second value at the end:\n");
list_print(l);
// Insert the value 2 at the second position in the list.
list_insert(l, 2, list_next(l, list_first(l)));
printf("List after inserting a third value in the middle:\n");
list_print(l);
// Remove first element.
list_remove(l, list_first(l));
printf("List after removing first element:\n");
list_print(l);
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stdio.h>
#include <int_list.h>
/*
* Minimum working example for int_list.c. Create a list, insert two
* elements, print list, free list.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
* v1.11 2024-01-16: Fix include to be with brackets, not citation marks.
*/
#define VERSION "v1.11"
#define VERSION_DATE "2024-01-16"
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const list *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
list_print_internal(l, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(void)
{
printf("%s, %s %s: Create typed integer list.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty();
printf("Empty list from the outside.\n");
list_print(l);
print_internal_with_cut_lines(l, "Empty list showing the internals");
// Insert the value 5 first in the list.
list_insert(l, 5, list_first(l));
printf("List from the outside after inserting one value:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after inserting one value showing the internals");
// Insert the value 8 last in the list.
list_insert(l, 8, list_end(l));
printf("List from the outside after inserting second value at the end:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after inserting second value at the end showing the internals");
printf("List after removing first element:\n");
list_print(l);
print_internal_with_cut_lines(l, "List after removing first element showing the internals");
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

File diff suppressed because it is too large Load Diff

2
OU4/src/int_queue/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
int_queue_example_internal
int_queue_example

View File

@@ -0,0 +1,34 @@
MWE = int_queue_mwe1 int_queue_mwe1i int_queue_example int_queue_example_internal
SRC = int_queue.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
int_queue_mwe1: int_queue_mwe1.c int_queue.c
gcc -o $@ $(CFLAGS) $^
int_queue_mwe1i: int_queue_mwe1i.c int_queue.c
gcc -o $@ $(CFLAGS) $^
int_queue_example: int_queue_example.c int_queue.c
gcc -o $@ $(CFLAGS) $^
int_queue_example_internal: int_queue_example_internal.c int_queue.c
gcc -o $@ $(CFLAGS) $^
memtest1: int_queue_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<

View File

@@ -0,0 +1,310 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <int_queue.h>
/*
* Implementation of an integer queue for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The queue stores integers directly and does not use
* dynamic memory. Thus, the clean-up function queue_kill is strictly
* not necessary, but recommended to maintain symmetry with untyped,
* generic queue implementations.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-10: First public version.
*/
/**
* queue_empty() - Create an empty queue.
*
* Returns: A new, empty, queue.
*/
queue queue_empty(void)
{
queue q;
q.first_free_pos = 0;
// Set all elements to zero. Not really needed, but otherwise
// the output from print_internal becomes unreadable.
for (int i = 0; i < sizeof(q.elements)/sizeof(q.elements[0]); i++) {
q.elements[i] = 0;
}
return q;
}
/**
* queue_is_empty() - Check if a queue is empty.
* @q: Queue to check.
*
* Returns: True if queue is empty, otherwise false.
*/
bool queue_is_empty(const queue q)
{
// The queue is empty if no positions are occupied with elements,
// i.e., the first free position is zero
return q.first_free_pos == 0;
}
/**
* queue_enqueue() - Put a value at the end of a queue.
* @q: Queue to manipulate.
* @v: Value (integer) to be put in the queue.
*
* Returns: The modified queue.
*/
queue queue_enqueue(queue q, int v)
{
// Store value at first free position.
q.elements[q.first_free_pos] = v;
// Update first free position.
q.first_free_pos++;
// Return the new queue.
return q;
}
/**
* queue_dequeue() - Remove the element at the beginning of a queue.
* @q: Queue to manipulate.
*
* NOTE: Undefined for an empty queue.
*
* Returns: The modified queue.
*/
queue queue_dequeue(queue q)
{
if (queue_is_empty(q)) {
fprintf(stderr, "queue_dequeue: Warning: dequeue on empty queue\n");
} else {
// Shift all elements one step to the left
for (int i = 0; i < q.first_free_pos - 1; i++) {
q.elements[i] = q.elements[i + 1];
}
// Update the position of the first free element
q.first_free_pos--;
}
return q;
}
/**
* queue_front() - Inspect the value at the front of the queue.
* @q: Queue to inspect.
*
* Returns: The value at the front of the queue.
* NOTE: The return value is undefined for an empty queue.
*/
int queue_front(const queue q)
{
if (queue_is_empty(q)) {
fprintf(stderr, "queue_front: Warning: front on empty queue\n");
}
return q.elements[0];
}
/**
* queue_kill() - Destroy a given queue.
* @q: Queue to destroy.
*
* Does nothing since the queue does not use any dynamic
* memory. Included for symmetry with generic queue.h.
*
* Returns: Nothing.
*/
void queue_kill(queue q)
{
// Do nothing.
}
/**
* queue_print() - Iterate over the queue elements and print their values.
* @q: Queue to inspect.
*
* Iterates over the queue and prints each integer.
*
* Returns: Nothing.
*/
void queue_print(const queue q)
{
printf("{ ");
// Print elements from the top down.
for (int i = 0; i < q.first_free_pos; i++) {
printf("[%d]", q.elements[i]);
if (i < q.first_free_pos - 1) {
printf(", ");
}
}
printf(" }\n");
}
// ===========INTERNAL FUNCTIONS USED BY queue_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_head_node() - Print a node corresponding to the queue struct.
* @indent_level: Indentation level.
* @max_elems: Maximum element to print.
* @q: Queue to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, int max_elems, const queue q)
{
int elems_to_print = sizeof(q.elements)/sizeof(q.elements[0]);
if (max_elems < elems_to_print) {
elems_to_print = max_elems;
}
iprintf(indent_level, "q [shape=record label=\"first_free_pos\\n%d", q.first_free_pos);
for (int i = 0; i < elems_to_print; i++) {
printf("|%d\\n%d", i, q.elements[i]);
}
printf("\" xlabel=\"q\"]\n");
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
// Print edge from the description to the queue.
static void print_desc_edge(int indent_level)
{
iprintf(indent_level, "description -> q [style=invis] "
"// Dummy line to place description above\n");
}
/**
* queue_print_internal() - Print the internal structure of the queue in dot format.
* @q: Queue to inspect.
* @desc: String with a description/state of the queue, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost.
* @max_elems: Maximum number of elements to print.
*
* Iterates over the queue and outputs dot code that shows the
* internal structure of the queue. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <queue_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <queue_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void queue_print_internal(const queue q, const char *desc, int indent_level, int max_elems)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph QUEUE_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "cluster_queue_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
// Output the head node
print_head_node(il, max_elems, q);
// Output a dummy line to place the description at the top
print_desc_edge(il);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,50 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_queue.h>
/*
* A small example that uses an integer queue.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-16: First public version.
*/
int main(void)
{
// Create the queue.
queue q = queue_empty();
// The queue should be empty. Is it?
if (queue_is_empty(q)) {
printf("The newly created queue is empty.\n");
} else {
printf("The newly created queue is NOT empty.\n");
}
for (int i = 11; i <= 13; i++) {
printf("Add the value %d at the end of the queue.\n", i);
// Put some values in the queue.
q = queue_enqueue(q, i);
}
int v = queue_front(q);
printf("The value at the front of the queue is: %d.\n", v);
// Remove one element from the queue.
printf("Remove one element.\n");
q = queue_dequeue(q);
v = queue_front(q);
printf("The value at the front of the queue is now: %d.\n", v);
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,99 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_queue.h>
// Size of internal string buffer
#define BUFLEN 400
/*
* A small example that uses an integer queue.
*
* Generates two kinds of output:
* 1) The 'outside' view showing the stored values only.
* 2) The 'inside' view showing the internal organization.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-24: First public version.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2025-01-24"
// Print a message, then the queue and wait for the user to press return.
void print_and_wait(const queue q, const char *msg)
{
printf("\nThe output from queue_print() shows the values stored in the queue\n");
printf("\n%s\n", msg);
queue_print(q);
printf("\nPress Enter to continue...");
getchar(); // Waits for the user to press Enter
printf("\n");
}
// Print cut lines before and after a call array_print_internal.
void print_internal_and_wait(queue q, const char *desc)
{
// Print starting marker line.
printf("Direct your web browser to:\n https://dreampuf.github.io/GraphvizOnline/?engine=dot#digraph%%20G%%20%%7B%%7D%%0A\n");
printf("\n\n1) Copy the lines between the cut marks\n"
"2) Paste into the left half of the browser window.\n"
"3) The right half of the window should now show a visualization of the\n internal structure of the queue.\n");
printf("\n--- CUT HERE ---\n\n");
// Call the internal print function to get the actual dot code.
queue_print_internal(q, desc, 0, 10);
// Print ending marker line
printf("\n--- END CUT HERE ---\n\n");
printf("\nPress Enter to continue...");
getchar(); // Waits for the user to press Enter
printf("\n");
}
int main(void)
{
// Message buffer
char buf[BUFLEN];
printf("%s, %s %s: Example use of a typed integer queue.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the queue.
queue q = queue_empty();
// Call print functions to show the content of the queue
print_and_wait(q, "The queue is empty");
print_internal_and_wait(q, "The queue is empty");
for (int i = 11; i <= 13; i++) {
q = queue_enqueue(q, i);
snprintf(buf, BUFLEN, "The value %d was added to the queue", i);
print_and_wait(q, buf);
print_internal_and_wait(q, buf);
}
int v = queue_front(q);
printf("The value at the front of the queue is: %d.\n", v);
// Remove one element from the queue.
q = queue_dequeue(q);
snprintf(buf, BUFLEN, "The front element was removed from the queue");
print_and_wait(q, buf);
print_internal_and_wait(q, buf);
v = queue_front(q);
printf("The value at the front of the queue is now: %d.\n", v);
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_queue.h>
/*
* Minimum working example for int_queue.c.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-10: First public version.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2025-01-10"
int main(void)
{
printf("%s, %s %s: Create typed integer queue.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the queue.
queue q = queue_empty();
printf("--Empty QUEUE--\n");
queue_print(q);
for (int i = 11; i <= 13; i++) {
// Put some values in the queue.
q = queue_enqueue(q, i);
printf("--QUEUE during insert--\n");
queue_print(q);
}
int v = queue_front(q);
printf("The value at the front of the queue is: %d.\n", v);
printf("--QUEUE after enqueue, before dequeueing--\n");
queue_print(q);
// Remove one element from the queue.
q = queue_dequeue(q);
printf("--QUEUE after dequeueing--\n");
queue_print(q);
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,104 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_queue.h>
/*
* Minimum working example for int_queue.c.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-10: Adapted from int_queue_mwe1.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2025-01-10"
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(queue s, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
queue_print_internal(s, desc, 0, 10);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create typed integer queue.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create the queue.
queue q=queue_empty();
printf("Empty queue from the outside:\n");
queue_print(q);
print_internal_with_cut_lines(q, "Empty queue showing the inside");
for (int i = 11; i <= 13; i++) {
// Put values in the queue.
q = queue_enqueue(q, i);
}
printf("Queue for the outside after adding 3 elements:\n");
queue_print(q);
print_internal_with_cut_lines(q, "Inside of the queue after adding 3 elements");
// Remove one element from queue.
q = queue_dequeue(q);
printf("Queue for the outside after removing 1 element:\n");
queue_print(q);
print_internal_with_cut_lines(q, "Inside of the queue after removing 1 element");
// Pop remaining elements
while (!queue_is_empty(q)) {
q = queue_dequeue(q);
}
printf("Queue from the outside after removing all elements:\n");
queue_print(q);
print_internal_with_cut_lines(q, "Inside of the queue after removing all elements");
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue_mwe1.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,28 @@
MWE = int_stack_mwe1 int_stack_mwe1i
SRC = int_stack.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
int_stack_mwe1: int_stack_mwe1.c int_stack.c
gcc -o $@ $(CFLAGS) $^
int_stack_mwe1i: int_stack_mwe1i.c int_stack.c
gcc -o $@ $(CFLAGS) $^
memtest1: int_stack_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<

View File

@@ -0,0 +1,316 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <int_stack.h>
/*
* Implementation of an integer stack for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University. The stack stores integers directly and does not use
* dynamic memory. Thus, the clean-up function stack_kill is strictly
* not necessary, but recommended to maintain symmetry with untyped,
* generic stack implementations.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se)
* Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2022-03-24: First public version.
* v1.1 2024-04-10: Added print_internal.
* v1.2 2024-05-10: Added/updated print_internal with improved encapsulation.
*/
/**
* stack_empty() - Create an empty stack.
*
* Returns: An empty stack.
*/
stack stack_empty(void)
{
stack s;
s.first_free_pos = 0;
// Set all elements to zero. Not really needed, but otherwise
// the output from print_internal becomes unreadable.
for (int i = 0; i < sizeof(s.elements)/sizeof(s.elements[0]); i++) {
s.elements[i] = 0;
}
return s;
}
/**
* stack_is_empty() - Check if a stack is empty.
* @s: Stack to check.
*
* Returns: True if stack is empty, otherwise false.
*/
bool stack_is_empty(const stack s)
{
// The stack is empty if no positions are occupied with elements,
// i.e., the first free position is zero
return s.first_free_pos == 0;
}
/**
* stack_push() - Push a value on top of a stack.
* @s: Stack to manipulate.
* @v: Value (integer) to be put on the stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack stack_push(stack s, int v)
{
// Store value at first free position.
s.elements[s.first_free_pos] = v;
// Update first free position.
s.first_free_pos++;
// Return the new stack.
return s;
}
/**
* stack_pop() - Remove the element at the top of a stack.
* @s: Stack to manipulate.
*
* NOTE: Undefined for an empty stack.
*
* Returns: The modified stack.
* NOTE: After the call, the input stack should be considered invalid.
*/
stack stack_pop(stack s)
{
if (stack_is_empty(s)) {
fprintf(stderr, "stack_pop: Warning: pop on empty stack\n");
} else {
// We only have to decrease the first free position to
// indicate that the element that used to be on top of the
// stack is now free for use.
s.first_free_pos--;
}
return s;
}
/**
* stack_top() - Inspect the value at the top of the stack.
* @s: Stack to inspect.
*
* Returns: The integer at the top of the stack.
* NOTE: The return value is undefined for an empty stack.
*/
int stack_top(const stack s)
{
if (stack_is_empty(s)) {
fprintf(stderr, "stack_top: Warning: top on empty stack\n");
}
return s.elements[s.first_free_pos - 1];
}
/**
* stack_kill() - Destroy a given stack.
* @s: Stack to destroy.
*
* Does nothing since the stack does not use any dynamic
* memory. Included for symmetry with generic stack.h.
*
* Returns: Nothing.
*/
void stack_kill(stack s)
{
// Do nothing.
}
/**
* stack_print() - Iterate over the stack elements and print their values.
* @s: Stack to inspect.
*
* Iterates over the stack and prints each integer.
*
* Returns: Nothing.
*/
void stack_print(const stack s)
{
printf("{ ");
// Print elements from the top down.
for (int i = s.first_free_pos - 1; i >= 0; i--) {
printf("[%d]", s.elements[i]);
if (i>0) {
printf(", ");
}
}
printf(" }\n");
}
// ===========INTERNAL FUNCTIONS USED BY stack_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_head_node() - Print a node corresponding to the stack struct.
* @indent_level: Indentation level.
* @max_elems: Maximum element to print.
* @s: Stack to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, int max_elems, const stack s)
{
int elems_to_print = sizeof(s.elements)/sizeof(s.elements[0]);
if (max_elems < elems_to_print) {
elems_to_print = max_elems;
}
iprintf(indent_level, "s [shape=record label=\"first_free_pos\\n%d", s.first_free_pos);
for (int i = 0; i < elems_to_print; i++) {
printf("|%d\\n%d", i, s.elements[i]);
}
printf("\" xlabel=\"s\"]\n");
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
// Print edge from the description to the stack.
static void print_desc_edge(int indent_level)
{
iprintf(indent_level, "description -> s [style=invis] "
"// Dummy line to place description above\n");
}
/**
* stack_print_internal() - Print the internal structure of the stack in dot format.
* @s: Stack to inspect.
* @desc: String with a description/state of the stack, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost.
* @max_elems: Maximum number of elements to print.
*
* Iterates over the stack and outputs dot code that shows the
* internal structure of the stack. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <stack_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <stack_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void stack_print_internal(const stack s, const char *desc, int indent_level, int max_elems)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph STACK_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "cluster_stack_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
// Output the head node
print_head_node(il, max_elems, s);
// Output a dummy line to place the description at the top
print_desc_edge(il);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_stack.h>
/*
* Minimum working example for int_stack.c.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2022-03-24: First public version.
* v1.1 2023-01-14: Added printouts at start/end of main.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2023-01-14"
int main(void)
{
printf("%s, %s %s: Create typed integer stack.\n", __FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the stack.
stack s=stack_empty();
for (int i=1; i<=3; i++) {
// Push value on stack.
s = stack_push(s, i);
}
printf("--STACK before popping--\n");
stack_print(s);
// Pop element from stack.
s=stack_pop(s);
printf("--STACK after popping--\n");
stack_print(s);
// Kill stack. Strictly not necessary for int_stack since it
// does not use any dynamic memory. Included for symmetry with
// stack.c.
stack_kill(s);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,103 @@
#include <stdio.h>
#include <stdlib.h>
#include <int_stack.h>
/*
* Minimum working example for int_stack.c.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-04-10: Adapted from int_stack_mwe1.c.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2024-04-10"
// Print cut lines before and after a call array_print_internal.
void print_internal_with_cut_lines(stack s, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
stack_print_internal(s, desc, 0, 10);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create typed integer stack.\n", __FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create the stack.
stack s=stack_empty();
printf("Empty stack from the outside:\n");
stack_print(s);
print_internal_with_cut_lines(s, "Empty stack showing the inside");
for (int i=1; i<=3; i++) {
// Push value on stack.
s = stack_push(s, 10 + i);
}
printf("Stack for the outside after pushing 3 elements:\n");
stack_print(s);
print_internal_with_cut_lines(s, "Inside of the stack after pushing 3 elements");
// Pop one element from stack.
s = stack_pop(s);
printf("Stack for the outside after popping 1 element:\n");
stack_print(s);
print_internal_with_cut_lines(s, "Inside of the stack after popping 1 element");
// Pop remaining elements
while (!stack_is_empty(s)) {
s = stack_pop(s);
}
printf("Stack from the outside after popping all elements:\n");
stack_print(s);
print_internal_with_cut_lines(s, "Inside of the stack after popping all elements");
// Kill stack. Strictly not necessary for int_stack since it
// does not use any dynamic memory. Included for symmetry with
// stack_mwe1.c.
stack_kill(s);
printf("\nNormal exit.\n\n");
return 0;
}

68
OU4/src/list/Makefile Normal file
View File

@@ -0,0 +1,68 @@
MWE = list_mwe1 list_mwe2 list_mwe1i list_mwe2i
TEST = list_test1 list_test2
SRC = list.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe test
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
test: list_test1 list_test2
# Clean up
clean:
-rm -f $(MWE) $(TEST) $(OBJ)
list_mwe1: list_mwe1.c list.c
gcc -o $@ $(CFLAGS) $^
list_mwe2: list_mwe2.c list.c
gcc -o $@ $(CFLAGS) $^
list_mwe1i: list_mwe1i.c list.c
gcc -o $@ $(CFLAGS) $^
list_mwe2i: list_mwe2i.c list.c
gcc -o $@ $(CFLAGS) $^
memtest_mwe1: list_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_mwe2: list_mwe2
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_mwe1i: list_mwe1i
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_mwe2i: list_mwe2i
valgrind --leak-check=full --show-reachable=yes ./$<
list_test1: list_test1.c list.c
gcc -o $@ $(CFLAGS) $^
list_test2: list_test2.c list.c
gcc -o $@ $(CFLAGS) $^
test_run1: list_test1
# Run the test
./$<
test_run2: list_test2
# Run the test
./$<
memtest_test1: list_test1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest_test2: list_test2
valgrind --leak-check=full --show-reachable=yes ./$<
memtests: memtest_mwe1 memtest_mwe2 memtest_mwe1i memtest_mwe2i memtest_test1 memtest_test2

111
OU4/src/list/README.md Normal file
View File

@@ -0,0 +1,111 @@
# Dubbellänkad lista
En två-cellsimplementation av ADT:n _Lista_.
## Minneshantering
Följande kodsnutt kommer skapa en lista med ett element som har värdet 5. I
detta exempel så allokeras inget minne dynamiskt, därför behöver vi inte heller
ta hand om något minne efter vi använt klart listan.
```c
int val = 5;
list *l = list_empty(NULL);
list_insert(l, &val, list_first(l));
```
Vi kan skriva om ovan exempel så att minne allokeras på heapen, men då måste vi
manuellt komma ihåg att avallokera detta minne efter användning.
```c
int *val = malloc(sizeof(int));
*val = 5;
list *l = list_empty(NULL);
list_insert(l, val, list_first(l));
...
list_kill(l);
free(val);
```
Om vi vill allokera minne dynamiskt, men vill att listan själva ska hantera
avallokering av minne (e.g. vid `list_remove`) så behöver vi ange en
minneshanteringsfunktion:
```c
int *val = malloc(sizeof(int));
*val = 5;
list *l = list_empty(free);
list_insert(l, val, list_first(l));
...
list_kill(l);
```
I exemplet ovan kommer `list_kill(l)` att anropa `free` för varje element i
listan, och därmed sköta minneshanteringen åt oss.
### Egen free-funktion
Det är också möjligt att definiera en egen funktion som ska sköta
avallokeringen. Till exempel kanske vi vill skriva ut varje värde som
avallokeras i debugging-syfte. Då kan vi skriva en enkel wrapper-funktion för
`free` på följande sätt:
```c
static void free_and_print(void *data)
{
printf("Free'ing [%d]\n", *(int*)data);
free(data);
}
```
Denna funktion skulle då kunna användas på följande sätt:
```c
list *l = list_empty(free_and_print);
int *val = malloc(sizeof(int));
*val = 5;
list_insert(l, val, list_first(l));
list_kill(l);
```
Denna kodsnutt skulle då skriva ut `Free'ing [5]`.
## Utskrift
För att skriva ut listan, t.ex. vid debugging eller för att visa innehållet för
en användare så kan vi definiera en egen funktion för att presentera tillståndet
hos datatypen. Det enklaste fallet är om vi enbart vill skriva ut, e.g., en
lista med heltal där varje värde hamnar på en egen rad:
```c
static void print_ints(const void *data)
{
printf("%d\n", *(int*)data);
}
```
Notera att inparametern är av typen `const`. `const` indikerar att pekaren bara
får läsas, ej manipuleras. Vi vill inte att en print-funktion ska kunna ändra på
listans innehåll.
`print_ints` kan nu användas på följande sätt:
```c
list *l = list_empty(free);
int *val = malloc(sizeof(int));
*val = 5;
list_insert(l, val, list_first(l));
list_print(l, print_ints);
```
Detta exempel skulle skriva ut `5` på en egen rad.
# Minimal working example
Mycket av det som behandlats ovan sammanfattas i följande minimal working
example:
Se [list_mwe1.c](list_mwe1.c) och [list_mwe2.c](list_mwe2.c).

620
OU4/src/list/list.c Normal file
View File

@@ -0,0 +1,620 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <list.h>
/*
* Implementation of a generic, undirected list for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
* Lars Karlsson (larsk@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-02-25: Renamed list header fields head and tail.
* v1.4 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v1.5 2024-03-13: Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.0 2024-03-14: Added list_print_internal to output dot code for visualization.
* v2.1 2024-05-10: Added/updated print_internal with improved encapsulation.
*/
// ===========INTERNAL DATA TYPES ============
/*
* The list elements are implemented as two-cells with forward and
* backward links and a void * for the value. The list uses two border
* cells at the start and end of the list.
*/
typedef struct cell {
struct cell *next;
struct cell *prev;
void *val;
} cell;
struct list {
cell *head;
cell *tail;
kill_function kill_func;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS============
/**
* list_empty() - Create an empty list.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new list.
*/
list *list_empty(kill_function kill_func)
{
// Allocate memory for the list head.
list *l = calloc(1, sizeof(list));
// Allocate memory for the border cells.
l->head = calloc(1, sizeof(cell));
l->tail = calloc(1, sizeof(cell));
// Set consistent links between border elements.
l->head->next = l->tail;
l->tail->prev = l->head;
// Store the kill function.
l->kill_func = kill_func;
return l;
}
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list *l)
{
// List is empty if there are no cells between head and tail.
return (l->head->next == l->tail);
}
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list *l)
{
// First position is position of first element.
return l->head->next;
}
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list *l)
{
// Last position is position *after* last element.
return l->tail;
}
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list *l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_next: Warning: Trying to navigate past end of list!");
}
return p->next;
}
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list *l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_first(l))) {
// This should really throw an error.
fprintf(stderr,"list_prev: Warning: Trying to navigate "
"past beginning of list!\n");
}
return p->prev;
}
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The value at the given position as a void pointer.
* NOTE: The return value is undefined for the last position.
*/
void *list_inspect(const list *l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_inspect: Warning: Trying to inspect "
"position at end of list!\n");
}
return p->val;
}
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @v: Value (pointer) to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list *l, void *v, const list_pos p)
{
// Allocate memory for a new cell.
list_pos e = malloc(sizeof(cell));
// Store the value.
e->val = v;
// Add links to/from the new cell.
e->next = p;
e->prev = p->prev;
p->prev = e;
e->prev->next = e;
// Return the position of the new cell.
return e;
}
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list. If a kill_func
* was registered at list creation, calls it to deallocate the memory
* held by the element value.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p)
{
// Remember return position.
list_pos next_pos = p->next;
// Link past this element.
p->prev->next = p->next;
p->next->prev = p->prev;
// Call kill_func if registered.
if (l->kill_func != NULL) {
// Return any user-allocated memory for the value.
l->kill_func(p->val);
}
// Return the memory allocated to the cell itself.
free(p);
// Return the position of the next element.
return next_pos;
}
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements. If a
* kill_func was registered at list creation, also calls it for each
* element to return any user-allocated memory occupied by the element
* values.
*
* Returns: Nothing.
*/
void list_kill(list *l)
{
// Use public functions to traverse the list.
// Start with the first element (will be defined even for an
// empty list).
list_pos p = list_first(l);
// Remove first element until list is empty.
while (!list_is_empty(l)) {
p = list_remove(l, p);
}
// Free border elements and the list head.
free(l->head);
free(l->tail);
free(l);
}
/**
* list_print() - Iterate over the list element and print their values.
* @l: List to inspect.
* @print_func: Function called for each element.
*
* Iterates over the list and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void list_print(const list *l, inspect_callback print_func)
{
// Start at the beginning of the list.
list_pos p = list_first(l);
printf("( ");
while (!list_pos_is_equal(l, p, list_end(l))) {
// Call print_func with the element value at the
// current position.
print_func(list_inspect(l, p));
// Advance to next position.
p = list_next(l, p);
// Print separator unless at end.
if (!list_pos_is_equal(l, p, list_end(l))) {
printf(", ");
}
}
printf(" )\n");
}
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2)
{
// Since we don't need to check whether p1 or p2 are valid, we
// only need to compare them directly.
return p1 == p2;
}
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p)
{
// Iterate over all positions in l.
list_pos q = list_first(l);
while (!list_pos_is_equal(l, q, list_end(l))) {
if (list_pos_is_equal(l, p, q)) {
// We found the position in the list.
return true;
}
// Advance to the next valid position,
q = list_next(l, q);
}
// p was not among valid positions in l.
return false;
}
// ===========INTERNAL FUNCTIONS USED BY dlist_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the list head struct.
* @indent_level: Indentation level.
* @l: List to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const list *l)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"kill\\n%04lx|<h>head\\n%04lx|<t>tail\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(l), PTR2ADDR(l->kill_func), PTR2ADDR(l->head), PTR2ADDR(l->tail),
PTR2ADDR(l));
}
// Print edges from the list head to the head and tail cells.
static void print_head_edges(int indent_level, const list *l)
{
print_edge(indent_level, l, l->head, "h", "head", NULL);
print_edge(indent_level, l, l->tail, "t", "tail", NULL);
}
// Print a node corresponding to the cell at position p.
static void print_elem_node(int indent_level, const list_pos p)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<v>val\\n%04lx|<n>next\\n%04lx|<p>prev\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(p), PTR2ADDR(p->val), PTR2ADDR(p->next), PTR2ADDR(p->prev), PTR2ADDR(p));
}
// Print edges from the cell at position p to the next and previous
// cells and the value. The value pointer is red, the others are
// black. If the list owns the memory, the edge is solid, otherwise
// dashed.
static void print_elem_edges(int indent_level, const list *l, const list_pos p)
{
print_edge(indent_level, p, p->next, "n", "next", NULL);
print_edge(indent_level, p, p->prev, "p", "prev", NULL);
// Ignore val ptr for head and tail nodes.
if (p == l->head || p == l->tail) {
return;
}
if (l->kill_func) {
print_edge(indent_level, p, p->val, "v", "val", "color=red");
} else {
print_edge(indent_level, p, p->val, "v", "val", "color=red style=dashed");
}
}
// Print the node for the memory block at p using the user-supplied
// print_func to print the label.
static void print_value_node(int indent_level, const void *p, inspect_callback print_func)
{
iprintf(indent_level, "m%04lx [label=\"", PTR2ADDR(p));
if (print_func != NULL) {
print_func(p);
}
printf("\" xlabel=\"%04lx\"]\n", PTR2ADDR(p));
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, inspect_callback print_func, const char *desc,
int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph LIST_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
iprintf(il, "subgraph cluster_nullspace {\n");
iprintf(il+1, "NULL\n");
iprintf(il, "}\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_list_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "l [label=\"%04lx\" xlabel=\"l\"]\n", PTR2ADDR(l));
iprintf(il, "l -> m%04lx\n", PTR2ADDR(l));
}
// Print the subgraph to surround the DList content
iprintf(il, "subgraph cluster_list_%d { label=\"List\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, l);
// Output the element nodes
list_pos p = l->head;
while (p != NULL) {
print_elem_node(il, p);
p = p->next;
}
// Close the subgraph
il--;
iprintf(il, "}\n");
if (indent_level == 0) {
// Put the user nodes in userspace
iprintf(il, "subgraph cluster_userspace { label=\"User space\"\n");
il++;
}
// Output the value nodes
p = l->head;
while (p != NULL) {
if (p->val) {
print_value_node(il, p->val, print_func);
}
p = p->next;
}
if (indent_level == 0) {
// Close userspace
il--;
iprintf(il, "}\n");
}
// Output the edges from the head
print_head_edges(il, l);
// Output the edges from each element
p = l->head;
while (p != NULL) {
print_elem_edges(il, l, p);
p = p->next;
}
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

103
OU4/src/list/list_mwe1.c Normal file
View File

@@ -0,0 +1,103 @@
#include <stdio.h>
#include <stdlib.h>
#include <list.h>
/*
* Minimum working example for list.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-13: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-13"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
static void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v=malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p=v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer list without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty(NULL);
// Create a dynamic integer with value 5.
int *val = int_create(5);
// Insert the value first in the list.
list_insert(l, val, list_first(l));
printf("List after inserting one value:\n");
list_print(l, print_int);
// Allocate space for another integer.
val = int_create(8);
// Insert the value last in the list.
list_insert(l, val, list_end(l));
printf("List after inserting second value at the end:\n");
list_print(l, print_int);
// Allocate space for a third integer.
val = int_create(2);
// Insert the value at the second position in the list.
list_insert(l, val, list_next(l, list_first(l)));
printf("List after inserting a third value in the middle:\n");
list_print(l, print_int);
// Remove first element.
list_pos p=list_first(l);
int *v=list_inspect(l, p);
// Remove element from list.
list_remove(l, p);
// Free element content.
int_kill(v);
printf("List after removing first element:\n");
list_print(l, print_int);
// Empty the list.
while (!list_is_empty(l)) {
list_pos p=list_first(l);
int *v=list_inspect(l,p);
int_kill(v);
list_remove(l,p);
}
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

131
OU4/src/list/list_mwe1i.c Normal file
View File

@@ -0,0 +1,131 @@
#include <stdio.h>
#include <stdlib.h>
#include <list.h>
/*
* Minimum working example for list.c that shows how the internal
* structure of a list can be visualized. In this version, the list
* "borrows" the payload memory, i.e., the user of the list is
* responsible for deallocating the payload memory. See list_mwe2i.c
* for a version where the list takes over the responsibility.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-03-14: First public version.
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2024-03-15"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const list *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
list_print_internal(l, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create integer list without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create the list.
list *l = list_empty(NULL);
printf("Empty list from the outside:\n");
list_print(l, print_int);
print_internal_with_cut_lines(l, "Empty list showing the internal structure");
// Insert the value 5 first in the list.
list_insert(l, int_create(5), list_first(l));
// Insert the value 8 last in the list.
list_insert(l, int_create(8), list_end(l));
// Insert the value 2 at the second position in the list.
list_insert(l, int_create(2), list_next(l, list_first(l)));
printf("List from the outside after inserting 3 values:\n");
list_print(l, print_int);
const char *long_desc = __FILE__
": Internal structure of the List after inserting 3 values.\n"
"Red lines are used for the list payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the list, i.e., the payload\n"
"memory will NOT be deallocated by the list.\n\n"
"See list_mwe2i for a list example\nthat owns the payload memory.";
print_internal_with_cut_lines(l, long_desc);
// Empty the list.
while (!list_is_empty(l)) {
list_pos p=list_first(l);
int *v=list_inspect(l,p);
int_kill(v);
list_remove(l,p);
}
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

92
OU4/src/list/list_mwe2.c Normal file
View File

@@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <list.h>
/*
* Minimum working example for list.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.21 2024-01-16: Fix include to be with brackets, not citation marks.
* v1.3 2024-03-13: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-13"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
static void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v=malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p=v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer list with custom kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the list.
list *l = list_empty(int_kill);
// Create a dynamic integer with value 5.
int *val = int_create(5);
// Insert the value first in the list.
list_insert(l, val, list_first(l));
printf("List after inserting one value:\n");
list_print(l, print_int);
// Allocate space for another integer.
val = int_create(8);
// Insert the value last in the list.
list_insert(l, val, list_end(l));
printf("List after inserting second value at the end:\n");
list_print(l, print_int);
// Allocate space for a third integer.
val = int_create(2);
// Insert the value at the second position in the list.
list_insert(l, val, list_next(l, list_first(l)));
printf("List after inserting a third value in the middle:\n");
list_print(l, print_int);
// Remove first element.
list_remove(l, list_first(l));
printf("List after removing first element:\n");
list_print(l, print_int);
// Done, kill the list.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

125
OU4/src/list/list_mwe2i.c Normal file
View File

@@ -0,0 +1,125 @@
#include <stdio.h>
#include <stdlib.h>
#include <list.h>
/*
* Minimum working example for list.c that shows how the internal
* structure of a list can be visualized. In this version, the list
* "owns" the payload memory, i.e., the list takes over the
* responsibility to deallocate the payload memory when the
* corresponding elements are removed. See list_mwe1i.c for a version
* where the list does not take over the responsibility.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-03-14: First public version.
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2024-03-15"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call list_print_internal.
void print_internal_with_cut_lines(const list *l, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
list_print_internal(l, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create integer list with kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create the list.
list *l = list_empty(int_kill);
printf("Empty list from the outside:\n");
list_print(l, print_int);
print_internal_with_cut_lines(l, "Empty list showing the internal structure");
// Insert the value 5 first in the list.
list_insert(l, int_create(5), list_first(l));
// Insert the value 8 last in the list.
list_insert(l, int_create(8), list_end(l));
// Insert the value 2 at the second position in the list.
list_insert(l, int_create(2), list_next(l, list_first(l)));
printf("List from the outside after inserting 3 values:\n");
list_print(l, print_int);
const char *long_desc = __FILE__
": Internal structure of the List after inserting 3 values.\n"
"Red lines are used for the list payload.\n\n"
"The solid red lines indicate that the payload memory is\n"
"OWNED -- not borrowed -- by the list, i.e., the payload\n"
"memory WILL be deallocated by the list.\n\n"
"See list_mwe1i for a list example\nthat borrows the payload memory.";
print_internal_with_cut_lines(l, long_desc);
// Kill the list, including the payload.
list_kill(l);
printf("\nNormal exit.\n\n");
return 0;
}

1190
OU4/src/list/list_test1.c Normal file

File diff suppressed because it is too large Load Diff

1308
OU4/src/list/list_test2.c Normal file

File diff suppressed because it is too large Load Diff

2
OU4/src/queue/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
queue_example
queue_example_internal

49
OU4/src/queue/Makefile Normal file
View File

@@ -0,0 +1,49 @@
MWE = queue_mwe1 queue_mwe2 queue_mwe1i queue_mwe2i queue_example queue_example_internal
SRC = queue.c
OBJ = $(SRC:.c=.o)
CC = gcc
CFLAGS = -std=c99 -Wall -I../../include -g
all: mwe
# Minimum working examples.
mwe: $(MWE)
# Object file for library
obj: $(OBJ)
# Clean up
clean:
-rm -f $(MWE) $(OBJ)
queue_example_internal: queue_example_internal.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
queue_example: queue_example.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
queue_mwe1: queue_mwe1.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
queue_mwe2: queue_mwe2.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
queue_mwe1i: queue_mwe1i.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
queue_mwe2i: queue_mwe2i.c queue.c ../list/list.c
gcc -o $@ $(CFLAGS) $^
memtest1: queue_mwe1
valgrind --leak-check=full --show-reachable=yes ./$<
memtest2: queue_mwe2
valgrind --leak-check=full --show-reachable=yes ./$<
memtest3: queue_mwe1i
valgrind --leak-check=full --show-reachable=yes ./$<
memtest4: queue_mwe2i
valgrind --leak-check=full --show-reachable=yes ./$<

11
OU4/src/queue/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Kö
En implementation av ADT:n __ baserad på en dubbel-länkad lista.
## Minneshantering och utskrift
Det mesta av hur gränsytan används med avseende på minneshantering och
utskrifter är analogt för hur [listimplementationen](../list/) fungerar.
# Minimal working example
Se [queue_mwe1.c](queue_mwe1.c) och [queue_mwe2.c](queue_mwe2.c).

401
OU4/src/queue/queue.c Normal file
View File

@@ -0,0 +1,401 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <queue.h>
#include <list.h>
/*
* Implementation of a generic queue for the "Datastructures and
* algorithms" courses at the Department of Computing Science, Umea
* University.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Based on earlier code by: Johan Eliasson (johane@cs.umu.se).
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.01 2024-01-16: Fix include to be with brackets, not citation marks.
* v2.0 2024-03-14: Added queue_print_internal to output dot code for visualization.
* Renamed free_* stuff to kill_*. Converted to 4-tabs.
* v2.1 2024-05-10: Updated print_internal with improved encapsulation.
*/
// ===========INTERNAL DATA TYPES ============
/*
* The queue is implemented using the list abstract datatype. Almost
* everything is done by the list.
*/
struct queue {
list *elements;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
/**
* queue_empty() - Create an empty queue.
* @kill_func: A pointer to a function (or NULL) to be called to
* de-allocate memory on remove/kill.
*
* Returns: A pointer to the new queue.
*/
queue *queue_empty(kill_function kill_func)
{
// Allocate the queue head.
queue *q = calloc(1, sizeof(*q));
// Create an empty list.
q->elements = list_empty(kill_func);
return q;
}
/**
* queue_is_empty() - Check if a queue is empty.
* @q: Queue to check.
*
* Returns: True if queue is empty, otherwise false.
*/
bool queue_is_empty(const queue *q)
{
return list_is_empty(q->elements);
}
/**
* queue_enqueue() - Put a value at the end of the queue.
* @q: Queue to manipulate.
* @v: Value (pointer) to be put in the queue.
*
* Returns: The modified queue.
*/
queue *queue_enqueue(queue *q, void *v)
{
list_insert(q->elements, v, list_end(q->elements));
return q;
}
/**
* queue_dequeue() - Remove the element at the front of a queue.
* @q: Queue to manipulate.
*
* NOTE: Undefined for an empty queue.
*
* Returns: The modified queue.
*/
queue *queue_dequeue(queue *q)
{
list_remove(q->elements, list_first(q->elements));
return q;
}
/**
* queue_front() - Inspect the value at the front of the queue.
* @q: Queue to inspect.
*
* Returns: The value at the top of the queue.
* NOTE: The return value is undefined for an empty queue.
*/
void *queue_front(const queue *q)
{
return list_inspect(q->elements, list_first(q->elements));
}
/**
* queue_kill() - Destroy a given queue.
* @q: Queue to destroy.
*
* Return all dynamic memory used by the queue and its elements. If a
* kill_func was registered at queue creation, also calls it for each
* element to kill any user-allocated memory occupied by the element values.
*
* Returns: Nothing.
*/
void queue_kill(queue *q)
{
list_kill(q->elements);
free(q);
}
/**
* queue_print() - Iterate over the queue elements and print their values.
* @q: Queue to inspect.
* @print_func: Function called for each element.
*
* Iterates over the queue and calls print_func with the value stored
* in each element.
*
* Returns: Nothing.
*/
void queue_print(const queue *q, inspect_callback print_func)
{
printf("{ ");
list_pos pos = list_first(q->elements);
while (pos != list_end(q->elements)) {
print_func(list_inspect(q->elements, pos));
pos = list_next(q->elements, pos);
if (pos != list_end(q->elements)) {
printf(", ");
}
}
printf(" }\n");
}
// ===========INTERNAL FUNCTIONS USED BY queue_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the queue head struct.
* @il: Indentation level.
* @q: Queue to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const queue *q)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<e>elements\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(q), PTR2ADDR(q->elements), PTR2ADDR(q));
}
// Print edges from the queue head to the elements list.
static void print_head_edge(int indent_level, const queue *q)
{
print_edge(indent_level, q, q->elements, "e", "elements", NULL);
}
// Print the node for the memory block at p using the user-supplied
// print_func to print the label.
static void print_value_node(int indent_level, const void *p, inspect_callback print_func)
{
iprintf(indent_level, "m%04lx [label=\"", PTR2ADDR(p));
if (print_func != NULL) {
print_func(p);
}
printf("\" xlabel=\"%04lx\"]\n", PTR2ADDR(p));
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* queue_print_internal() - Print the queues internal structure in dot format.
* @l: Queue to inspect.
* @print_func: Function called for each element value.
* @desc: String with a description/state of the queue, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the queue and outputs dot code that shows the internal
* structure of the queue. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <queue_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <queue_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void queue_print_internal(const queue *q, inspect_callback print_func, const char *desc,
int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph QUEUE_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
iprintf(il, "subgraph cluster_nullspace {\n");
iprintf(il+1, "NULL\n");
iprintf(il, "}\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_queue_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "q [label=\"%04lx\" xlabel=\"q\"]\n", PTR2ADDR(q));
iprintf(il, "q -> m%04lx\n", PTR2ADDR(q));
}
// Output the payload nodes before asking the list to print them
// to render them in their own subgraph.
if (indent_level == 0) {
// Put the user nodes in userspace
iprintf(il, "subgraph cluster_userspace { label=\"User space\"\n");
il++;
// Iterate over the list to print the payload nodes
list_pos p = list_first(q->elements);
while (!list_pos_is_equal(q->elements, p, list_end(q->elements))) {
print_value_node(il, list_inspect(q->elements, p), print_func);
// Advance
p = list_next(q->elements, p);
}
// Close the subgraph
il--;
iprintf(il, "}\n");
}
// Print the subgraph to surround the DList content
iprintf(il, "subgraph cluster_queue_%d { label=\"Queue\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, q);
if (q->elements) {
list_print_internal(q->elements, print_func, NULL, il);
}
// Close the subgraph
il--;
iprintf(il, "}\n");
// Output the edges from the head
print_head_edge(il, q);
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}

View File

@@ -0,0 +1,68 @@
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
/*
* A small example that uses the generic queue to store integers.
* Based on int_queue_example.c from int_queue.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-23: First public version.
*/
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
int main(void)
{
// Create the queue.
queue *q = queue_empty(int_kill);
// The queue should be empty. Is it?
if (queue_is_empty(q)) {
printf("The newly created queue is empty.\n");
} else {
printf("The newly created queue is NOT empty.\n");
}
for (int i = 11; i <= 13; i++) {
printf("Add the value %d at the end of the queue.\n", i);
int *v = int_create(i);
// Put some values in the queue.
q = queue_enqueue(q, v);
}
int *v = queue_front(q);
printf("The value at the front of the queue is: %d.\n", *v);
// Remove one element from the queue.
printf("Remove one element.\n");
q = queue_dequeue(q);
v = queue_front(q);
printf("The value at the front of the queue is now: %d.\n", *v);
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,124 @@
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
// Size of internal string buffer
#define BUFLEN 400
/*
* A small example that uses a generic queue to store integers.
*
* Generates two kinds of output:
* 1) The 'outside' view showing the stored values only.
* 2) The 'inside' view showing the internal organization.
*
* Author: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2025-01-24: First public version.
*/
#define VERSION "v1.0"
#define VERSION_DATE "2025-01-24"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print a message, then the queue and wait for the user to press return.
void print_and_wait(const queue *q, const char *msg)
{
printf("\nThe output from queue_print() shows the values stored in the queue\n");
printf("\n%s\n", msg);
queue_print(q, print_int);
printf("\nPress Enter to continue...");
getchar(); // Waits for the user to press Enter
printf("\n");
}
// Print cut lines before and after a call array_print_internal.
void print_internal_and_wait(const queue *q, const char *desc)
{
// Print starting marker line.
printf("Direct your web browser to:\n https://dreampuf.github.io/GraphvizOnline/?engine=dot#digraph%%20G%%20%%7B%%7D%%0A\n");
printf("\n\n1) Copy the lines between the cut marks\n"
"2) Paste into the left half of the browser window.\n"
"3) The right half of the window should now show a visualization of the\n internal structure of the queue.\n");
printf("\n--- CUT HERE ---\n\n");
// Call the internal print function to get the actual dot code.
queue_print_internal(q, print_int, desc, 0);
// Print ending marker line
printf("\n--- END CUT HERE ---\n\n");
printf("\nPress Enter to continue...");
getchar(); // Waits for the user to press Enter
printf("\n");
}
int main(void)
{
// Message buffer
char buf[BUFLEN];
printf("%s, %s %s: Example use of a typed integer queue.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the queue.
queue *q = queue_empty(int_kill);
// Call print functions to show the content of the queue
print_and_wait(q, "The queue is empty");
print_internal_and_wait(q, "The queue is empty");
for (int i = 11; i <= 13; i++) {
int *v = int_create(i);
q = queue_enqueue(q, v);
snprintf(buf, BUFLEN, "The value %d was added to the queue", i);
print_and_wait(q, buf);
print_internal_and_wait(q, buf);
}
int *w = queue_front(q);
printf("The value at the front of the queue is: %d.\n", *w);
// Remove one element from the queue.
q = queue_dequeue(q);
snprintf(buf, BUFLEN, "The front element was removed from the queue");
print_and_wait(q, buf);
print_internal_and_wait(q, buf);
w = queue_front(q);
printf("The value at the front of the queue is now: %d.\n", *w);
// Kill queue. Strictly not necessary for int_queue since it
// does not use any dynamic memory. Included for symmetry with
// queue.c.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,89 @@
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
/*
* Minimum working example for queue.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-14"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v=malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p=v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer queue without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the queue.
queue *q=queue_empty(NULL);
for (int i = 11; i <= 13; i++) {
// Allocate memory for one int.
int *v = int_create(i);
// Put value in queue.
q=queue_enqueue(q,v);
}
printf("--QUEUE before dequeueing--\n");
queue_print(q, print_int);
// Get value on top of queue.
int *v=queue_front(q);
// Remote element from queue.
q=queue_dequeue(q);
// Return memory
int_kill(v);
printf("--QUEUE after dequeueing--\n");
queue_print(q, print_int);
// Now we must empty the queue and free each value ourselves.
while (!queue_is_empty(q)) {
// Get value from top of queue.
int *v=queue_front(q);
// Remove element from queue.
q=queue_dequeue(q);
// Free value
int_kill(v);
}
// Finally, destroy the bare queue.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

134
OU4/src/queue/queue_mwe1i.c Normal file
View File

@@ -0,0 +1,134 @@
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
/*
* Minimum working example for queue.c that shows how the internal
* structure of a queue can be visualized. In this version, the queue
* "borrows" the payload memory, i.e., the user of the queue is
* responsible for deallocating the payload memory. See queue_mwe2i.c
* for a version where the queue takes over the responsibility.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2024-03-14: First public version.
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
*/
#define VERSION "v1.1"
#define VERSION_DATE "2024-03-15"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v = malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p = v; // Convert to a readable pointer - useful in a debugger
free(p);
}
// Print cut lines before and after a call queue_print_internal.
void print_internal_with_cut_lines(const queue *q, const char *desc)
{
// Internal counter that will be remembered between calls.
// Used to generate sequentially numbered -- CUT HERE -- marker lines
// to enable automatic parsing of the output.
static int cut = 1;
// Print starting marker line.
printf("\n--- START CUT HERE %d ---\n", cut);
// Call the internal print function to get the actual dot code.
queue_print_internal(q, print_int, desc, 0);
// Print ending marker line
printf("--- END CUT HERE %d ---\n\n", cut);
// Increment the cut number. Will be remembered next time the
// function is called since cut is a static variable.
cut++;
}
// Print a message with intructions how to use the dot output. prog is
// the name of the executable.
void print_dot_usage(char *prog)
{
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
printf("Use\n\n%s ", prog);
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
printf("The generated file can then be visualized with\n\n");
printf("firefox /tmp/dot.svg\n\n");
printf("Use -Tpng to generate a .png file instead. "
"See graphviz.org and %s for documentation.\n", __FILE__);
printf("\n--- Start of normal output ---\n\n");
}
int main(int argc, char *argv[])
{
printf("%s, %s %s: Create integer queue without kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
print_dot_usage(argv[0]);
// Create the queue.
queue *q = queue_empty(NULL);
printf("Empty queue from the outside:\n");
queue_print(q, print_int);
print_internal_with_cut_lines(q, "Empty queue showing the internal structure");
for (int i = 11; i <= 13; i++) {
// Allocate memory for one int.
int *v = int_create(i);
// Put value in queue.
q = queue_enqueue(q, v);
}
printf("Queue from the outside after inserting 3 values:\n");
queue_print(q, print_int);
const char *long_desc = __FILE__
": Internal structure of the Queue after inserting 3 values.\n"
"All data is stored internally using a List.\n"
"Red lines are used for the queue payload.\n\n"
"The dashed red lines indicate that the payload memory is\n"
"BORROWED by the queue, i.e., the payload\n"
"memory will NOT be deallocated by the queue.\n\n"
"See queue_mwe2i for a queue example\nthat owns the payload memory.";
print_internal_with_cut_lines(q, long_desc);
// Now we must empty the queue and free each value ourselves.
while (!queue_is_empty(q)) {
// Get value from top of queue.
int *v = queue_front(q);
// Remove element from queue.
q = queue_dequeue(q);
// Free value
int_kill(v);
}
// Finally, destroy the bare queue.
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

View File

@@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
#include <queue.h>
/*
* Minimum working example for queue.c.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
* Adam Dahlgren Lindstrom (dali@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.1 2018-04-03: Split into versions with/without memhandler.
* v1.2 2023-01-14: Added printouts at start/end of main.
* v1.3 2024-03-14: Added explicit create/kill functions.
*/
#define VERSION "v1.3"
#define VERSION_DATE "2024-03-14"
// Integers are stored via int pointers stored as void pointers.
// Convert the given pointer and print the dereferenced value.
void print_int(const void *data)
{
const int *v = data;
printf("%d", *v);
}
// Create a dynamic copy of the integer i.
int *int_create(int i)
{
// Allocate memory for an integer and set the value
int *v=malloc(sizeof(*v));
*v = i;
return v;
}
// Return the memory used by the integer.
void int_kill(void *v)
{
int *p=v;
free(p);
}
int main(void)
{
printf("%s, %s %s: Create integer queue with kill_function.\n",
__FILE__, VERSION, VERSION_DATE);
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
// Create the queue.
queue *q = queue_empty(int_kill);
for (int i = 11; i <= 13; i++) {
// Allocate memory for one int.
int *v = int_create(i);
// Put value in queue.
q=queue_enqueue(q,v);
}
printf("--QUEUE before dequeueing--\n");
queue_print(q, print_int);
// Dequeue one element. The payload memory will be automatically returned.
queue_dequeue(q);
printf("--QUEUE after dequeueing--\n");
queue_print(q, print_int);
queue_kill(q);
printf("\nNormal exit.\n\n");
return 0;
}

Some files were not shown because too many files have changed in this diff Show More