week 4 tasks

This commit is contained in:
Peter 2021-08-14 14:23:24 +08:00
parent 28dd17cbcc
commit b8a0d87ee0
11 changed files with 546 additions and 0 deletions

3
Week 4/README.md Normal file
View File

@ -0,0 +1,3 @@
# Week 3
Lab sheet: https://web.archive.org/web/20210813101313/https://teaching.csse.uwa.edu.au/units/CITS2002/labsheets/labsheet3.php

View File

@ -0,0 +1,39 @@
/*
* A palindrome is a word that reads the same forwards as it does backwards. For
example, the words noon and madam are palindromes. Write a function named
isPalindrome() which determines if a string, supplied as the single character
array argument to the function, is a palindrome or not, returning a Boolean.
Use the strlen() function to determine the length of the argument string.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
bool isPalindrome(char const str[]) {
int str_length = strlen(str);
for (size_t i = 0; i < str_length/2; i++)
{
if (str[i] != str[str_length-i-1]) {
return false;
}
}
return true;
}
int main(int argc, char const *argv[])
{
for (size_t i = 1; i < argc; i++)
{
if (isPalindrome(argv[i]))
{
printf("yes ");
} else {
printf("no ");
}
}
printf("\n");
exit(EXIT_SUCCESS);
return 0;
}

View File

@ -0,0 +1,52 @@
/*
* A computer password is often consider "safe" (i.e. hard to guess) if it
contains a mixture of uppercase and lowercase characters and digits. Write a
function named isSafe() to determine if a potential password (a string) has at
least two uppercase characters, two lowercase characters, and two digits. Your
function should take a single character array as its argument and return a
Boolean value to indicate whether the password is considered safe or not.
* See the online documentation (man pages) for help with the isalpha(),
islower(), and isupper() functions. Include the appropriate header file
<ctype.h> into your program.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
bool isSafe(char const passwd[]) {
size_t i = 0;
unsigned int uppercase = 0;
unsigned int lowercase = 0;
unsigned int digit = 0;
while (passwd[i] != '\0')
{
if (isalpha(passwd[i])) {
if (isupper(passwd[i])) {
uppercase++;
} else {
lowercase++;
}
} else {
digit++; //Assume non-alphabet characters as digits
}
i++;
}
return uppercase > 1 && lowercase > 1 && digit > 1;
}
int main(int argc, char const *argv[])
{
for (size_t i = 1; i < argc; i++)
{
if (isSafe(argv[i])) {
printf("safe ");
} else {
printf("unsafe ");
}
}
printf("\n");
exit(EXIT_SUCCESS);
return 0;
}

99
Week 4/easy_tasks/rand.c Normal file
View File

@ -0,0 +1,99 @@
/*
* Each call to the standard C11 function rand() returns a different random
integer. Running the same program multiple times results in exactly the same
sequence of random integers. While this is generally unexpected ("hey, they
are not random"!), it is very helpful for debugging programs without the
randomness.
* We can provide each execution with a more random sequence of random numbers by
seeding the random number generator with the C statement srand( time(NULL) );
* Write a simple program to fill an array of 10 integers with random numbers
from rand(). Run the program several times, printing the contents of the
array.
* Now, use srand() to seed the generation of random numbers. Run the program
several times, printing the contents of the array.
* Extend your program by passing the initialised array to another function
which finds and prints the largest value in the array.
* Finally, extend the program's function to place the array's largest value
into the array's first element (index position 0), "pushing" all other
values down in the array (01, 12, 23, and so on).
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARRAY_LENGTH 10
void randomize_array(int arr_len, int arr[])
{
for (size_t i = 0; i < arr_len; i++)
{
arr[i] = rand();
}
}
int max(int arr_len, int arr[])
{
int max = -__INT32_MAX__;
for (size_t i = 0; i < arr_len; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
return max;
}
int count(int arr_len, int arr[], int n) {
int count = 0;
for (size_t i = 0; i < arr_len; i++)
{
if (arr[i] == n)
{
count++;
}
}
return count;
}
// Implementation will account for very rare occurence of duplicate max values.
// (even though it is very, VERY unlikely).
int shift_max(int arr_len, int arr[]) {
int arr_[arr_len];
memcpy(arr_, arr, sizeof(int)*arr_len);
int m = max(arr_len, arr);
int m_count = count(arr_len, arr, m);
int idx = m_count;
for (size_t i = 0; i < m_count; i++)
arr[i] = m;
for (size_t i = 0; i < arr_len; i++)
{
if (arr_[i] != m)
{
arr[idx] = arr_[i];
idx++;
}
}
}
int main(void)
{
srand(time(NULL));
int rand_arr[ARRAY_LENGTH];
randomize_array(ARRAY_LENGTH, rand_arr);
shift_max(ARRAY_LENGTH, rand_arr);
printf("Max: %d\n", max(ARRAY_LENGTH, rand_arr));
for (size_t i = 0; i < ARRAY_LENGTH; i++)
{
printf("%d ", rand_arr[i]);
}
printf("\n");
exit(EXIT_SUCCESS);
return 0;
}

View File

@ -0,0 +1,63 @@
/*
* Write a function named my_strcmp() to determine if one string is
(lexicographically, or alphabetically) less than, equal to, or greater than
another string. Your function should accept the two character arrays as its
arguments, and return either: -1 if the first string is less than the second
string, 0 if the two strings are equal, or 1 if the first string is greater
than the second string.
* Call your function from the main() function with the code:
my_strcmp(argv[1], argv[2]).
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// Note that in many programming languages, uppercase characters have a lower
// value than lowercase characters.
int alphabet_index(char c) {
if (isalpha(c))
{
if (isupper(c)) {
return c - 'A';
} else {
return c - 'a' + 26;
}
}
return 0;
}
int my_strcmp(char s1[], char s2[]) {
int s1_len = strlen(s1);
int s2_len = strlen(s2);
size_t i = 0;
while (s1[i] != '\0' && s2[i] != '\0')
{
int s1_idx = alphabet_index(s1[i]);
int s2_idx = alphabet_index(s2[i]);
if (s1_idx > s2_idx) {
return 1;
} else if (s1_idx < s2_idx) {
return -1;
}
i++;
}
if (s1_len > s2_len) {
return 1;
} else if (s2_len > s1_len) {
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("Only two strings for comparison allowed\n");
exit(EXIT_FAILURE);
}
printf("%d\n",my_strcmp(argv[1], argv[2]));
return 0;
}

View File

@ -0,0 +1,31 @@
/*
* Write a function named my_strlen() that calculates and returns the length of a
string. Your function should take one argument, a character array that
represents the string, and return an integer - the length of the string. The
calling function (the main() function) should print the integer returned by
your my_strlen() function.
* Test your function with some string constants and by passing to it some
command-line arguments.
*/
#include <stdio.h>
#include <stdlib.h>
int my_strlen(char const str[]) {
int i = 0;
while (str[i] != '\0')
{
i++;
}
return i;
}
int main(int argc, char const *argv[])
{
for (size_t i = 1; i < argc; i++)
{
printf("%d ", my_strlen(argv[i]));
}
printf("\n");
return 0;
}

