Your tutor has asked a lab pair to present their week 7 work.
Discuss the good, the bad and the ugly aspects of their code.
Please be gentle in any criticism - we are all learning!
Try out the reference Castle Defense implementation: 1511 castle_defense.
The Locations are a linked list, but instead of simple ints that we've seen so far, they contain more information.
The Realm is a special struct that contains pointers to the start (Lair) and end (Castle) of the linked list of locations.
Both of these structs will need to be edited and worked with in the assignment.
Do you have questions that others in the tutorial may be able to answer?
struct overall {
struct node *start;
struct node *end;
};
struct node {
int data;
struct node *next;
};
where start
points at the first element of the
list and end
points at the last element of the
list:
overall
struct look like in
memory? What is its purpose?
node
struct look like in
memory? What is its purpose?
malloc
function do? How could
you use it to allocate memory for a single
struct node
?
new_node
that creates
a new node with the specified data value:
struct node *new_node(int data) {
}
struct node *new_node(int data) {
struct node *new = malloc(sizeof(struct node));
node->data = data;
node->next = NULL;
return node;
}
insert_at_head
that
uses your new_node
function to create a node,
and then inserts that node at the front of the linked
list.
void insert_at_front(struct overall *o, int data) {
}
void insert_at_front(struct overall *o, int data) {
struct node *new = new_node(data);
new->next = o->head;
o->head = new;
}
insert_before_end
that inserts an element
just before the end element.
void insert_before_end(struct overall *o, int data) {
}
void insert_before_end(struct overall *o, int data) {
// loop until just before the end
struct node *n = o->start;
while (n != o->end) {
n = n->next;
}
// create a new node and insert it after n
struct node *newNode = malloc(sizeof (struct node));
newNode->data = data;
newNode->next = n->next;
n->next = newNode;
}
Anything can happen when using an uninitialized variable including your program terminating immediately.
With common C implementations you'll often find a value formed from the bytes of a previous variable. This will often be zero because past values will often be part or all zeros.
As commonly zero is the value that the variable should have been initialized with, the code will seem to work.
But a slightest change to platform, compiler, the code, perhaps even just time of day, will result in the bytes being different and the program breaking.
Small simple programs, like COMP1511 lab exercises, are particularly vulnerable to this because the value of an uninitialized variable will often be formed from bytes that haven't been previously used for anything and will be hence zero.
dcc enables all the compile-time error checking options that clang offers.
dcc adds extra explanation to help you understand these error messages.
dcc also enables run-time checking of your code using a tool called Address Sanitizer. This checks, for example, that array indices are valid.
Address Sanitizer error messages are hard to understand so dcc adds code to your program to explain the error. This code uses Python and a debugging tool named gdb to give you an explanation of the error with some hopefully helpful information about the state of your program when the error occurred.
#define MAX_SPECIES_NAME_LENGTH 128 struct pod { struct date when; int how_many; char species[MAX_SPECIES_NAME_LENGTH]; };What if we use a linked list of this struct to store a whale sighting?
struct pod { struct pod *next; struct date *when; int how_many; char *species; };And a date is still represented by the same struct:
struct date { int year; int month; int day; };Sketch out how these two data structures would be laid out in memory.
Discuss the differences and how that will affect the use of this data
Arrays will be laid out adjacent in memory.
Linked Lists are potentially scattered through memory.
Arrays will be easier to loop through and sometimes to access individual elements because they can be accessed by index.
Linked Lists can be easier to modify because elements can be inserted and removed from any part of the list easily.
In addition to this, the date struct in the linked list will actually be separate in memory, linked only via a pointer.
Your tutor may still choose to cover some of the questions time permitting.
split_string
which
takes a string read by fgets containing substrings
separated by commas, places the substrings in an
char[][] array and returns the number of strings.
You can assume there are at most 128 words on the line and no word is more than 32 characters long.
print_substrings
which prints one per
line the substrings in the char[][] array created
in the previous question.
substrings_sorted
which given the
char[][] array in the previous question returns 1
if the substrings are increasing order and 0
otherwise.
search_substrings
which given the
char[][] array in the previous question returns 1
if the array contains a specified string and 0
otherwise.
substring.c
which
reads lines using fgets and calls the above
functions.
substring.c
// Written by Costa Paraskevopoulos as a
// COMP1511 tutorial solution
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NUM_WORDS 128
#define MAX_WORD_LEN 33 // including null char
// accounts for 128 * 32 "word" characters + 127 commas + 1 null char
#define MAX_LINE_LEN (MAX_NUM_WORDS * MAX_WORD_LEN)
int split_string(char *src,
char dest[MAX_NUM_WORDS][MAX_WORD_LEN]);
void print_substrings(int num_substrings,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]);
int substrings_sorted(int num_substrings,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]);
int search_substrings(int num_substrings, char *search_str,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]);
int main(int argc, char *argv[]) {
char line[MAX_LINE_LEN];
int line_no = 1;
while (fgets(line, MAX_LINE_LEN, stdin) != NULL) {
char substrings[MAX_NUM_WORDS][MAX_WORD_LEN];
int num_words = split_string(line, substrings);
printf("%d words on line %d:\n", num_words, line_no);
print_substrings(num_words, substrings);
if (substrings_sorted(num_words, substrings) != 0) {
printf("Substrings are in increasing order\n");
} else {
printf("Substrings are not in increasing order\n");
}
// search for some common test strings
char *searches[4] = {"hello", "world", "test", "qwerty"};
for (int i = 0; i < 4; i = i + 1) {
if (search_substrings(num_words, searches[i], substrings)) {
printf("Found \"%s\" on line %d\n", searches[i], line_no);
} else {
printf("\"%s\" not found on line %d\n", searches[i], line_no);
}
}
printf("\n");
line_no = line_no + 1;
}
return 0;
}
// Extracts words separated by commas and places them in dest
int split_string(char *src, char dest[MAX_NUM_WORDS][MAX_WORD_LEN]) {
int num_words = 0;
int i, j;
for (i = 0; i < MAX_LINE_LEN && num_words != MAX_NUM_WORDS; i = i + 1) {
// reached end of src
if (src[i] == '\n' || src[i] == '\0') {
break;
}
// copy current word over to dest
for (j = i; j - i < MAX_WORD_LEN - 1; j = j +1) {
if ((src[j] == ',' || src[j] == '\n' || src[j] == '\0') && i != j) {
dest[num_words][j - i] = '\0';
num_words = num_words + 1;
i = j; // start next word
break;
} else if (src[j] == ',') {
break; // skip empty words
}
dest[num_words][j - i] = src[j];
}
// terminate long word
if (i != j) {
dest[num_words][j - i] = '\0';
num_words = num_words + 1;
i = j;
// skip rest of word
while (src[i] != '\0' && src[i] != '\n' && src[i] != ',') {
i = i + 1;
}
}
}
return num_words;
}
// Prints all words in strings on separate lines
void print_substrings(int num_substrings,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]) {
for (int i = 0; i < num_substrings; i = i + 1) {
printf("%s\n", strings[i]);
}
}
// Returns 1 if strings is sorted; 0 otherwise
int substrings_sorted(int num_substrings,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]) {
for (int i = 1; i < num_substrings; i = i + 1) {
if (strcmp(strings[i], strings[i - 1]) < 0) {
return 0;
}
}
return 1;
}
// Returns 1 if search_str is in strings; 0 otherwise
int search_substrings(int num_substrings, char *search_str,
char strings[MAX_NUM_WORDS][MAX_WORD_LEN]) {
for (int i = 0; i < num_substrings; i = i + 1) {
if (strcmp(strings[i], search_str) == 0) {
return 1;
}
}
return 0;
}
struct date
pointers and compares returns 0
if they are equal, -1 if the first is less than the second
and 1 if the first is larger than the second.
int compare_date(struct date *d1, struct date *d2);