diff --git a/.gitignore b/.gitignore index ca8a6c5..8eeceec 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ !*/ *.out -.vscode/ \ No newline at end of file +.vscode/ + +concordance/ \ No newline at end of file diff --git a/Week 8/4_str/README.md b/Week 8/4_str/README.md new file mode 100644 index 0000000..7e34fba --- /dev/null +++ b/Week 8/4_str/README.md @@ -0,0 +1,20 @@ +Using the example strlen() and strcpy() functions of Lecture 13 as a guide, write pairs of functions to implement versions of the following standard C functions: +* strcat +* strcmp +* strncmp +* strchr +* strrchr +* 🌶 strpbrk +* 🌶 🌶 strstr + +Maintain two separate C source files for this task: one file for the array-based versions of each function (named arrays.c), and one file for the pointer-based versions (named pointers.c). Develop two separate header files, one containing the prototypes of the array-based functions (named arrays.h), and the other containing the prototypes of the pointer-based functions (named pointers.h). + +Create a single testing program named stringtest.c, containing the only main() function for this question, that tests each of the functions you write. The file stringtest.c should include both of your header files. +Approach the writing of each function by following these steps: +Firstly, read the appropriate online Linux manual entry for each function (e.g. run man strcat). Pay particular attention to the parameters of the function and its return value. Note that the online documentation will frequently use the (as yet not explained) keywords const and restrict. For now, simply ignore these and do not reproduce them in your functions (ask a demonstrator if interested in what they're for). + +Next, develop a version of each function using arrays (not pointers), in arrays.c, As an example, name your first function strcat_a(). + +Write a short test function in stringtest.c file that calls your new function several times to test its execution. Depending on the function being tested, suitable parameters to the function will include simple short strings, long strings, empty strings, identical strings (when comparing them), very different strings, strings differing in only a single character, and strings containing, or otherwise, a required character (for strchr). + +Next, develop a version of each function using pointers (not arrays) in pointers.c. As an example, name your first function strcat_p(). Undertake the same tests on your pointer-based functions as you did on your array-based ones. \ No newline at end of file diff --git a/Week 8/4_str/arrays.c b/Week 8/4_str/arrays.c new file mode 100644 index 0000000..ba29da6 --- /dev/null +++ b/Week 8/4_str/arrays.c @@ -0,0 +1,98 @@ + +#include +#include +#include +#include +#include + +#include "arrays.h" + +// the dest string must have enough space for the result. If dest is not large +// enough, program behavior is unpredictable +char *strcat_a(char dest[], char src[]) +{ + size_t src_len = strlen(src); + size_t dest_len = strlen(dest); + for (size_t i = 0; i < src_len; i++) { + dest[i + dest_len] = src[i]; + } + dest[src_len + dest_len] = '\0'; + return dest; +} + +int strncmp_a(char s1[], char s2[], size_t n) +{ + size_t i = 0; + while ( (s1[i] != '\0' || s2[i] != '\0') && i < n ) { + if (s1[i] != s2[i]) { + return s1[i] - s2[i]; + } + i++; + } + return 0; +} + +int strcmp_a(char s1[], char s2[]) +{ + return strncmp_a(s1, s2, SIZE_MAX); +} + +char *strchr_a(char s[], int c) +{ + size_t str_len = strlen(s); + for (size_t i = 0; i < str_len; i++) { + if (s[i] == c) { + return &s[i]; + } + } + return NULL; +} + +char *strrchr_a(char s[], int c) +{ + for (size_t i = strlen(s)-1; i >= 0; i--) { + if (s[i] == c) { + return &s[i]; + } + } + return NULL; +} + +char *strpbrk_a(char s[], char accept[]) +{ + size_t i = 0; + size_t accept_len = strlen(accept); + while (s[i] != '\0') { + for (size_t j = 0; j < accept_len; j++) { + if (s[i] == accept[j]) { + return &s[i]; + } + } + i++; + } + return NULL; +} + +bool __substring_match__(char str[], char substr[], size_t start) +{ + size_t i = 0; + while (substr[i] != '\0') { + if (str[i+start] != substr[i]) { + return false; + } + i++; + } + return true; +} + +char *strstr_a(char haystack[], char needle[]) +{ + size_t i = 0; + while (haystack[i] != '\0') { + if (__substring_match__(haystack,needle,i)) { + return &haystack[i]; + } + i++; + } + return NULL; +} diff --git a/Week 8/4_str/arrays.h b/Week 8/4_str/arrays.h new file mode 100644 index 0000000..4031322 --- /dev/null +++ b/Week 8/4_str/arrays.h @@ -0,0 +1,18 @@ +#ifndef _STR_ARRAYS_H +#define _STR_ARRAYS_H + +extern char *strcat_a(char dest[], char src[]); + +extern int strncmp_a(char s1[], char s2[], size_t n); + +extern int strcmp_a(char s1[], char s2[]); + +extern char *strchr_a(char s[], int c); + +extern char *strrchr_a(char s[], int c); + +extern char *strpbrk_a(char s[], char accept[]); + +extern char *strstr_a(char haystack[], char needle[]); + +#endif \ No newline at end of file diff --git a/Week 8/4_str/pointers.c b/Week 8/4_str/pointers.c new file mode 100644 index 0000000..f592eea --- /dev/null +++ b/Week 8/4_str/pointers.c @@ -0,0 +1,100 @@ + +#include +#include +#include +#include +#include + +// the dest string must have enough space for the result. If dest is not large +// enough, program behavior is unpredictable +char *strcat_p(char *dest, char *src) +{ + char *return_ptr = dest; + dest += strlen(src); + while (*src != '\0') + { + *dest = *src; + dest++; + src++; + } + *dest = '\0'; + return return_ptr; +} + +int strncmp_p(char *s1, char *s2, size_t n) +{ + size_t i = 0; + while ( (*s1 != '\0' || *s2 != '\0') && i < n ) { + if (*s1 != *s2) { + return *s1 - *s2; + } + s1++; + s2++; + i++; + } + return 0; +} + +int strcmp_p(char *s1, char *s2) +{ + return strncmp_p(s1, s2, SIZE_MAX); +} + +char *strchr_p(char *s, int c) +{ + while (*s != '\0') { + if (*s == c) { + return s; + } + s++; + } + return NULL; +} + +char *strrchr_p(char *s, int c) +{ + char *s_ = *s + strlen(s) - 1; + while (s_ >= s) { + if (*s == c) { + return s; + } + s--; + } + return NULL; +} + +char *strpbrk_p(char *s, char *accept) +{ + size_t accept_len = strlen(accept); + while (*s != '\0') { + for (char *c = accept; c < accept+accept_len; c++) { + if (*s == *c) { + return s; + } + } + } + return NULL; +} + +bool __substring_match__(char *haystack_start, char *needle) +{ + while (*needle != '\0') { + if (*haystack_start != *needle) { + return false; + } + haystack_start++; + needle++; + } + return true; +} + +char *strstr_p(char *haystack, char *needle) +{ + while (*haystack != '\0') { + if (__substring_match__(haystack,needle)) { + return haystack; + } + haystack++; + } + return NULL; +} diff --git a/Week 8/4_str/pointers.h b/Week 8/4_str/pointers.h new file mode 100644 index 0000000..1da08c9 --- /dev/null +++ b/Week 8/4_str/pointers.h @@ -0,0 +1,18 @@ +#ifndef _STR_POINTERS_H +#define _STR_POINTERS_H + +extern char *strcat_p(char *dest, char *src) + +extern int strncmp_p(char *s1, char *s2, size_t n) + +extern int strcmp_p(char *s1, char *s2) + +extern char *strchr_p(char *s, int c) + +extern char *strrchr_p(char *s, int c) + +extern char *strpbrk_p(char *s, char *accept) + +extern char *strstr_p(char *haystack, char *needle) + +#endif \ No newline at end of file diff --git a/Week 8/4_str/stringtest.c b/Week 8/4_str/stringtest.c new file mode 100644 index 0000000..1864f09 --- /dev/null +++ b/Week 8/4_str/stringtest.c @@ -0,0 +1,79 @@ + +#include +#include +#include +#include "arrays.h" +#include "pointers.h" + +void print_cmp(char s1[], char s2[], int n) +{ + if (n == 0) { + printf("strcmp(%s,%s) = %i\n", s1, s2, strcmp(s1, s2)); + printf("\tstrcmp_a(%s,%s) = %i\n", s1, s2, strcmp_a(s1, s2)); + } else { + printf("strncmp(%s,%s,%i) = %i\n", s1, s2, n, strncmp(s1, s2, n)); + printf("\tstrncmp_a(%s,%s,%i) = %i\n", s1, s2, n, strncmp_a(s1, s2, n)); + } +} + +void print_chr(char str[], char c) +{ + char *strchr_ptr = strchr(str, c); + printf("strchr(): V %c; PTR %lu\n", *strchr_ptr, strchr_ptr-&str[0]); + strchr_ptr = strchr_a(str, c); + printf("\tstrchr_a(): V %c; PTR %lu\n", *strchr_ptr, strchr_ptr-&str[0]); + strchr_ptr = strrchr(str, c); + printf("strrchr(): V %c; PTR %lu\n", *strchr_ptr, strchr_ptr-&str[0]); + strchr_ptr = strrchr_a(str, c); + printf("\tstrrchr_a(): V %c; PTR %lu\n", *strchr_ptr, strchr_ptr-&str[0]); +} + +void print_pbrk(char str[], char accept[]) +{ + char *strpbrk_ptr = strpbrk(str, accept); + printf("strpbrk(): V %c; PTR %lu\n", *strpbrk_ptr, strpbrk_ptr-&str[0]); + strpbrk_ptr = strpbrk_a(str, accept); + printf("\tstrpbrk_a(): V %c; PTR %lu\n", *strpbrk_ptr, strpbrk_ptr-&str[0]); +} + +void print_strstr(char haystack[], char needle[]) +{ + char *strstr_ptr = strstr(haystack, needle); + printf("strstr(): PTR %lu\n", strstr_ptr-&haystack[0]); + strstr_ptr = strstr_a(haystack, needle); + printf("\tstrstr_a(): PTR %lu\n", strstr_ptr-&haystack[0]); +} + +int main(int argc, char const *argv[]) +{ + char string_1[40] = "Hello "; + char string_2[] = "World!"; + + // TEST strcat() + char *dest = strcat_a(string_1, string_2); + printf("%s\n", dest); + + // TEST strcmp() + print_cmp("ABC", "ABC", 0); + print_cmp("ABCD", "AB", 0); + print_cmp("AB", "ABC", 0); + print_cmp("ABA", "ABZ", 0); + print_cmp("ABJ", "ABC", 0); + + // TEST strncmp() + print_cmp("ABC", "AB", 3); + print_cmp("ABC", "AB", 2); + + // TEST strchr(), strrchr() + char string_3[] = "Sussy susser"; + print_chr(string_3,'u'); + + // TEST strpbrk() + print_pbrk(string_3,"yer"); + print_pbrk(string_3,"s"); + + // TEST strstr() + print_strstr(string_3,"sus"); + print_strstr(string_3,"ss"); + return 0; +} diff --git a/Week 8/7_sort_pointers/7_sort_pointers.c b/Week 8/7_sort_pointers/7_sort_pointers.c new file mode 100644 index 0000000..9f64ef1 --- /dev/null +++ b/Week 8/7_sort_pointers/7_sort_pointers.c @@ -0,0 +1,77 @@ +/* +* 🌶 🌶 Write a function named sortPointers() that sets an array of integer + pointers to point to the elements of another array in ascending order. +* Your function should accept three parameters: the array of integers, the array + of integer pointers to assign, and the integer count of the number of elements + in the array, and hence should have the prototype: + void sortPointers(int src[], int *ptrs[], int n); + +* Your function should not change the original array, nor create any other + arrays in completing this task. +*/ + +#include +#include +#include +#include + +#define TEST_LENGTH 16 + +void swap_pointers(int **a, int **b) +{ + int *tmp = *a; + *a = *b; + *b = tmp; +} + +bool sorted(int *ptrs[], int n) +{ + for (size_t i = 1; i < n; i++) { + if (*ptrs[i-1] > *ptrs[i]) { + swap_pointers(&ptrs[i-1],&ptrs[i]); + return false; + } + } + return true; +} + +// V. SLOW SORT +void sortPointers(int src[], int *ptrs[], int n) +{ + for (size_t i = 0; i < n; i++) { + ptrs[i] = &src[i]; + } + while (!sorted(ptrs,n)); // KEEP SWAPPING WHILE NOT SORTED - SLOW SORT. +} + + +// TEST sortPointers() +void intialize_rand_arr(int *arr) +{ + putchar('['); + for (size_t i = 0; i < TEST_LENGTH; i++) { + int value = rand() % 512; + printf("%i, ", value); + arr[i] = value; + } + printf("]\n"); +} + +int main(int argc, char const *argv[]) +{ + srand(time(NULL)); + + int *ptrs[TEST_LENGTH]; + int src[TEST_LENGTH]; + intialize_rand_arr(src); + + + sortPointers(src, ptrs, TEST_LENGTH); + + + for (size_t i = 0; i < TEST_LENGTH; i++) { + printf("%i\t%lu\n",*ptrs[i],(long)ptrs[i]); + } + + return 0; +} diff --git a/Week 8/basic_tasks/1_money.c b/Week 8/basic_tasks/1_money.c new file mode 100644 index 0000000..40cc23d --- /dev/null +++ b/Week 8/basic_tasks/1_money.c @@ -0,0 +1,36 @@ +/* +* Write a function named money that accepts a single integer parameter that + represents a total number of cents, and breaks the total down into its numbers + of dollars and cents. Your function should calculate the number of dollars, + and the number of "left-over" cents, and provide these to its calling function + through its parameters. For example, a value of 524 should be "returned" as 5 + dollars and 24 cents. +* Your function should have the prototype: + void money(int total, int *dollars, int *cents); +* and be called as: + money(524, &dollars, ¢s); +*/ + +#include +#include + +void money(int total, int *dollars, int *cents) +{ + *dollars = total/100; + *cents = total % 100; +} + +int main(int argc, char const *argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "Usage: money [INT CENTS]\n"); + exit(EXIT_FAILURE); + } + + int dollars; + int cents; + money(atoi(argv[1]), &dollars, ¢s); + printf("%i dollars, %i cents.\n", dollars, cents); + exit(EXIT_SUCCESS); +} diff --git a/Week 8/basic_tasks/2_3_maximum_a_p.c b/Week 8/basic_tasks/2_3_maximum_a_p.c new file mode 100644 index 0000000..613faee --- /dev/null +++ b/Week 8/basic_tasks/2_3_maximum_a_p.c @@ -0,0 +1,69 @@ +/* +* Write a function named maximum_a() that accepts an integer array and the + number of elements in that array as parameters, returning a pointer to the + maximum integer in the array. It should have the prototype: + int *maximum_a(int values[], int n); +* Your function should access elements of values as an array. + +* Write a (very similar) version of the maximum_a() function that now accepts + the integer array as a pointer. It should have the prototype: + int *maximum_p(int *values, int n); +* Use *pointer arithmetic* to complete this task. +*/ + +#include +#include +#include + +#define TEST_LENGTH 16 + +int *maximum_a(int values[], int n) +{ + int *max = &values[0]; + for (size_t i = 0; i < n; i++) { + if (values[i] > *max) { + max = &values[i]; + } + } + return max; +} + +int *maximum_p(int *values, int n) +{ + int *max = &values[0]; + int *end = &values[0]+n; + for (int *v_ptr = max; v_ptr < end; v_ptr++) { + if (*v_ptr > *max) { + max = v_ptr; + } + } + return max; +} + +// TEST maximum_a() +void intialize_rand_arr(int *arr) +{ + putchar('['); + for (size_t i = 0; i < TEST_LENGTH; i++) { + int value = rand() % 512; + printf("%i, ", value); + arr[i] = value; + } + printf("]\n"); +} + +int main(int argc, char const *argv[]) +{ + srand(time(NULL)); + + int arr[TEST_LENGTH]; + intialize_rand_arr(arr); + + int *maximum_a_result = maximum_a(arr, TEST_LENGTH); + printf("maximum_a() : Maximum is %i\n", *maximum_a_result); + + int *maximum_p_result = maximum_p(arr, TEST_LENGTH); + printf("maximum_p() : Maximum is %i\n", *maximum_p_result); + + return 0; +}