42
Week 4/multistat/stat.c Normal file
View File

@ -0,0 +1,42 @@
/*
* 🌶 Lecture 6 introduced C11's structures and presented an example of how
application programs can request and receive information from the underlying
operating system The example involved the gettimeofday() system-call and the
struct timeval structure.
* Similarly, applications can determine information about a file's attributes
using the stat() system-call and the struct stat structure. Note that we need
to read Section 2 of the online manual:
prompt> man 2 stat
otherwise we'll receive the documentation from Section 1.
* Write a program which accepts a number of filenames on the command-line, and
prints (just as an integer) the modification-time of each file.
* Now, extend the program to also print each file's size (in bytes) and the
(more useful string) modification-time of each file, using the ctime()
function.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
int main(int argc, char const *argv[])
{
struct stat *stat_result;
stat_result = malloc(sizeof(struct stat));
for (size_t i = 1; i < argc; i++)
{
stat(argv[i], stat_result);
const time_t *mod_time = &(stat_result->st_mtim).tv_sec;
char *time_human_readable = ctime(mod_time);
printf("File \"%s\":\n", argv[i]);
printf(" => last_modified: %s", time_human_readable);
printf(" => size: %ld\n\n", stat_result->st_size);
}
return 0;
}

118
Week 4/replace/replace.c Normal file
View File

@ -0,0 +1,118 @@
/*
* 🌶 Write a function named replace() that replaces all instances of one string
for another string in a third string. For example:
prompt> ./replace red blue aredrobin
abluerobin
prompt> ./replace cat bison catocathartic
bisonobisonhartic
* A reasonable prototype for the function is:
void replace( char oldword[], char newword[], char whole_sentence[] );
* Ensure you have terminated your string correctly.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool __match(int m_len, char m[], char s_len, char s[], int start)
{
int offset = start + m_len;
if (offset <= s_len)
{
int idx = 0;
for (int i = start; i < offset; i++)
{
if (m[idx] != s[i])
{
return false;
}
idx++;
}
return true;
}
return false;
}
// assume match and replacement length > 0
void replace(char match[], char replacement[], char string[])
{
int match_length = strlen(match);
int replacement_length = strlen(replacement);
int string_length = strlen(string);
int positions[string_length]; // easy solution - probably memory wasteful
int valid_positions[string_length];
memset(positions, -1, sizeof positions);
memset(valid_positions, -1, sizeof valid_positions);
int idx = 0;
int idx_v = 0;
int idx_new = 0;
int last_position = -__INT32_MAX__;
// get possible positions.
for (int i = 0; i < string_length; i++)
{
if (string[i] == match[0])
{
positions[idx] = i;
idx++;
}
}
// get valid positions for replacement.
idx = 0;
do
{
int position = positions[idx];
if (__match(match_length, match, string_length, string, position))
{
// prevent overlapping matches
if (position > last_position + match_length) {
valid_positions[idx_v] = position;
last_position = position;
idx_v++;
}
}
idx++;
} while (positions[idx] != -1);
// make new string
char new_string[string_length + idx_v*(match_length - replacement_length)];
idx = 0;
idx_v = 0;
while (string[idx] != '\0')
{
if (idx == valid_positions[idx_v]) {
idx_v++;
idx += match_length-1;
for (size_t i = 0; i < replacement_length; i++)
{
new_string[idx_new] = replacement[i];
idx_new++;
}
} else {
new_string[idx_new] = string[idx];
idx_new++;
}
idx++;
}
new_string[idx_new] = '\0';
strcpy(string, new_string);
}
int main(int argc, char *argv[])
{
if (argc != 4)
{
printf("Error - only three arguments allowed\nreplace pattern replacement string\n");
exit(EXIT_FAILURE);
}
replace(argv[1], argv[2], argv[3]);
printf("%s\n", argv[3]);
return 0;
}

View File

@ -0,0 +1,65 @@
/*
* 🌶 🌶 🌶 If you had to write some code that iterated through all the
possibilities for three variables in the range 0 to 10, you would probably
write code similar to:
for(int a = 0; a < 10; ++a) {
for(int b = 0; b < 10; ++b) {
for(int c = 0; c < 10; ++c) {
; // LOOP-BODY USING a, b, AND c
}
}
}
But what if you had to extend this to 4, 5, or even 10+ "nested" loops?
Instead of further nesting more loops, it is possible to write a function that
acts as a "superloop", performing the equivalent of n nested loops with just
one loop. Write a function to do this, taking an argument n that indicates the
number of nested loops your function should perform. To do this, you will need
to keep a 1-dimensional array of n values that maintain the state of each loop
during the execution of your function.
*/
#include <stdlib.h>
#include "superloop.h"
struct __superloop_state {
void (*function)(int, int (*)[]);
int (*value)[];
int level;
int depth;
int start;
int end;
int increment;
};
void __loop(struct __superloop_state *state)
{
if (state->level < state->depth)
{
for (int i = state->start; i < state->end; i += state->increment)
{
(*state->value)[state->level] = i;
state->level++;
__loop(state);
state->level--;
}
} else {
(*state->function)(state->depth, state->value);
}
}
void superloop(int depth, int start, int end, int increment, void (*function)(int, int (*)[]))
{
int (*value)[depth];
value = malloc(depth*sizeof(int));
struct __superloop_state state = {
function,
value,
0,
depth,
start,
end,
abs(increment)
};
__loop(&state);
}

View File

@ -0,0 +1,6 @@
#ifndef _SUPERLOOP_H
#define _SUPERLOOP_H
extern void superloop(int depth, int start, int end, int increment, void (*function)(int, int (*)[]));
#endif

View File

@ -0,0 +1,28 @@
// see superloop.c for information
// remember to add ./superloop.c to gcc for this to compile!
#include <stdio.h>
#include <stdlib.h>
#include "superloop.h"
void func(int length, int (*values)[]) {
for (size_t i = 0; i < length; i++)
{
printf("%d ", (*values)[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
if (argc != 5)
{
printf("Expected 4 arguments\ntest_superloop <loop_depth> <start> <end> <increment>\n");
exit(EXIT_FAILURE);
}
superloop(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), func);
exit(EXIT_SUCCESS);
return 0;
}