├── src ├── sample.bmp ├── sample_gray_10.bmp ├── sample_gray_20.bmp ├── sample_gray_30.bmp ├── sample_gray_5.bmp ├── sample_gray_50.bmp ├── 3_pi.c ├── 9_factorization.c ├── 2_numerical_derivatives.c ├── 5_complex_numbers.c ├── 8_shortest_path.c ├── 4_union_find.c ├── 10_performance_comparison_of_sorting_algorithm.c ├── 1_sequential_sorting.c ├── 6_linear_algebra.c ├── 12_text_processor.c ├── 14_generic_sorting.c ├── 11_image_segmentation.c ├── 1_sequential_sorting_string.c ├── 7_adjacency_matrix.c ├── 13_generic_derivative.c ├── 18_parallel_sorting_with_threads.c ├── 15_text_processing_in_strings.c ├── 17_text_processor_sophistication.c └── 16_text_processing_in_streams.c └── README.md /src/sample.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample.bmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modern-C 2 | <Modern C> of Jens Gustedt, code for challenge problems 3 | -------------------------------------------------------------------------------- /src/sample_gray_10.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample_gray_10.bmp -------------------------------------------------------------------------------- /src/sample_gray_20.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample_gray_20.bmp -------------------------------------------------------------------------------- /src/sample_gray_30.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample_gray_30.bmp -------------------------------------------------------------------------------- /src/sample_gray_5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample_gray_5.bmp -------------------------------------------------------------------------------- /src/sample_gray_50.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozenca/Modern-C/HEAD/src/sample_gray_50.bmp -------------------------------------------------------------------------------- /src/3_pi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static size_t const ITERATION_LIMIT = 100000; 7 | 8 | #define PI 3.14159265358979323846 9 | 10 | void approx_pi(size_t precision) { 11 | double sqrt12 = sqrt(12.0); 12 | assert(precision); 13 | double value = 0.0; 14 | size_t k = 0; 15 | printf("Approximate pi by %zu digits\n", precision - 1); 16 | while (k < ITERATION_LIMIT) { 17 | value += sqrt12 / ((2.0 * k + 1.0) * pow(-3.0, k)); 18 | printf("At iteration %zu, the value is %.16f, ", k, value); 19 | double error = fabs(value - PI); 20 | printf("error is %.16f\n", error); 21 | if (error < pow(0.1, precision)) { 22 | printf("Done!\n"); 23 | break; 24 | } 25 | k++; 26 | } 27 | } 28 | 29 | int main() { 30 | approx_pi(5); 31 | approx_pi(11); 32 | return EXIT_SUCCESS; 33 | } 34 | -------------------------------------------------------------------------------- /src/9_factorization.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool is_prime(size_t p) { 8 | assert(p > 1); 9 | if (p == 2) return true; 10 | for (size_t i = 3; i <= sqrt(p); i += 2) { 11 | if (p % i == 0) return false; 12 | } 13 | return true; 14 | } 15 | 16 | void factorize_recur(size_t n) { 17 | if (n % 2 == 0) { 18 | printf("2 "); 19 | while (n % 2 == 0) { 20 | n /= 2; 21 | } 22 | } 23 | for (size_t i = 3; i <= n; i += 2) { 24 | if (is_prime(i) && (n % i == 0)) { 25 | printf("%zu ", i); 26 | while (n % i == 0) { 27 | n /= i; 28 | } 29 | factorize_recur(n); 30 | break; 31 | } 32 | } 33 | } 34 | 35 | void factorize(size_t n) { 36 | printf("%zu: ", n); 37 | factorize_recur(n); 38 | printf("\n"); 39 | } 40 | 41 | int main(int argc, char* argv[argc + 1]) { 42 | for (size_t i = 1; i < argc; i++) { 43 | char* end = 0; 44 | size_t n = strtoull(argv[i], &end, 10); 45 | factorize(n); 46 | } 47 | return EXIT_SUCCESS; 48 | } -------------------------------------------------------------------------------- /src/2_numerical_derivatives.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static double const eps = 1.0e-7; 7 | 8 | #define PI 3.14159265358979323846 9 | 10 | double derivative(double F(double), double x) { 11 | double x_p = x + eps; 12 | double x_m = x - eps; 13 | return (F(x_p) - F(x_m)) / (x_p - x_m); 14 | } 15 | 16 | double is_almost_equal(double a, double b, double epsilon) { 17 | return fabs(a - b) < epsilon; 18 | } 19 | 20 | int main() { 21 | double point_0 = 0.0, point_1 = PI / 2, point_2 = 4; 22 | 23 | double sin_d_0 = derivative(sin, point_0); 24 | assert(is_almost_equal(sin_d_0, cos(point_0), eps)); 25 | printf("Derivative of sin at %g : %g\n", point_0, sin_d_0); 26 | 27 | double sin_d_1 = derivative(sin, point_1); 28 | assert(is_almost_equal(sin_d_1, cos(point_1), eps)); 29 | printf("Derivative of sin at %g : %g\n", point_1, sin_d_1); 30 | 31 | double cos_d_0 = derivative(cos, point_0); 32 | assert(is_almost_equal(cos_d_0, -sin(point_0), eps)); 33 | printf("Derivative of cos at %g : %g\n", point_0, cos_d_0); 34 | 35 | double cos_d_1 = derivative(cos, point_1); 36 | assert(is_almost_equal(cos_d_1, -sin(point_1), eps)); 37 | printf("Derivative of cos at %g : %g\n", point_1, cos_d_1); 38 | 39 | double sqrt_d_2 = derivative(sqrt, point_2); 40 | assert(is_almost_equal(sqrt_d_2, 1 / (2.0 * sqrt(point_2)), eps)); 41 | printf("Derivative of sqrt at %g : %g\n", point_2, sqrt_d_2); 42 | 43 | return EXIT_SUCCESS; 44 | } -------------------------------------------------------------------------------- /src/5_complex_numbers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static double const eps = 1.0e-7; 9 | 10 | #define PI 3.14159265358979323846 11 | 12 | double complex derivative(double complex F(double complex), double complex x) { 13 | double complex x_p = x + eps; 14 | double complex x_m = x - eps; 15 | return (F(x_p) - F(x_m)) / (x_p - x_m); 16 | } 17 | 18 | bool is_almost_equal(double complex a, double complex b, double epsilon) { 19 | return cabs(a - b) < epsilon; 20 | } 21 | 22 | int main() { 23 | double complex point_0 = 0.0, point_1 = PI / 2 + (PI / 2) * I, point_2 = 4 + 4 * I; 24 | 25 | double complex sin_d_0 = derivative(csin, point_0); 26 | assert(is_almost_equal(sin_d_0, ccos(point_0), eps)); 27 | printf("Derivative of sin at %g + %g i : %g + %g i\n", 28 | creal(point_0), cimag(point_0), creal(sin_d_0), cimag(sin_d_0)); 29 | 30 | double complex sin_d_1 = derivative(csin, point_1); 31 | assert(is_almost_equal(sin_d_1, ccos(point_1), eps)); 32 | printf("Derivative of sin at %g + %g i : %g + %g i\n", 33 | creal(point_1), cimag(point_1), creal(sin_d_1), cimag(sin_d_1)); 34 | 35 | double complex cos_d_0 = derivative(ccos, point_0); 36 | assert(is_almost_equal(cos_d_0, -csin(point_0), eps)); 37 | printf("Derivative of cos at %g + %g i : %g + %g i\n", 38 | creal(point_0), cimag(point_0), creal(cos_d_0), cimag(cos_d_0)); 39 | 40 | double complex cos_d_1 = derivative(ccos, point_1); 41 | assert(is_almost_equal(cos_d_1, -csin(point_1), eps)); 42 | printf("Derivative of cos at %g + %g i : %g + %g i\n", 43 | creal(point_1), cimag(point_1), creal(cos_d_1), cimag(cos_d_1)); 44 | 45 | double complex sqrt_d_2 = derivative(csqrt, point_2); 46 | assert(is_almost_equal(sqrt_d_2, 1 / (2.0 * csqrt(point_2)), eps)); 47 | printf("Derivative of sqrt at %g + %g i : %g + %g i\n", 48 | creal(point_2), cimag(point_2), creal(sqrt_d_2), cimag(sqrt_d_2)); 49 | 50 | return EXIT_SUCCESS; 51 | } 52 | -------------------------------------------------------------------------------- /src/8_shortest_path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define SIZE_N 6 8 | 9 | void dijkstra(size_t N, size_t A[static N][N], size_t source, size_t target) { 10 | size_t visited[N], dist[N], prev[N], unvisited_count = 0; 11 | for (size_t i = 0; i < N; i++) { 12 | dist[i] = SIZE_MAX; 13 | prev[i] = SIZE_MAX; 14 | visited[i] = false; 15 | unvisited_count++; 16 | } 17 | dist[source] = 0; 18 | while (unvisited_count) { 19 | size_t min_dist = SIZE_MAX, min_vertex = 0; 20 | for (size_t i = 0; i < N; i++) { 21 | if (!visited[i] && dist[i] < min_dist) { 22 | min_dist = dist[i]; 23 | min_vertex = i; 24 | } 25 | } 26 | unvisited_count--; 27 | assert(min_dist != SIZE_MAX); 28 | visited[min_vertex] = true; 29 | for (size_t i = 0; i < N; i++) { 30 | if (A[min_vertex][i]) { 31 | size_t value = dist[min_vertex] + A[min_vertex][i]; 32 | if (value < dist[i]) { 33 | dist[i] = value; 34 | prev[i] = min_vertex; 35 | } 36 | } 37 | } 38 | } 39 | size_t curr = target; 40 | while (curr != source) { 41 | printf("%zu - %zu\n", prev[curr], curr); 42 | curr = prev[curr]; 43 | } 44 | 45 | } 46 | 47 | int main() { 48 | size_t A[SIZE_N][SIZE_N] = {{0, 7, 9, 0, 0, 14}, 49 | {7, 0, 10, 15, 0, 0}, 50 | {9, 10, 0, 11, 0, 2}, 51 | {0, 15, 11, 0, 6, 0}, 52 | {0, 0, 0, 6, 0, 9}, 53 | {14, 0, 2, 0, 9, 0}}; 54 | printf("A:\n"); 55 | for (size_t i = 0; i < SIZE_N; i++) { 56 | for (size_t j = 0; j < SIZE_N; j++) { 57 | printf("%zu ", A[i][j]); 58 | } 59 | printf("\n"); 60 | } 61 | printf("\n"); 62 | size_t source = 0, target = 5; 63 | printf("Shortest path from source %zu to target %zu (in reversed order):\n", source, target); 64 | dijkstra(SIZE_N, A, source, target); 65 | 66 | return EXIT_SUCCESS; 67 | } -------------------------------------------------------------------------------- /src/4_union_find.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void MakeSet(size_t N, size_t parent[static N]) { 7 | for (size_t i = 0; i < N; i++) { 8 | parent[i] = i; 9 | } 10 | } 11 | 12 | size_t Find(size_t N, size_t parent[static N], size_t i) { 13 | if (i >= N) return SIZE_MAX; 14 | if (parent[i] != i) { 15 | return Find(N, parent, parent[i]); 16 | } else { 17 | return i; 18 | } 19 | } 20 | 21 | void FindReplace(size_t N, size_t parent[static N], size_t i, size_t value) { 22 | if (i >= N) return; 23 | if (parent[i] == i) { 24 | parent[i] = value; 25 | } else { 26 | size_t prev_parent = parent[i]; 27 | parent[i] = value; 28 | FindReplace(N, parent, prev_parent, value); 29 | } 30 | } 31 | 32 | size_t FindCompress(size_t N, size_t parent[static N], size_t i) { 33 | if (i >= N) return SIZE_MAX; 34 | if (parent[i] != i) { 35 | parent[i] = FindCompress(N, parent, parent[i]); 36 | } 37 | return parent[i]; 38 | } 39 | 40 | void Union(size_t N, size_t parent[static N], size_t i, size_t j) { 41 | if (i >= N || j >= N) return; 42 | FindReplace(N, parent, i, FindCompress(N, parent, j)); 43 | } 44 | 45 | void print(size_t N, size_t parent[static N]) { 46 | for (size_t i = 0; i < N; i++) { 47 | printf("%zu ", parent[i]); 48 | } 49 | printf("\n"); 50 | } 51 | 52 | #define TABLE_SIZE 10 53 | 54 | int main() { 55 | size_t parent[TABLE_SIZE]; 56 | MakeSet(TABLE_SIZE, parent); 57 | assert(Find(TABLE_SIZE, parent, 0) == 0); 58 | FindReplace(TABLE_SIZE, parent, 2, 3); 59 | FindReplace(TABLE_SIZE, parent, 3, 4); 60 | FindReplace(TABLE_SIZE, parent, 3, 5); 61 | FindReplace(TABLE_SIZE, parent, 8, 7); 62 | FindReplace(TABLE_SIZE, parent, 7, 9); 63 | assert(Find(TABLE_SIZE, parent, 3) == 5); 64 | assert(Find(TABLE_SIZE, parent, 7) == 9); 65 | FindCompress(TABLE_SIZE, parent, 2); 66 | FindReplace(TABLE_SIZE, parent, 0, 2); 67 | FindReplace(TABLE_SIZE, parent, 1, 7); 68 | FindCompress(TABLE_SIZE, parent, 8); 69 | Union(TABLE_SIZE, parent, 0, 1); 70 | assert(Find(TABLE_SIZE, parent, 1) == Find(TABLE_SIZE, parent, 3)); 71 | assert(Find(TABLE_SIZE, parent, 1) != Find(TABLE_SIZE, parent, 6)); 72 | 73 | return EXIT_SUCCESS; 74 | } -------------------------------------------------------------------------------- /src/10_performance_comparison_of_sorting_algorithm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void merge_double(size_t N, double A[N], double B[N], size_t begin, size_t mid, size_t end) { 7 | size_t i = begin; 8 | size_t j = mid; 9 | for (size_t k = begin; k < end; k++) { 10 | if (i < mid && (j >= end || A[i] <= A[j])) { 11 | B[k] = A[i]; 12 | i++; 13 | } else { 14 | B[k] = A[j]; 15 | j++; 16 | } 17 | } 18 | } 19 | 20 | void mergesort_double(size_t N, double A[N], double B[N], size_t begin, size_t end) { 21 | if (end < begin || end - begin < 2) { 22 | return; 23 | } 24 | size_t mid = begin + (end - begin) / 2; 25 | mergesort_double(N, B, A, begin, mid); 26 | mergesort_double(N, B, A, mid, end); 27 | merge_double(N, A, B, begin, mid, end); 28 | } 29 | 30 | void mergesort_helper_double(size_t N, double A[N]) { 31 | double B[N]; 32 | for (size_t i = 0; i < N; i++) { 33 | B[i] = A[i]; 34 | } 35 | mergesort_double(N, B, A, 0, N); 36 | } 37 | 38 | size_t partition_double(size_t N, double A[N], size_t begin, size_t end) { 39 | double pivot = A[end]; 40 | size_t i = begin; 41 | for (size_t j = begin; j <= end; j++) { 42 | if (A[j] < pivot) { 43 | double temp = A[j]; 44 | A[j] = A[i]; 45 | A[i] = temp; 46 | i++; 47 | } 48 | } 49 | double temp = A[i]; 50 | A[i] = A[end]; 51 | A[end] = temp; 52 | return i; 53 | } 54 | 55 | void quicksort_double(size_t N, double A[N], size_t begin, size_t end) { 56 | if (begin < end && end < N) { 57 | size_t p = partition_double(N, A, begin, end); 58 | quicksort_double(N, A, begin, p - 1); 59 | quicksort_double(N, A, p + 1, end); 60 | } 61 | } 62 | 63 | int main() { 64 | struct timespec ts; 65 | timespec_get(&ts, TIME_UTC); 66 | srand(ts.tv_sec * 1000 + ts.tv_nsec / 1000); 67 | 68 | for (size_t ARR_SIZE = 2; ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 69 | double A1[ARR_SIZE]; 70 | for (size_t i = 0; i < ARR_SIZE; i++) { 71 | A1[i] = rand() % ARR_SIZE; 72 | } 73 | clock_t t1 = clock(); 74 | mergesort_helper_double(ARR_SIZE, A1); 75 | clock_t t2 = clock(); 76 | 77 | double A2[ARR_SIZE]; 78 | for (size_t i = 0; i < ARR_SIZE; i++) { 79 | A2[i] = rand() % ARR_SIZE; 80 | } 81 | clock_t t3 = clock(); 82 | quicksort_double(ARR_SIZE, A2, 0, ARR_SIZE - 1); 83 | clock_t t4 = clock(); 84 | 85 | double dur1 = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 86 | double dur2 = 1000.0 * (t4 - t3) / CLOCKS_PER_SEC; 87 | printf("For sorting %zu elements:\n", ARR_SIZE); 88 | printf("Mergesort: %.2f ms\n", dur1); 89 | printf("Quicksort: %.2f ms\n", dur2); 90 | } 91 | 92 | return EXIT_SUCCESS; 93 | } -------------------------------------------------------------------------------- /src/1_sequential_sorting.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void merge_double(size_t N, double A[N], double B[N], size_t begin, size_t mid, size_t end) { 7 | size_t i = begin; 8 | size_t j = mid; 9 | for (size_t k = begin; k < end; k++) { 10 | if (i < mid && (j >= end || A[i] <= A[j])) { 11 | B[k] = A[i]; 12 | i++; 13 | } else { 14 | B[k] = A[j]; 15 | j++; 16 | } 17 | } 18 | } 19 | 20 | void mergesort_double(size_t N, double A[N], double B[N], size_t begin, size_t end) { 21 | if (end < begin || end - begin < 2) { 22 | return; 23 | } 24 | size_t mid = begin + (end - begin) / 2; 25 | mergesort_double(N, B, A, begin, mid); 26 | mergesort_double(N, B, A, mid, end); 27 | merge_double(N, A, B, begin, mid, end); 28 | } 29 | 30 | void mergesort_helper_double(size_t N, double A[N]) { 31 | double B[N]; 32 | for (size_t i = 0; i < N; i++) { 33 | B[i] = A[i]; 34 | } 35 | mergesort_double(N, B, A, 0, N); 36 | } 37 | 38 | size_t partition_double(size_t N, double A[N], size_t begin, size_t end) { 39 | double pivot = A[end]; 40 | size_t i = begin; 41 | for (size_t j = begin; j <= end; j++) { 42 | if (A[j] < pivot) { 43 | double temp = A[j]; 44 | A[j] = A[i]; 45 | A[i] = temp; 46 | i++; 47 | } 48 | } 49 | double temp = A[i]; 50 | A[i] = A[end]; 51 | A[end] = temp; 52 | return i; 53 | } 54 | 55 | void quicksort_double(size_t N, double A[N], size_t begin, size_t end) { 56 | if (begin < end && end < N) { 57 | size_t p = partition_double(N, A, begin, end); 58 | quicksort_double(N, A, begin, p - 1); 59 | quicksort_double(N, A, p + 1, end); 60 | } 61 | } 62 | 63 | static size_t const ARR_SIZE = 20; 64 | 65 | int main() { 66 | struct timespec ts; 67 | timespec_get(&ts, TIME_UTC); 68 | srand(ts.tv_sec * 1000 + ts.tv_nsec / 1000); 69 | 70 | double A1[ARR_SIZE]; 71 | printf("Array A1 before mergesort:\n"); 72 | for (size_t i = 0; i < ARR_SIZE; i++) { 73 | A1[i] = rand() % ARR_SIZE; 74 | printf("%g ", A1[i]); 75 | } 76 | mergesort_helper_double(ARR_SIZE, A1); 77 | printf("\n"); 78 | bool is_sorted = true; 79 | for (size_t i = 1; i < ARR_SIZE; i++) { 80 | if (A1[i] < A1[i - 1]) { 81 | is_sorted = false; 82 | break; 83 | } 84 | } 85 | printf("Array A1 is %s.\n", is_sorted ? "sorted" : "not sorted"); 86 | printf("Array A1 after mergesort:\n"); 87 | for (size_t i = 0; i < ARR_SIZE; i++) { 88 | printf("%g ", A1[i]); 89 | } 90 | printf("\n"); 91 | 92 | double A2[ARR_SIZE]; 93 | printf("Array A2 before quicksort:\n"); 94 | for (size_t i = 0; i < ARR_SIZE; i++) { 95 | A2[i] = rand() % ARR_SIZE; 96 | printf("%g ", A2[i]); 97 | } 98 | quicksort_double(ARR_SIZE, A2, 0, ARR_SIZE - 1); 99 | printf("\n"); 100 | is_sorted = true; 101 | for (size_t i = 1; i < ARR_SIZE; i++) { 102 | if (A2[i] < A2[i - 1]) { 103 | is_sorted = false; 104 | break; 105 | } 106 | } 107 | printf("Array A2 is %s.\n", is_sorted ? "sorted" : "not sorted"); 108 | printf("Array A2 after quicksort:\n"); 109 | for (size_t i = 0; i < ARR_SIZE; i++) { 110 | printf("%g ", A2[i]); 111 | } 112 | printf("\n"); 113 | 114 | return EXIT_SUCCESS; 115 | } -------------------------------------------------------------------------------- /src/6_linear_algebra.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | double vector_product(size_t N, const double A[static N], const double B[static N]) { 7 | double C = 0.0; 8 | for (size_t i = 0; i < N; i++) { 9 | C += A[i] * B[i]; 10 | } 11 | return C; 12 | } 13 | 14 | void matrix_vector_product(size_t M, size_t N, const double A[static M][N], const double v[static N], 15 | double b[static M]) { 16 | for (size_t i = 0; i < M; i++) { 17 | b[i] = 0.0; 18 | for (size_t j = 0; j < N; j++) { 19 | b[i] += A[i][j] * v[j]; 20 | } 21 | } 22 | } 23 | 24 | static const double eps = 1e-5; 25 | 26 | double almost_equal(const double x, const double y) { 27 | return fabs(x - y) < eps; 28 | } 29 | 30 | void gauss_elimination(size_t M, size_t N, double A[static M][N]) { 31 | size_t r = 0; 32 | size_t c = 0; 33 | while (r <= M && c <= N) { 34 | size_t pivot = 0; 35 | double max_leading = DBL_MIN; 36 | // search pivot 37 | for (size_t i = r; i < M; i++) { 38 | if (max_leading < fabs(A[i][c])) { 39 | max_leading = fabs(A[i][c]); 40 | pivot = i; 41 | } 42 | } 43 | if (almost_equal(A[pivot][c], 0.0)) { 44 | // if there's no pivot, pass to next column 45 | c++; 46 | } else { 47 | // swap rows 48 | for (size_t j = 0; j < N; j++) { 49 | double temp = A[r][j]; 50 | A[r][j] = A[pivot][j]; 51 | A[pivot][j] = temp; 52 | } 53 | // column elimination 54 | for (size_t i = r + 1; i < M; i++) { 55 | double ratio = A[i][c] / A[r][c]; 56 | A[i][c] = 0.0; 57 | for (size_t j = c + 1; j < N; j++) { 58 | A[i][j] -= A[r][j] * ratio; 59 | } 60 | } 61 | r++; 62 | c++; 63 | } 64 | } 65 | } 66 | 67 | #define SIZE_M 4 68 | #define SIZE_N 3 69 | 70 | int main() { 71 | 72 | double v1[SIZE_N] = {1.6, 2.7, 3.8,}; 73 | double v2[SIZE_N] = {1.1, 3.5, 2.1,}; 74 | printf("v1: "); 75 | for (size_t i = 0; i < SIZE_N; i++) { 76 | printf("%f ", v1[i]); 77 | } 78 | printf("\n"); 79 | printf("v2: "); 80 | for (size_t i = 0; i < SIZE_N; i++) { 81 | printf("%f ", v2[i]); 82 | } 83 | printf("\n"); 84 | double v = vector_product(SIZE_N, v1, v2); 85 | printf("product of v1 and v2: %f\n", v); 86 | 87 | double A[SIZE_M][SIZE_N] = {{6.7, 2.9, 11.3}, 88 | {5.8, 2.6, 8.5}, 89 | {9.2, 9.3, 6.5}, 90 | {19.5, 8.2, 6.2}}; 91 | double b[SIZE_M] = {0}; 92 | printf("A:\n"); 93 | for (size_t i = 0; i < SIZE_M; i++) { 94 | for (size_t j = 0; j < SIZE_N; j++) { 95 | printf("%f ", A[i][j]); 96 | } 97 | printf("\n"); 98 | } 99 | matrix_vector_product(SIZE_M, SIZE_N, A, v1, b); 100 | printf("product of A and v1: "); 101 | for (size_t i = 0; i < SIZE_M; i++) { 102 | printf("%f ", b[i]); 103 | } 104 | printf("\n"); 105 | 106 | gauss_elimination(SIZE_M, SIZE_N, A); 107 | printf("A after gaussian elimination:\n"); 108 | for (size_t i = 0; i < SIZE_M; i++) { 109 | for (size_t j = 0; j < SIZE_N; j++) { 110 | printf("%f ", A[i][j]); 111 | } 112 | printf("\n"); 113 | } 114 | 115 | return EXIT_SUCCESS; 116 | } 117 | -------------------------------------------------------------------------------- /src/12_text_processor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct Blob Blob; 6 | 7 | struct Blob { 8 | char* data; 9 | Blob* prev; 10 | Blob* next; 11 | }; 12 | 13 | Blob* blob_init(Blob* blob, const char* src) { 14 | if (blob) { 15 | if (src) { 16 | *blob = (Blob) { 17 | .data = malloc(sizeof(char[strlen(src) + 1])), 18 | .prev = 0, 19 | .next = 0, 20 | }; 21 | if (blob->data) { 22 | strcpy(blob->data, src); 23 | } 24 | } else { 25 | *blob = (Blob) {0}; 26 | } 27 | } 28 | return blob; 29 | } 30 | 31 | Blob* blob_new(const char* src) { 32 | return blob_init(malloc(sizeof(Blob)), src); 33 | } 34 | 35 | Blob* blob_set_data(Blob* blob, char* src) { 36 | if (blob) { 37 | free(blob->data); 38 | blob->data = src; 39 | } 40 | return blob; 41 | } 42 | 43 | void blob_destroy(Blob* blob) { 44 | if (blob) { 45 | free(blob->data); 46 | if (blob->next) { 47 | blob->next->prev = blob->prev; 48 | } 49 | if (blob->prev) { 50 | blob->prev->next = blob->next; 51 | } 52 | blob_init(blob, 0); 53 | } 54 | } 55 | 56 | void blob_delete(Blob* blob) { 57 | blob_destroy(blob); 58 | free(blob); 59 | } 60 | 61 | Blob* blob_split(Blob* blob, size_t split_point) { 62 | if (blob && blob->data) { 63 | size_t len = strlen(blob->data); 64 | if (len > split_point) { 65 | char *data1 = malloc(split_point + 1); 66 | char *data2 = malloc(len - split_point + 1); 67 | if (data1 && data2) { 68 | strncpy(data1, blob->data, split_point); 69 | strncpy(data2, blob->data + split_point, len - split_point); 70 | blob_set_data(blob, data1); 71 | Blob *blob2 = blob_new(data2); 72 | blob2->prev = blob; 73 | blob2->next = blob->next; 74 | if (blob->next) { 75 | blob->next->prev = blob2; 76 | blob->next = blob2; 77 | } 78 | } 79 | free(data1); 80 | free(data2); 81 | } 82 | } 83 | return blob; 84 | } 85 | 86 | Blob* blob_join(Blob* blob1, Blob* blob2) { 87 | if (blob1 && blob2 && blob1->data && blob2->data && blob1->next == blob2 && blob2->prev == blob1) { 88 | size_t len1 = strlen(blob1->data); 89 | size_t len2 = strlen(blob2->data); 90 | if (len1 && len2) { 91 | char* data_joined = malloc(len1 + len2 + 1); 92 | if (data_joined) { 93 | strcpy(data_joined, blob1->data); 94 | strcpy(data_joined + len1, blob2->data); 95 | blob_set_data(blob1, data_joined); 96 | blob_destroy(blob2); 97 | } 98 | } 99 | } 100 | return blob1; 101 | } 102 | 103 | void blob_print_all(Blob* blob) { 104 | if (blob) { 105 | if (blob->data) { 106 | printf("%s", blob->data); 107 | } 108 | blob_print_all(blob->next); 109 | } 110 | } 111 | 112 | int main(int argc, char* argv[argc + 1]) { 113 | FILE* file = fopen("text.txt", "r"); 114 | if (!file) { 115 | perror("fopen failed"); 116 | return EXIT_FAILURE; 117 | } 118 | char* line = 0; 119 | size_t len = 0; 120 | ssize_t read = 0; 121 | Blob* head = 0, *tail = 0; 122 | while ((read = getline(&line, &len, file)) != -1) { 123 | Blob* new_blob = blob_new(line); 124 | if (new_blob) { 125 | if (tail) { 126 | tail->next = new_blob; 127 | new_blob->prev = tail; 128 | tail = new_blob; 129 | } else { 130 | head = new_blob; 131 | tail = head; 132 | } 133 | } 134 | } 135 | blob_print_all(head); 136 | 137 | fclose(file); 138 | return EXIT_SUCCESS; 139 | } -------------------------------------------------------------------------------- /src/14_generic_sorting.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void merge(void* A, void* B, size_t N, size_t size, int comp(const void*, const void*), size_t begin, size_t mid, size_t end) { 8 | size_t i = begin; 9 | size_t j = mid; 10 | for (size_t k = begin; k < end; k++) { 11 | if (i < mid && (j >= end || comp(A + size * i, A + size * j) <= 0)) { 12 | memcpy(B + k * size, A + i * size, size); 13 | i++; 14 | } else { 15 | memcpy(B + k * size, A + j * size, size); 16 | j++; 17 | } 18 | } 19 | } 20 | 21 | void mergesort_helper(void* B, void* A, size_t N, size_t size, int comp(const void*, const void*), size_t begin, size_t end) { 22 | if (end < begin || end - begin < 2) { 23 | return; 24 | } 25 | size_t mid = begin + (end - begin) / 2; 26 | mergesort_helper(B, A, N, size, comp, begin, mid); 27 | mergesort_helper(B, A, N, size, comp, mid, end); 28 | merge(A, B, N, size, comp, begin, mid, end); 29 | } 30 | 31 | void mergesort(void* A, size_t N, size_t size, int comp(const void*, const void*)) { 32 | void* B = malloc(N * size); 33 | if (B) { 34 | memcpy(B, A, N * size); 35 | mergesort_helper(B, A, N, size, comp, 0, N); 36 | } 37 | } 38 | 39 | size_t partition(void* A, size_t N, size_t size, int comp(const void*, const void*), size_t begin, size_t end) { 40 | size_t i = begin; 41 | for (size_t j = begin; j <= end; j++) { 42 | if (comp(A + size * j, A + size * end) < 0) { 43 | unsigned char temp[size]; 44 | memcpy(temp, A + size * j, size); 45 | memcpy(A + size * j, A + size * i, size); 46 | memcpy(A + size * i, temp, size); 47 | i++; 48 | } 49 | } 50 | unsigned char temp[size]; 51 | memcpy(temp, A + size * i, size); 52 | memcpy(A + size * i, A + size * end, size); 53 | memcpy(A + size * end, temp, size); 54 | return i; 55 | } 56 | 57 | void quicksort(void* A, size_t N, size_t size, int comp(const void*, const void*), size_t begin, size_t end) { 58 | if (begin < end && end < N) { 59 | size_t p = partition(A, N, size, comp, begin, end); 60 | quicksort(A, N, size, comp, begin, p - 1); 61 | quicksort(A, N, size, comp, p + 1, end); 62 | } 63 | } 64 | 65 | int compare_double(const void* a, const void* b) { 66 | double arg1 = *(const double *) a; 67 | double arg2 = *(const double *) b; 68 | 69 | if (arg1 < arg2) return -1; 70 | if (arg1 > arg2) return 1; 71 | return 0; 72 | } 73 | 74 | int main(void) { 75 | struct timespec ts; 76 | timespec_get(&ts, TIME_UTC); 77 | srand(ts.tv_sec * 1000 + ts.tv_nsec / 1000); 78 | 79 | for (size_t ARR_SIZE = 2; ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 80 | double A1[ARR_SIZE]; 81 | for (size_t i = 0; i < ARR_SIZE; i++) { 82 | A1[i] = rand() % ARR_SIZE; 83 | } 84 | clock_t t1 = clock(); 85 | mergesort(A1, ARR_SIZE, sizeof(double), compare_double); 86 | clock_t t2 = clock(); 87 | 88 | double A2[ARR_SIZE]; 89 | for (size_t i = 0; i < ARR_SIZE; i++) { 90 | A2[i] = rand() % ARR_SIZE; 91 | } 92 | clock_t t3 = clock(); 93 | quicksort(A2, ARR_SIZE, sizeof(double), compare_double, 0, ARR_SIZE - 1); 94 | clock_t t4 = clock(); 95 | 96 | double A3[ARR_SIZE]; 97 | for (size_t i = 0; i < ARR_SIZE; i++) { 98 | A3[i] = rand() % ARR_SIZE; 99 | } 100 | 101 | clock_t t5 = clock(); 102 | qsort(A3, ARR_SIZE, sizeof(double), compare_double); 103 | clock_t t6 = clock(); 104 | 105 | double dur1 = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 106 | double dur2 = 1000.0 * (t4 - t3) / CLOCKS_PER_SEC; 107 | double dur3 = 1000.0 * (t6 - t5) / CLOCKS_PER_SEC; 108 | printf("For sorting %zu elements:\n", ARR_SIZE); 109 | printf("Mergesort: %.2f ms\n", dur1); 110 | printf("Quicksort: %.2f ms\n", dur2); 111 | printf("qsort: %.2f ms\n", dur3); 112 | } 113 | } -------------------------------------------------------------------------------- /src/11_image_segmentation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static size_t const MERGE_CRITERION = 50; 9 | 10 | typedef struct Segment Segment; 11 | 12 | struct Segment { 13 | unsigned char value; 14 | size_t parent; 15 | double average; 16 | size_t size; 17 | }; 18 | 19 | size_t FindCompress(size_t N, Segment pixels[static N], size_t i) { 20 | if (i >= N) return SIZE_MAX; 21 | if (pixels[i].parent != i) { 22 | pixels[i].parent = FindCompress(N, pixels, pixels[i].parent); 23 | } 24 | return pixels[i].parent; 25 | } 26 | 27 | bool Union(size_t N, Segment pixels[static N], size_t i, size_t j) { 28 | if (i >= N || j >= N) return false; 29 | size_t root_i = FindCompress(N, pixels, i); 30 | size_t root_j = FindCompress(N, pixels, j); 31 | if (root_i == root_j) return false; 32 | if (fabs(pixels[root_i].average - pixels[root_j].average) > MERGE_CRITERION) { 33 | return false; 34 | } 35 | if (pixels[root_i].size < pixels[root_j].size) { 36 | size_t temp = root_i; 37 | root_i = root_j; 38 | root_j = temp; 39 | } 40 | pixels[root_j].parent = root_i; 41 | double new_average = ((pixels[root_i].average * pixels[root_i].size) 42 | + (pixels[root_j].average * pixels[root_j].size)) / (double)(pixels[root_i].size + pixels[root_j].size); 43 | pixels[root_i].average = new_average; 44 | pixels[root_i].size += pixels[root_j].size; 45 | return true; 46 | } 47 | 48 | int main() { 49 | FILE* img = fopen("sample.bmp", "rb"); 50 | FILE* outimg = fopen("sample_gray.bmp", "wb"); 51 | 52 | unsigned char header[54] = {0}; 53 | fread(header, sizeof(unsigned char), 54, img); 54 | fwrite(header, sizeof(unsigned char), 54, outimg); 55 | 56 | uint32_t width = *(uint32_t*)&header[18]; 57 | uint32_t height = *(uint32_t*)&header[22]; 58 | uint32_t stride = (width * 3 + 3u) & ~(3u); 59 | uint32_t padding = stride - width * 3; 60 | 61 | printf("width %u, height %u, stride %u, padding %u\n", width, height, stride, padding); 62 | 63 | size_t image_size = width * height; 64 | Segment greyscaled[image_size]; 65 | 66 | unsigned char pixel[3] = {0}; 67 | for (uint32_t i = 0; i < height; i++) { 68 | for (uint32_t j = 0; j < width; j++) { 69 | fread(pixel, 3, 1, img); 70 | unsigned char gray = (unsigned char)(pixel[0] * 0.3 + pixel[1] * 0.58 + pixel[2] * 0.11); 71 | greyscaled[i * width + j] = (Segment){.value = gray, .parent = (i * width + j), 72 | .average = gray, .size = 1}; 73 | } 74 | fread(pixel, padding, 1, img); 75 | } 76 | size_t change_count = 1; 77 | 78 | size_t iteration = 0; 79 | while (change_count > 0) { 80 | change_count = 0; 81 | for (uint32_t j = 1; j < width; j++) { 82 | if (Union(image_size, greyscaled, j, j - 1)) { 83 | change_count++; 84 | } 85 | } 86 | for (uint32_t i = 1; i < height; i++) { 87 | if (Union(image_size, greyscaled, i * width, (i - 1) * width)) { 88 | change_count++; 89 | } 90 | for (uint32_t j = 1; j < width; j++) { 91 | if (Union(image_size, greyscaled, i * width + j, (i - 1) * width + j)) { 92 | change_count++; 93 | } 94 | if (Union(image_size, greyscaled, i * width + j, i * width + j - 1)) { 95 | change_count++; 96 | } 97 | } 98 | } 99 | printf("Iteration %zu, change_count %zu\n", ++iteration, change_count); 100 | } 101 | 102 | for (uint32_t i = 0; i < height; i++) { 103 | for (uint32_t j = 0; j < width; j++) { 104 | size_t root = FindCompress(image_size, greyscaled, i * width + j); 105 | unsigned char gray = (unsigned char) greyscaled[root].average; 106 | memset(pixel, gray, sizeof(pixel)); 107 | fwrite(&pixel, 3, 1, outimg); 108 | } 109 | fwrite(pixel, padding, 1, outimg); 110 | } 111 | 112 | fclose(img); 113 | fclose(outimg); 114 | 115 | return EXIT_SUCCESS; 116 | } 117 | -------------------------------------------------------------------------------- /src/1_sequential_sorting_string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define max(a, b) ((a) > (b) ? (a) : (b)) 9 | 10 | void merge_string(size_t N, char* A[N], char* B[N], size_t begin, size_t mid, size_t end) { 11 | size_t i = begin; 12 | size_t j = mid; 13 | for (size_t k = begin; k < end; k++) { 14 | if (i < mid && (j >= end || strcmp(A[j], A[i]) >= 0)) { 15 | strcpy(B[k], A[i]); 16 | i++; 17 | } else { 18 | strcpy(B[k], A[j]); 19 | j++; 20 | } 21 | } 22 | } 23 | 24 | void mergesort_string(size_t N, char* A[N], char* B[N], size_t begin, size_t end) { 25 | if (end < begin || end - begin < 2) { 26 | return; 27 | } 28 | size_t mid = begin + (end - begin) / 2; 29 | mergesort_string(N, B, A, begin, mid); 30 | mergesort_string(N, B, A, mid, end); 31 | merge_string(N, A, B, begin, mid, end); 32 | } 33 | 34 | void mergesort_helper_string(size_t N, char* A[N]) { 35 | char* B[N]; 36 | for (size_t i = 0; i < N; i++) { 37 | B[i] = calloc(strlen(A[i]) + 1, sizeof(char)); 38 | if (!B[i]) { 39 | printf("Not enough memory\n"); 40 | errno = 1; 41 | return; 42 | } 43 | strcpy(B[i], A[i]); 44 | } 45 | mergesort_string(N, B, A, 0, N); 46 | } 47 | 48 | void swap_strings(char* str1[static 1], char* str2[static 1]) { 49 | char* temp = *str1; 50 | *str1 = *str2; 51 | *str2 = temp; 52 | } 53 | 54 | void quicksort_string(size_t N, char* A[N]) { 55 | if (!N) { 56 | return; 57 | } 58 | size_t i = 0; 59 | for (size_t j = 0; j < N - 1; j++) { 60 | if (strcmp(A[j], A[N - 1]) < 0) { 61 | swap_strings(A + i, A + j); 62 | i++; 63 | } 64 | } 65 | swap_strings(A + i, A + N - 1); 66 | quicksort_string(i, A); 67 | i++; 68 | quicksort_string(N - i, A + i); 69 | } 70 | 71 | static char const charset[] = "abcdefghijklmnopqrstuvwxyz"; 72 | 73 | static char* rand_string(size_t N, char str[N]) { 74 | if (N) { 75 | for (size_t i = 0; i < N; i++) { 76 | size_t key = rand() % (sizeof charset - 1); 77 | str[i] = charset[key]; 78 | } 79 | } 80 | return str; 81 | } 82 | 83 | static char* rand_string_alloc(size_t N) { 84 | char* s = calloc(N + 1, sizeof(char)); 85 | return s; 86 | } 87 | 88 | static size_t const STR_SIZE = 10; 89 | static size_t const ARR_SIZE = 20; 90 | 91 | int main() { 92 | struct timespec ts; 93 | timespec_get(&ts, TIME_UTC); 94 | srand(ts.tv_sec * 1000 + ts.tv_nsec / 1000); 95 | 96 | char* A1[ARR_SIZE]; 97 | printf("Array A1 before mergesort:\n"); 98 | for (size_t i = 0; i < ARR_SIZE; i++) { 99 | size_t length = 1 + rand() % STR_SIZE; 100 | A1[i] = rand_string_alloc(length); 101 | if (!A1[i]) { 102 | printf("Not enough memory\n"); 103 | return EXIT_FAILURE; 104 | } 105 | A1[i] = rand_string(length, A1[i]); 106 | printf("%s ", A1[i]); 107 | } 108 | mergesort_helper_string(ARR_SIZE, A1); 109 | printf("\n"); 110 | if (errno == 1) { 111 | return EXIT_FAILURE; 112 | } 113 | bool is_sorted = true; 114 | for (size_t i = 1; i < ARR_SIZE; i++) { 115 | if (strcmp(A1[i - 1], A1[i]) > 0) { 116 | is_sorted = false; 117 | break; 118 | } 119 | } 120 | printf("Array A1 is %s.\n", is_sorted ? "sorted" : "not sorted"); 121 | printf("Array A1 after mergesort:\n"); 122 | for (size_t i = 0; i < ARR_SIZE; i++) { 123 | printf("%s ", A1[i]); 124 | } 125 | printf("\n"); 126 | 127 | char* A2[ARR_SIZE]; 128 | printf("Array A2 before quicksort:\n"); 129 | for (size_t i = 0; i < ARR_SIZE; i++) { 130 | size_t length = 1 + rand() % STR_SIZE; 131 | A2[i] = rand_string_alloc(length); 132 | if (!A2[i]) { 133 | printf("Not enough memory\n"); 134 | return EXIT_FAILURE; 135 | } 136 | A2[i] = rand_string(length, A2[i]); 137 | printf("%s ", A2[i]); 138 | } 139 | quicksort_string(ARR_SIZE, A2); 140 | is_sorted = true; 141 | for (size_t i = 1; i < ARR_SIZE; i++) { 142 | if (strcmp(A2[i - 1], A2[i]) > 0) { 143 | is_sorted = false; 144 | break; 145 | } 146 | } 147 | printf("\n"); 148 | printf("Array A2 is %s.\n", is_sorted ? "sorted" : "not sorted"); 149 | printf("Array A2 after quicksort:\n"); 150 | for (size_t i = 0; i < ARR_SIZE; i++) { 151 | printf("%s ", A2[i]); 152 | } 153 | printf("\n"); 154 | 155 | return EXIT_SUCCESS; 156 | } -------------------------------------------------------------------------------- /src/7_adjacency_matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define SIZE_N 6 8 | 9 | void BFS(size_t N, bool A[static N][N], bool visited[static N], size_t source) { 10 | assert(source < N); 11 | size_t front = 0, rear = 0; 12 | size_t Q[N]; 13 | for (size_t i = 0; i < N; i++) { 14 | Q[i] = 0; 15 | } 16 | visited[source] = true; 17 | Q[rear++] = source; 18 | printf("%zu ", source); 19 | while (front < rear) { 20 | size_t v = Q[front++]; 21 | for (size_t i = 0; i < N; i++) { 22 | if (A[v][i] && !visited[i]) { 23 | visited[i] = true; 24 | printf("%zu ", i); 25 | Q[rear++] = i; 26 | } 27 | } 28 | } 29 | printf("\n"); 30 | } 31 | 32 | void connected_components(size_t N, bool A[static N][N]) { 33 | bool visited[N]; 34 | for (size_t i = 0; i < N; i++) { 35 | visited[i] = false; 36 | } 37 | for (size_t i = 0; i < N; i++) { 38 | if (!visited[i]) { 39 | BFS(N, A, visited, i); 40 | } 41 | } 42 | printf("\n"); 43 | } 44 | 45 | size_t minimum_key(size_t N, size_t key[static N], bool visited[static N]) { 46 | size_t min_key = SIZE_MAX, min_index = 0; 47 | for (size_t i = 0; i < N; i++) { 48 | if (!visited[i] && key[i] < min_key) { 49 | min_key = key[i]; 50 | min_index = i; 51 | } 52 | } 53 | return min_index; 54 | } 55 | 56 | void spanning_tree(size_t N, bool A[static N][N]) { 57 | size_t parent[N]; 58 | size_t key[N]; 59 | bool visited[N]; 60 | for (size_t i = 0; i < N; i++) { 61 | parent[i] = 0; 62 | key[i] = SIZE_MAX; 63 | visited[i] = false; 64 | } 65 | key[0] = 0; 66 | parent[0] = SIZE_MAX; 67 | for (size_t count = 0; count < N; count++) { 68 | size_t u = minimum_key(N, key, visited); 69 | visited[u] = true; 70 | for (size_t v = 0; v < N; v++) { 71 | if (A[u][v] && !visited[v] && A[u][v] < key[v]) { 72 | parent[v] = u; 73 | key[v] = A[u][v]; 74 | } 75 | } 76 | } 77 | for (size_t i = 1; i < N; i++) { 78 | printf("%zu - %zu\n", parent[i], i); 79 | } 80 | } 81 | 82 | int main() { 83 | bool A[SIZE_N][SIZE_N] = {{false, true, false, false, false, false}, 84 | {false, false, true, false, false, true}, 85 | {false, false, false, false, false, false}, 86 | {false, true, false, false, true, false}, 87 | {false, false, false, false, false, true}, 88 | {false, false, false, false, false, false},}; 89 | 90 | printf("A:\n"); 91 | for (size_t i = 0; i < SIZE_N; i++) { 92 | for (size_t j = 0; j < SIZE_N; j++) { 93 | printf("%d ", A[i][j]); 94 | } 95 | printf("\n"); 96 | } 97 | printf("\n"); 98 | 99 | printf("BFS on A: "); 100 | bool v[SIZE_N] = {0,}; 101 | BFS(SIZE_N, A, v, 0); 102 | 103 | bool B[SIZE_N][SIZE_N] = {{false, true, false, false, false, false}, 104 | {true, false, true, true, false, false}, 105 | {false, true, false, false, false, false}, 106 | {false, true, false, false, true, false}, 107 | {false, false, false, true, false, false}, 108 | {false, false, false, false, false, false},}; 109 | 110 | printf("B:\n"); 111 | for (size_t i = 0; i < SIZE_N; i++) { 112 | for (size_t j = 0; j < SIZE_N; j++) { 113 | printf("%d ", B[i][j]); 114 | } 115 | printf("\n"); 116 | } 117 | printf("\n"); 118 | printf("Connected components on B: "); 119 | connected_components(SIZE_N, B); 120 | 121 | 122 | bool C[SIZE_N][SIZE_N] = {{false, true, false, false, false, false}, 123 | {true, false, true, true, false, false}, 124 | {false, true, false, false, false, false}, 125 | {false, true, false, false, true, false}, 126 | {false, false, false, true, false, true}, 127 | {false, false, false, false, true, false},}; 128 | 129 | printf("C:\n"); 130 | for (size_t i = 0; i < SIZE_N; i++) { 131 | for (size_t j = 0; j < SIZE_N; j++) { 132 | printf("%d ", C[i][j]); 133 | } 134 | printf("\n"); 135 | } 136 | printf("\n"); 137 | printf("Spanning tree of C:\n"); 138 | spanning_tree(SIZE_N, C); 139 | 140 | return EXIT_SUCCESS; 141 | } -------------------------------------------------------------------------------- /src/13_generic_derivative.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static double const eps = 1.0e-7; 10 | static double complex const eps_c = 1.0e-7 + 1.0e-7 * I; 11 | static double const tolerance = 1.0e-4; 12 | static size_t const MAX_ITER = 30; 13 | 14 | typedef double func_r(double); 15 | typedef double complex func_c(double complex); 16 | 17 | double derivative_r(func_r F, double x) { 18 | double x_p = x + eps; 19 | double x_m = x - eps; 20 | return (F(x_p) - F(x_m)) / (x_p - x_m); 21 | } 22 | 23 | double complex derivative_c(func_c F, double complex x) { 24 | double complex x_p = x + eps_c; 25 | double complex x_m = x - eps_c; 26 | return (F(x_p) - F(x_m)) / (x_p - x_m); 27 | } 28 | 29 | double find_real_root(double F(double), double init_point) { 30 | double x_0 = init_point; 31 | for (size_t iter = 1; iter < MAX_ITER; iter++) { 32 | double h = F(x_0) / derivative_r(F, x_0); 33 | double x_1 = x_0 - h; 34 | printf("Iteration %zu: x = %9.6f\n", iter, x_1); 35 | if (fabs(h) < tolerance) { 36 | printf("Root = %9.6f\n", x_1); 37 | return x_1; 38 | } 39 | x_0 = x_1; 40 | } 41 | return DBL_MAX; 42 | } 43 | 44 | typedef struct Polynomial Polynomial; 45 | 46 | struct Polynomial { 47 | size_t N; 48 | double complex* coeff; 49 | }; 50 | 51 | Polynomial* poly_init(Polynomial* poly, size_t N, const double complex coeff[static (N + 1)], bool zero_init) { 52 | if (poly) { 53 | *poly = (Polynomial) { 54 | .N = N, 55 | .coeff = malloc((N + 1) * sizeof(double complex)), 56 | }; 57 | if (poly->coeff) { 58 | if (!zero_init) { 59 | for (size_t i = 0; i <= N; i++) { 60 | poly->coeff[i] = coeff[i]; 61 | } 62 | } 63 | } else { 64 | *poly = (Polynomial) {0}; 65 | } 66 | } 67 | return poly; 68 | } 69 | 70 | Polynomial* poly_new(size_t N, const double complex coeff[static (N + 1)], bool zero_init) { 71 | return poly_init(malloc(sizeof(Polynomial)), N, coeff, zero_init); 72 | } 73 | 74 | double complex poly_evaluate(Polynomial* poly, double complex x) { 75 | double complex res = {0}; 76 | if (poly) { 77 | res = poly->coeff[0]; 78 | for (size_t i = 1; i <= poly->N; i++) { 79 | res = res * x + poly->coeff[i]; 80 | } 81 | } 82 | return res; 83 | } 84 | 85 | void poly_delete(Polynomial* poly) { 86 | if (poly) { 87 | free(poly->coeff); 88 | } 89 | free(poly); 90 | } 91 | 92 | Polynomial* poly_div(const Polynomial* p, const Polynomial* d, Polynomial* r) { 93 | Polynomial* q = 0; 94 | if (p && d && p->N > d->N) { 95 | size_t N = p->N - d->N; 96 | double complex coeff[N]; 97 | memset(coeff, 0, N * sizeof(double complex)); 98 | q = poly_new(N, coeff, true); 99 | poly_delete(r); 100 | r = poly_new(p->N, p->coeff, false); 101 | 102 | double complex ratio = 0; 103 | for (size_t i = p->N; i >= d->N && i <= p->N; i--) { 104 | ratio = r->coeff[i] / d->coeff[d->N]; 105 | q->coeff[i - d->N] = ratio; 106 | r->coeff[i] = 0; 107 | for (size_t j = 0; j < d->N; j++) { 108 | r->coeff[i - d->N + j] -= d->coeff[j] * ratio; 109 | } 110 | } 111 | while (!r->coeff[--(r->N)]); 112 | } 113 | return q; 114 | } 115 | 116 | double complex poly_derivative(Polynomial* p, double complex x) { 117 | double complex x_p = x + eps_c; 118 | double complex x_m = x - eps_c; 119 | return (poly_evaluate(p, x_p) - poly_evaluate(p, x_m)) / (x_p - x_m); 120 | } 121 | 122 | double complex poly_find_root(Polynomial* p, double complex init_point) { 123 | if (p) { 124 | double complex x_0 = init_point; 125 | for (size_t iter = 1; iter < MAX_ITER; iter++) { 126 | double complex h = poly_evaluate(p, x_0) / poly_derivative(p, x_0); 127 | double complex x_1 = x_0 - h; 128 | printf("Iteration %zu: x = %9.6f + %9.6fI\n", iter, creal(x_1), cimag(x_1)); 129 | if (cabs(h) < tolerance) { 130 | printf("Root = %9.6f + %9.6fI\n", creal(x_1), cimag(x_1)); 131 | return x_1; 132 | } 133 | x_0 = x_1; 134 | } 135 | } 136 | return DBL_MAX; 137 | } 138 | 139 | void poly_find_roots(Polynomial* p, double complex init_point) { 140 | if (p) { 141 | double complex root = poly_find_root(p, init_point); 142 | double complex coeff[2] = {1, -root}; 143 | Polynomial* d = poly_new(1, coeff, false); 144 | Polynomial* r = 0; 145 | Polynomial* q = poly_div(p, d, r); 146 | poly_find_roots(q, init_point); 147 | } 148 | } 149 | 150 | int main(void) { 151 | find_real_root(log, 2.0); 152 | 153 | // x^2 - 3x + 2 154 | double complex coeff1[3] = {1.0, -3.0, 2.0}; 155 | Polynomial* p1 = poly_new(2, coeff1, false); 156 | poly_find_roots(p1, 0); 157 | 158 | // x^2 + 1 159 | double complex coeff2[3] = {1.0, 0.0, 1.0}; 160 | Polynomial* p2 = poly_new(2, coeff2, false); 161 | // poly_find_roots(p2, 0); // newton's method does not converge for real initial conditions 162 | poly_find_roots(p2, 0.5 * I); 163 | 164 | return EXIT_SUCCESS; 165 | } -------------------------------------------------------------------------------- /src/18_parallel_sorting_with_threads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct sorting_args sorting_args; 7 | 8 | struct sorting_args { 9 | size_t length; 10 | double* ptrA; 11 | double* ptrB; 12 | }; 13 | 14 | void merge_double(size_t N, const double A[N], double B[N], size_t begin, size_t mid, size_t end) { 15 | size_t i = begin; 16 | size_t j = mid; 17 | for (size_t k = begin; k < end; k++) { 18 | if (i < mid && (j >= end || A[i] <= A[j])) { 19 | B[k] = A[i]; 20 | i++; 21 | } else { 22 | B[k] = A[j]; 23 | j++; 24 | } 25 | } 26 | } 27 | 28 | void mergesort_double(size_t N, double A[N], double B[N], size_t begin, size_t end) { 29 | if (end < begin || end - begin < 2) { 30 | return; 31 | } 32 | size_t mid = begin + (end - begin) / 2; 33 | mergesort_double(N, B, A, begin, mid); 34 | mergesort_double(N, B, A, mid, end); 35 | merge_double(N, A, B, begin, mid, end); 36 | } 37 | 38 | void mergesort_helper_double(size_t N, double A[N]) { 39 | double B[N]; 40 | for (size_t i = 0; i < N; i++) { 41 | B[i] = A[i]; 42 | } 43 | mergesort_double(N, B, A, 0, N); 44 | } 45 | 46 | size_t thread_index = 0; 47 | 48 | int mergesort_caller(void* arg) { 49 | sorting_args* sortingArgs = arg; 50 | mergesort_double(sortingArgs->length, sortingArgs->ptrB, sortingArgs->ptrA, 0, sortingArgs->length); 51 | return 0; 52 | } 53 | 54 | int main() { 55 | struct timespec ts; 56 | timespec_get(&ts, TIME_UTC); 57 | srand(ts.tv_sec * 1000 + ts.tv_nsec / 1000); 58 | 59 | size_t THREAD_COUNT = 2; 60 | 61 | for (size_t ARR_SIZE = (1u << 15u); ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 62 | double A[ARR_SIZE]; 63 | for (size_t i = 0; i < ARR_SIZE; i++) { 64 | A[i] = rand() % ARR_SIZE; 65 | } 66 | double B[ARR_SIZE]; 67 | for (size_t i = 0; i < ARR_SIZE; i++) { 68 | B[i] = A[i]; 69 | } 70 | clock_t t1 = clock(); 71 | thrd_t thrd[THREAD_COUNT]; 72 | size_t CHUNK_SIZE = ARR_SIZE / THREAD_COUNT; 73 | for (size_t i = 0; i < THREAD_COUNT; i++) { 74 | sorting_args sortingArgs = (sorting_args) {.length = CHUNK_SIZE, 75 | .ptrA = A + (i * CHUNK_SIZE), 76 | .ptrB = B + (i * CHUNK_SIZE)}; 77 | thrd_create(&thrd[i], mergesort_caller, &sortingArgs); 78 | } 79 | for (size_t i = 0; i < THREAD_COUNT; i++) { 80 | thrd_join(thrd[i], 0); 81 | } 82 | merge_double(ARR_SIZE, A, B, 0, CHUNK_SIZE, 2 * CHUNK_SIZE); 83 | 84 | clock_t t2 = clock(); 85 | 86 | double dur = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 87 | printf("For sorting %zu elements with %zu threads:\n", ARR_SIZE, THREAD_COUNT); 88 | printf("Mergesort: %.2f ms\n", dur); 89 | } 90 | printf("\n"); 91 | 92 | THREAD_COUNT = 4; 93 | 94 | for (size_t ARR_SIZE = (1u << 15u); ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 95 | double A[ARR_SIZE]; 96 | for (size_t i = 0; i < ARR_SIZE; i++) { 97 | A[i] = rand() % ARR_SIZE; 98 | } 99 | double B[ARR_SIZE]; 100 | for (size_t i = 0; i < ARR_SIZE; i++) { 101 | B[i] = A[i]; 102 | } 103 | clock_t t1 = clock(); 104 | thrd_t thrd[THREAD_COUNT]; 105 | size_t CHUNK_SIZE = ARR_SIZE / THREAD_COUNT; 106 | for (size_t i = 0; i < THREAD_COUNT; i++) { 107 | sorting_args sortingArgs = (sorting_args) {.length = CHUNK_SIZE, 108 | .ptrA = A + (i * CHUNK_SIZE), 109 | .ptrB = B + (i * CHUNK_SIZE)}; 110 | thrd_create(&thrd[i], mergesort_caller, &sortingArgs); 111 | } 112 | for (size_t i = 0; i < THREAD_COUNT; i++) { 113 | thrd_join(thrd[i], 0); 114 | } 115 | merge_double(ARR_SIZE, A, B, 0, CHUNK_SIZE, 2 * CHUNK_SIZE); 116 | merge_double(ARR_SIZE, A, B, 2 * CHUNK_SIZE, 3 * CHUNK_SIZE, 4 * CHUNK_SIZE); 117 | merge_double(ARR_SIZE, A, B, 0, 2 * CHUNK_SIZE, 4 * CHUNK_SIZE); 118 | 119 | clock_t t2 = clock(); 120 | 121 | double dur = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 122 | printf("For sorting %zu elements with %zu threads:\n", ARR_SIZE, THREAD_COUNT); 123 | printf("Mergesort: %.2f ms\n", dur); 124 | } 125 | printf("\n"); 126 | 127 | THREAD_COUNT = 8; 128 | 129 | for (size_t ARR_SIZE = (1u << 15u); ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 130 | double A[ARR_SIZE]; 131 | for (size_t i = 0; i < ARR_SIZE; i++) { 132 | A[i] = rand() % ARR_SIZE; 133 | } 134 | double B[ARR_SIZE]; 135 | for (size_t i = 0; i < ARR_SIZE; i++) { 136 | B[i] = A[i]; 137 | } 138 | clock_t t1 = clock(); 139 | thrd_t thrd[THREAD_COUNT]; 140 | size_t CHUNK_SIZE = ARR_SIZE / THREAD_COUNT; 141 | for (size_t i = 0; i < THREAD_COUNT; i++) { 142 | sorting_args sortingArgs = (sorting_args) {.length = CHUNK_SIZE, 143 | .ptrA = A + (i * CHUNK_SIZE), 144 | .ptrB = B + (i * CHUNK_SIZE)}; 145 | thrd_create(&thrd[i], mergesort_caller, &sortingArgs); 146 | } 147 | for (size_t i = 0; i < THREAD_COUNT; i++) { 148 | thrd_join(thrd[i], 0); 149 | } 150 | merge_double(ARR_SIZE, A, B, 0, CHUNK_SIZE, 2 * CHUNK_SIZE); 151 | merge_double(ARR_SIZE, A, B, 2 * CHUNK_SIZE, 3 * CHUNK_SIZE, 4 * CHUNK_SIZE); 152 | merge_double(ARR_SIZE, A, B, 0, 2 * CHUNK_SIZE, 4 * CHUNK_SIZE); 153 | merge_double(ARR_SIZE, A, B, 4 * CHUNK_SIZE, 5 * CHUNK_SIZE, 6 * CHUNK_SIZE); 154 | merge_double(ARR_SIZE, A, B, 6 * CHUNK_SIZE, 7 * CHUNK_SIZE, 8 * CHUNK_SIZE); 155 | merge_double(ARR_SIZE, A, B, 4 * CHUNK_SIZE, 6 * CHUNK_SIZE, 8 * CHUNK_SIZE); 156 | merge_double(ARR_SIZE, A, B, 0 * CHUNK_SIZE, 4 * CHUNK_SIZE, 8 * CHUNK_SIZE); 157 | 158 | clock_t t2 = clock(); 159 | 160 | double dur = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 161 | printf("For sorting %zu elements with %zu threads:\n", ARR_SIZE, THREAD_COUNT); 162 | printf("Mergesort: %.2f ms\n", dur); 163 | } 164 | printf("\n"); 165 | 166 | THREAD_COUNT = 16; 167 | 168 | for (size_t ARR_SIZE = (1u << 15u); ARR_SIZE <= (1u << 18u); ARR_SIZE <<= 1u) { 169 | double A[ARR_SIZE]; 170 | for (size_t i = 0; i < ARR_SIZE; i++) { 171 | A[i] = rand() % ARR_SIZE; 172 | } 173 | double B[ARR_SIZE]; 174 | for (size_t i = 0; i < ARR_SIZE; i++) { 175 | B[i] = A[i]; 176 | } 177 | clock_t t1 = clock(); 178 | thrd_t thrd[THREAD_COUNT]; 179 | size_t CHUNK_SIZE = ARR_SIZE / THREAD_COUNT; 180 | for (size_t i = 0; i < THREAD_COUNT; i++) { 181 | sorting_args sortingArgs = (sorting_args) {.length = CHUNK_SIZE, 182 | .ptrA = A + (i * CHUNK_SIZE), 183 | .ptrB = B + (i * CHUNK_SIZE)}; 184 | thrd_create(&thrd[i], mergesort_caller, &sortingArgs); 185 | } 186 | for (size_t i = 0; i < THREAD_COUNT; i++) { 187 | thrd_join(thrd[i], 0); 188 | } 189 | merge_double(ARR_SIZE, A, B, 0, CHUNK_SIZE, 2 * CHUNK_SIZE); 190 | merge_double(ARR_SIZE, A, B, 2 * CHUNK_SIZE, 3 * CHUNK_SIZE, 4 * CHUNK_SIZE); 191 | merge_double(ARR_SIZE, A, B, 0, 2 * CHUNK_SIZE, 4 * CHUNK_SIZE); 192 | merge_double(ARR_SIZE, A, B, 4 * CHUNK_SIZE, 5 * CHUNK_SIZE, 6 * CHUNK_SIZE); 193 | merge_double(ARR_SIZE, A, B, 6 * CHUNK_SIZE, 7 * CHUNK_SIZE, 8 * CHUNK_SIZE); 194 | merge_double(ARR_SIZE, A, B, 4 * CHUNK_SIZE, 6 * CHUNK_SIZE, 8 * CHUNK_SIZE); 195 | merge_double(ARR_SIZE, A, B, 0 * CHUNK_SIZE, 4 * CHUNK_SIZE, 8 * CHUNK_SIZE); 196 | merge_double(ARR_SIZE, A, B, 8 * CHUNK_SIZE, 9 * CHUNK_SIZE, 10 * CHUNK_SIZE); 197 | merge_double(ARR_SIZE, A, B, 10 * CHUNK_SIZE, 11 * CHUNK_SIZE, 12 * CHUNK_SIZE); 198 | merge_double(ARR_SIZE, A, B, 8 * CHUNK_SIZE, 10 * CHUNK_SIZE, 12 * CHUNK_SIZE); 199 | merge_double(ARR_SIZE, A, B, 12 * CHUNK_SIZE, 13 * CHUNK_SIZE, 14 * CHUNK_SIZE); 200 | merge_double(ARR_SIZE, A, B, 14 * CHUNK_SIZE, 15 * CHUNK_SIZE, 16 * CHUNK_SIZE); 201 | merge_double(ARR_SIZE, A, B, 12 * CHUNK_SIZE, 14 * CHUNK_SIZE, 16 * CHUNK_SIZE); 202 | merge_double(ARR_SIZE, A, B, 8 * CHUNK_SIZE, 12 * CHUNK_SIZE, 16 * CHUNK_SIZE); 203 | merge_double(ARR_SIZE, A, B, 0 * CHUNK_SIZE, 8 * CHUNK_SIZE, 16 * CHUNK_SIZE); 204 | 205 | clock_t t2 = clock(); 206 | 207 | double dur = 1000.0 * (t2 - t1) / CLOCKS_PER_SEC; 208 | printf("For sorting %zu elements with %zu threads:\n", ARR_SIZE, THREAD_COUNT); 209 | printf("Mergesort: %.2f ms\n", dur); 210 | } 211 | printf("\n"); 212 | 213 | return EXIT_SUCCESS; 214 | } -------------------------------------------------------------------------------- /src/15_text_processing_in_strings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef enum ERROR ERROR; 11 | 12 | enum ERROR { 13 | SUCCESS, 14 | ERROR_NOMATCH, 15 | ERROR_MALLOC_FAILED, 16 | ERROR_INVALID_EXPRESSION, 17 | ERROR_INVALID_CHARCLASS, 18 | ERROR_TRAILING_ESCAPE, 19 | ERROR_BRACKET, 20 | ERROR_PARENTHESES, 21 | ERROR_BRACES, 22 | ERROR_INVALID_CHARRANGE, 23 | ERROR_TOO_MANY_SUBGROUP, 24 | ERROR_EMPTY 25 | }; 26 | 27 | ERROR error_state = SUCCESS; 28 | 29 | bool search(const char text[restrict static 1], const char word[restrict static 1]) { 30 | if (strstr(text, word)) { 31 | printf("Found the word %s\n", word); 32 | return true; 33 | } else { 34 | printf("The word %s was not found\n", word); 35 | return false; 36 | } 37 | } 38 | 39 | const char* replace(const char text[restrict static 1], const char old_word[restrict static 1], 40 | const char new_word[restrict static 1]) { 41 | char* pos = strstr(text, old_word); 42 | if (pos) { 43 | size_t new_text_size = strlen(text) - strlen(old_word) + strlen(new_word) + 1; 44 | char* new_text = calloc(new_text_size, sizeof(char)); 45 | if (new_text) { 46 | memcpy(new_text, text, pos - text); 47 | memcpy(new_text + (pos - text), new_word, strlen(new_word)); 48 | strcpy(new_text + (pos - text) + strlen(new_word), text + (pos - text) + strlen(old_word)); 49 | return new_text; 50 | } else { 51 | error_state = ERROR_MALLOC_FAILED; 52 | return text; 53 | } 54 | } else { 55 | return text; 56 | } 57 | } 58 | 59 | typedef struct RegExpMatch RegExpMatch; 60 | 61 | // circular linked list 62 | struct RegExpMatch { 63 | const char* begin; 64 | const char* end; 65 | RegExpMatch* next; 66 | size_t group_size; 67 | RegExpMatch* subgroup[10]; 68 | }; 69 | 70 | static bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 71 | RegExpMatch* curr_match); 72 | static bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 73 | RegExpMatch* curr_match); 74 | 75 | typedef struct CharClass CharClass; 76 | 77 | static struct CharClass { 78 | const char* name; 79 | const char* chars; 80 | } char_classes[] = { 81 | {"alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, 82 | {"alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}, 83 | {"blank", " \t"}, 84 | {"cntrl", "\\007\\b\\t\\n\\v\\f\\r\\1\\2\\3\\4\\5\\6\\16\\17\\20\\21\\22\\23\\24" 85 | "\\25\\26\\27\\30\\31\\32\\33\\34\\35\\36\\37\\177"}, 86 | {"digit", "0123456789"}, 87 | {"graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 88 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 89 | {"lower", "abcdefghijklmnopqrstuvwxyz"}, 90 | {"print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 91 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~ "}, 92 | {"punct", "!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 93 | {"space", "\t\n\v\f\r "}, 94 | {"upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 95 | {"xdigit", "0123456789ABCDEFabcdef"}, 96 | }; 97 | 98 | typedef struct CharSet CharSet; 99 | 100 | struct CharSet { 101 | uint8_t mask[16]; 102 | }; 103 | 104 | void add_char(char c, CharSet cs[static 1]) { 105 | assert(c > 0); 106 | cs->mask[c / 8] |= (1u << (c % 8)); 107 | } 108 | 109 | bool is_in_charset(char c, CharSet cs[static 1]) { 110 | assert(c >= 0); 111 | if (!c) return false; 112 | return (cs->mask[c / 8] & (1u << (c % 8))); 113 | } 114 | 115 | size_t regex_parse_bracket_charclass(const char pattern[restrict static 1], CharSet cs[static 1]) { 116 | const char* pattern_start = pattern; 117 | while (*pattern && isalpha(*pattern++)) ; 118 | size_t length = pattern - pattern_start - 1; 119 | CharClass* char_class = 0; 120 | for (char_class = char_classes; char_class->name; char_class++) { 121 | if (!strncmp(char_class->name, pattern_start, length) && !char_class->name[length]) { 122 | break; 123 | } 124 | } 125 | if (!char_class->name) { 126 | error_state = ERROR_INVALID_CHARCLASS; 127 | return 0; 128 | } 129 | 130 | const char* chars = char_class->chars; 131 | char ch; 132 | while ((ch = *chars++)) { 133 | add_char(ch, cs); 134 | } 135 | return length; 136 | } 137 | 138 | size_t regex_parse_bracket_charlist_unit(const char pattern[restrict static 1], CharSet cs[static 1]) { 139 | size_t parsed = 0; 140 | switch (pattern[0]) { 141 | case ':': // character class 142 | pattern++; 143 | parsed++; 144 | if (!pattern[0]) { 145 | error_state = ERROR_BRACKET; 146 | return 0; 147 | } 148 | if (pattern[0] == ']') { 149 | error_state = ERROR_INVALID_CHARCLASS; 150 | return 0; 151 | } 152 | size_t length = regex_parse_bracket_charclass(pattern, cs); 153 | pattern += length; 154 | parsed += length; 155 | if (!pattern[0]) { 156 | error_state = ERROR_BRACKET; 157 | return 0; 158 | } 159 | if (!(pattern[0] == ':' && pattern[1] == ']')) { 160 | error_state = ERROR_INVALID_CHARCLASS; 161 | return 0; 162 | } else { 163 | parsed += 1; 164 | } 165 | break; 166 | default: 167 | if (!pattern[0]) { 168 | error_state = ERROR_BRACKET; 169 | return 0; 170 | } 171 | char start = pattern[0]; 172 | char finish; 173 | if (pattern[1] == '-' && pattern[2] && pattern[2] != ']') { // range 174 | finish = pattern[2]; 175 | parsed += 3; 176 | } else { 177 | finish = start; 178 | parsed += 1; 179 | } 180 | if (start > finish) { 181 | error_state = ERROR_INVALID_CHARRANGE; 182 | return 0; 183 | } 184 | for (char ch = start; ch <= finish; ch++) { 185 | add_char(ch, cs); 186 | } 187 | break; 188 | } 189 | return parsed; 190 | } 191 | 192 | CharSet* regex_parse_bracket_charlist(const char star[restrict static 1], const char pattern[restrict static 1]) { 193 | CharSet* cs = calloc(1, sizeof(CharSet)); 194 | if (!cs) { 195 | error_state = ERROR_MALLOC_FAILED; 196 | return 0; 197 | } 198 | bool invert = false; 199 | if (pattern[0] == '^') { 200 | pattern++; 201 | invert = true; 202 | } 203 | while (pattern[0] && pattern[0] != ']') { 204 | pattern += regex_parse_bracket_charlist_unit(pattern, cs); 205 | } 206 | if (pattern[0] != ']') { 207 | error_state = ERROR_BRACKET; 208 | free(cs); 209 | return 0; 210 | } 211 | if (invert) { 212 | for (size_t i = 0; i < 16; i++) { 213 | cs->mask[i] = ~cs->mask[i]; 214 | } 215 | } 216 | 217 | return cs; 218 | } 219 | 220 | bool regex_match_star_cs(CharSet cs[static 1], const char text[restrict static 1], const char pattern[restrict static 1], 221 | RegExpMatch curr_match[static 1]) { 222 | bool matched = false; 223 | do { 224 | if (regex_match_recursive(text, pattern, curr_match)) { 225 | matched = true; 226 | } 227 | } while (*text && (is_in_charset(*text++, cs))); 228 | return matched; 229 | } 230 | 231 | bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 232 | RegExpMatch curr_match[static 1]) { 233 | if (!pattern[0]) { 234 | curr_match->end = text; 235 | return true; 236 | } 237 | if (pattern[0] == '(') { 238 | if (curr_match->group_size >= 10) { 239 | error_state = ERROR_TOO_MANY_SUBGROUP; 240 | return false; 241 | } 242 | pattern++; 243 | const char* pattern_start = pattern; 244 | while (*pattern && (*++pattern != ')')); 245 | if (*pattern != ')') { 246 | error_state = ERROR_PARENTHESES; 247 | return false; 248 | } 249 | size_t length = pattern - pattern_start; 250 | pattern++; 251 | char* subpattern = calloc(length + 1, 1); 252 | strncpy(subpattern, pattern_start, length); 253 | curr_match->group_size++; // starts from 1. 254 | curr_match->subgroup[curr_match->group_size] = calloc(1, sizeof(RegExpMatch)); 255 | RegExpMatch* subgroup_match = curr_match->subgroup[curr_match->group_size]; 256 | *subgroup_match = (RegExpMatch) { 257 | .begin = text, 258 | .end = text, 259 | .next = subgroup_match, 260 | }; 261 | for (size_t i = 0; i < curr_match->group_size; i++) { 262 | subgroup_match->subgroup[i] = curr_match->subgroup[i]; 263 | } 264 | subgroup_match->group_size = curr_match->group_size; 265 | if (regex_match_recursive(text, subpattern, subgroup_match)) { 266 | RegExpMatch* curr_group_curr_node = subgroup_match; 267 | bool subgroup_matched = false; 268 | size_t curr_group_length = 0; 269 | do { 270 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 271 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 272 | subgroup_matched = true; 273 | break; 274 | } 275 | curr_group_curr_node = curr_group_curr_node->next; 276 | } while (curr_group_curr_node->next != subgroup_match); 277 | if (!subgroup_matched) { 278 | return false; 279 | } else { 280 | text += curr_group_length; 281 | return regex_match_recursive(text, pattern, curr_match); 282 | } 283 | } else { 284 | return false; 285 | } 286 | } 287 | 288 | CharSet* cs = 0; 289 | if (pattern[0] == '[') { 290 | cs = regex_parse_bracket_charlist(text, ++pattern); 291 | while (*pattern && *pattern++ != ']'); 292 | } 293 | 294 | if (pattern[0] == '\\') { 295 | if (pattern[1] >= '1' && pattern[1] <= '9') { 296 | size_t curr_group_index = pattern[1] - '0'; 297 | RegExpMatch* curr_group_head = curr_match->subgroup[curr_group_index]; 298 | if (!curr_group_head) { 299 | return false; 300 | } else { 301 | RegExpMatch* curr_group_curr_node = curr_group_head; 302 | bool subgroup_matched = false; 303 | size_t curr_group_length = 0; 304 | do { 305 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 306 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 307 | subgroup_matched = true; 308 | break; 309 | } 310 | curr_group_curr_node = curr_group_curr_node->next; 311 | } while (curr_group_curr_node->next != curr_group_head); 312 | if (!subgroup_matched) { 313 | return false; 314 | } else { 315 | pattern += 2; 316 | text += curr_group_length; 317 | return regex_match_recursive(text, pattern, curr_match); 318 | } 319 | } 320 | } else { 321 | error_state = ERROR_INVALID_EXPRESSION; 322 | return false; 323 | } 324 | } 325 | 326 | if (pattern[1] == '*') { 327 | if (cs) { 328 | CharSet* aux_cs = calloc(1, sizeof(CharSet)); 329 | for (size_t i = 0; i < 16; i++) { 330 | aux_cs->mask[i] = cs->mask[i]; 331 | } 332 | add_char(pattern[0], aux_cs); 333 | return regex_match_star_cs(aux_cs, text, pattern + 2, curr_match); 334 | } else { 335 | return regex_match_star(pattern[0], text, pattern + 2, curr_match); 336 | } 337 | } 338 | if (*text && (pattern[0] == '?' || pattern[0] == *text || (cs && is_in_charset(*text, cs)))) { 339 | if (!pattern[0]) { 340 | curr_match->end = text + 1; 341 | return true; 342 | } else { 343 | return regex_match_recursive(text + 1, pattern + 1, curr_match); 344 | } 345 | } 346 | return false; 347 | } 348 | 349 | bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 350 | RegExpMatch curr_match[static 1]) { 351 | bool matched = false; 352 | do { 353 | if (regex_match_recursive(text, pattern, curr_match)) { 354 | matched = true; 355 | } 356 | } while (*text && (*text++ == ch || ch == '?')); 357 | return matched; 358 | } 359 | 360 | bool regex_match(const char text[restrict static 1], const char pattern[restrict static 1], 361 | RegExpMatch* curr_match) { 362 | bool matched = false; 363 | *curr_match = (RegExpMatch) { 364 | .begin = text, 365 | .end = text, 366 | .next = curr_match, 367 | }; 368 | do { 369 | if (regex_match_recursive(text, pattern, curr_match)) { 370 | matched = true; 371 | RegExpMatch* next_match = calloc(1, sizeof(RegExpMatch)); 372 | if (!next_match) { 373 | error_state = ERROR_MALLOC_FAILED; 374 | return matched; 375 | } 376 | *next_match = (RegExpMatch) { 377 | .begin = text, 378 | .end = text, 379 | .next = curr_match->next, 380 | }; 381 | curr_match->next = next_match; 382 | curr_match = next_match; 383 | } 384 | } while (*text++ && (curr_match->begin = text) && !(curr_match->group_size = 0)); 385 | return matched; 386 | } 387 | 388 | void print_regex_result(RegExpMatch result[static 1]) { 389 | RegExpMatch* head = result; 390 | RegExpMatch* curr = result; 391 | while (curr->next != head) { 392 | const char* ptr = curr->begin; 393 | if (!*ptr || curr->begin == curr->end) { 394 | curr = curr->next; 395 | continue; 396 | } 397 | while (*ptr && ptr != curr->end) { 398 | putchar(*ptr++); 399 | } 400 | putchar('\n'); 401 | curr = curr->next; 402 | } 403 | } 404 | 405 | const char* regex_replace(const char text[restrict static 1], RegExpMatch result[static 1], 406 | const char new_word[restrict static 1]) { 407 | RegExpMatch* head = result; 408 | RegExpMatch* curr = result; 409 | size_t word_length = strlen(new_word); 410 | size_t list_length = 0; 411 | const char* text_pos = text; 412 | size_t text_length = 0; 413 | while (curr->next != head) { 414 | const char* ptr = curr->begin; 415 | if (!*ptr || curr->begin == curr->end) { 416 | curr = curr->next; 417 | continue; 418 | } 419 | text_length += curr->begin - text_pos; 420 | text_length += word_length; 421 | text_pos = curr->end; 422 | list_length++; 423 | curr = curr->next; 424 | } 425 | size_t rest_length = 0; 426 | if (!list_length) { 427 | return text; 428 | } else { 429 | rest_length = strlen(text) - (text_pos - text); 430 | text_length += rest_length; 431 | } 432 | text_pos = text; 433 | char* new_text = calloc(text_length + 1, 1); 434 | curr = result; 435 | char* new_text_pos = new_text; 436 | while (curr->next != head) { 437 | const char* ptr = curr->begin; 438 | if (!*ptr || curr->begin == curr->end) { 439 | curr = curr->next; 440 | continue; 441 | } 442 | size_t preceding_unmatched = curr->begin - text_pos; 443 | strncpy(new_text_pos, text_pos, preceding_unmatched); 444 | new_text_pos += preceding_unmatched; 445 | strncpy(new_text_pos, new_word, word_length); 446 | new_text_pos += word_length; 447 | text_pos = curr->end; 448 | curr = curr->next; 449 | } 450 | strncpy(new_text_pos, text_pos, rest_length); 451 | return new_text; 452 | } 453 | 454 | int main() { 455 | const char* sample_text = "four people live for the fortune"; 456 | 457 | assert(search(sample_text, "for")); 458 | assert(!search(sample_text, "form")); 459 | const char* new_sample_text = replace(sample_text, "fo", "of"); 460 | printf("%s\n", new_sample_text); 461 | 462 | RegExpMatch result = (RegExpMatch) {0}; 463 | regex_match(sample_text, "[a-f]", &result); 464 | print_regex_result(&result); 465 | 466 | const char* sample_text2 = "that that movie was bad"; 467 | RegExpMatch result2 = (RegExpMatch) {0}; 468 | regex_match(sample_text2, "(that) (\\1)", &result2); 469 | print_regex_result(&result2); 470 | 471 | const char* new_sample_text3 = regex_replace(sample_text, &result, "mario"); 472 | printf("%s\n", new_sample_text3); 473 | 474 | } -------------------------------------------------------------------------------- /src/17_text_processor_sophistication.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef enum ERROR ERROR; 13 | 14 | enum ERROR { 15 | SUCCESS, 16 | ERROR_NOMATCH, 17 | ERROR_MALLOC_FAILED, 18 | ERROR_INVALID_EXPRESSION, 19 | ERROR_INVALID_CHARCLASS, 20 | ERROR_TRAILING_ESCAPE, 21 | ERROR_BRACKET, 22 | ERROR_PARENTHESES, 23 | ERROR_BRACES, 24 | ERROR_INVALID_CHARRANGE, 25 | ERROR_TOO_MANY_SUBGROUP, 26 | ERROR_EMPTY 27 | }; 28 | 29 | ERROR error_state = SUCCESS; 30 | 31 | bool search(const char text[restrict static 1], const char word[restrict static 1]) { 32 | if (strstr(text, word)) { 33 | printf("Found the word %s\n", word); 34 | return true; 35 | } else { 36 | printf("The word %s was not found\n", word); 37 | return false; 38 | } 39 | } 40 | 41 | const char* replace(const char text[restrict static 1], const char old_word[restrict static 1], 42 | const char new_word[restrict static 1]) { 43 | char* pos = strstr(text, old_word); 44 | if (pos) { 45 | size_t new_text_size = strlen(text) - strlen(old_word) + strlen(new_word) + 1; 46 | char* new_text = calloc(new_text_size, sizeof(char)); 47 | if (new_text) { 48 | memcpy(new_text, text, pos - text); 49 | memcpy(new_text + (pos - text), new_word, strlen(new_word)); 50 | strcpy(new_text + (pos - text) + strlen(new_word), text + (pos - text) + strlen(old_word)); 51 | return new_text; 52 | } else { 53 | error_state = ERROR_MALLOC_FAILED; 54 | return text; 55 | } 56 | } else { 57 | return text; 58 | } 59 | } 60 | 61 | typedef struct RegExpMatch RegExpMatch; 62 | 63 | // circular linked list 64 | struct RegExpMatch { 65 | const char* begin; 66 | const char* end; 67 | RegExpMatch* next; 68 | size_t group_size; 69 | RegExpMatch* subgroup[10]; 70 | }; 71 | 72 | static bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 73 | RegExpMatch* curr_match); 74 | static bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 75 | RegExpMatch* curr_match); 76 | 77 | typedef struct CharClass CharClass; 78 | 79 | static struct CharClass { 80 | const char* name; 81 | const char* chars; 82 | } char_classes[] = { 83 | {"alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, 84 | {"alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}, 85 | {"blank", " \t"}, 86 | {"cntrl", "\\007\\b\\t\\n\\v\\f\\r\\1\\2\\3\\4\\5\\6\\16\\17\\20\\21\\22\\23\\24" 87 | "\\25\\26\\27\\30\\31\\32\\33\\34\\35\\36\\37\\177"}, 88 | {"digit", "0123456789"}, 89 | {"graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 90 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 91 | {"lower", "abcdefghijklmnopqrstuvwxyz"}, 92 | {"print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 93 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~ "}, 94 | {"punct", "!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 95 | {"space", "\t\n\v\f\r "}, 96 | {"upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 97 | {"xdigit", "0123456789ABCDEFabcdef"}, 98 | }; 99 | 100 | typedef struct CharSet CharSet; 101 | 102 | struct CharSet { 103 | uint8_t mask[16]; 104 | }; 105 | 106 | void add_char(char c, CharSet cs[static 1]) { 107 | assert(c > 0); 108 | cs->mask[c / 8] |= (1u << (c % 8)); 109 | } 110 | 111 | bool is_in_charset(char c, CharSet cs[static 1]) { 112 | assert(c >= 0); 113 | if (!c) return false; 114 | return (cs->mask[c / 8] & (1u << (c % 8))); 115 | } 116 | 117 | size_t regex_parse_bracket_charclass(const char pattern[restrict static 1], CharSet cs[static 1]) { 118 | const char* pattern_start = pattern; 119 | while (*pattern && isalpha(*pattern++)) ; 120 | size_t length = pattern - pattern_start - 1; 121 | CharClass* char_class = 0; 122 | for (char_class = char_classes; char_class->name; char_class++) { 123 | if (!strncmp(char_class->name, pattern_start, length) && !char_class->name[length]) { 124 | break; 125 | } 126 | } 127 | if (!char_class->name) { 128 | error_state = ERROR_INVALID_CHARCLASS; 129 | return 0; 130 | } 131 | 132 | const char* chars = char_class->chars; 133 | char ch; 134 | while ((ch = *chars++)) { 135 | add_char(ch, cs); 136 | } 137 | return length; 138 | } 139 | 140 | size_t regex_parse_bracket_charlist_unit(const char pattern[restrict static 1], CharSet cs[static 1]) { 141 | size_t parsed = 0; 142 | switch (pattern[0]) { 143 | case ':': // character class 144 | pattern++; 145 | parsed++; 146 | if (!pattern[0]) { 147 | error_state = ERROR_BRACKET; 148 | return 0; 149 | } 150 | if (pattern[0] == ']') { 151 | error_state = ERROR_INVALID_CHARCLASS; 152 | return 0; 153 | } 154 | size_t length = regex_parse_bracket_charclass(pattern, cs); 155 | pattern += length; 156 | parsed += length; 157 | if (!pattern[0]) { 158 | error_state = ERROR_BRACKET; 159 | return 0; 160 | } 161 | if (!(pattern[0] == ':' && pattern[1] == ']')) { 162 | error_state = ERROR_INVALID_CHARCLASS; 163 | return 0; 164 | } else { 165 | parsed += 1; 166 | } 167 | break; 168 | default: 169 | if (!pattern[0]) { 170 | error_state = ERROR_BRACKET; 171 | return 0; 172 | } 173 | char start = pattern[0]; 174 | char finish; 175 | if (pattern[1] == '-' && pattern[2] && pattern[2] != ']') { // range 176 | finish = pattern[2]; 177 | parsed += 3; 178 | } else { 179 | finish = start; 180 | parsed += 1; 181 | } 182 | if (start > finish) { 183 | error_state = ERROR_INVALID_CHARRANGE; 184 | return 0; 185 | } 186 | for (char ch = start; ch <= finish; ch++) { 187 | add_char(ch, cs); 188 | } 189 | break; 190 | } 191 | return parsed; 192 | } 193 | 194 | CharSet* regex_parse_bracket_charlist(const char star[restrict static 1], const char pattern[restrict static 1]) { 195 | CharSet* cs = calloc(1, sizeof(CharSet)); 196 | if (!cs) { 197 | error_state = ERROR_MALLOC_FAILED; 198 | return 0; 199 | } 200 | bool invert = false; 201 | if (pattern[0] == '^') { 202 | pattern++; 203 | invert = true; 204 | } 205 | while (pattern[0] && pattern[0] != ']') { 206 | pattern += regex_parse_bracket_charlist_unit(pattern, cs); 207 | } 208 | if (pattern[0] != ']') { 209 | error_state = ERROR_BRACKET; 210 | free(cs); 211 | return 0; 212 | } 213 | if (invert) { 214 | for (size_t i = 0; i < 16; i++) { 215 | cs->mask[i] = ~cs->mask[i]; 216 | } 217 | } 218 | 219 | return cs; 220 | } 221 | 222 | bool regex_match_star_cs(CharSet cs[static 1], const char text[restrict static 1], const char pattern[restrict static 1], 223 | RegExpMatch curr_match[static 1]) { 224 | bool matched = false; 225 | do { 226 | if (regex_match_recursive(text, pattern, curr_match)) { 227 | matched = true; 228 | } 229 | } while (*text && (is_in_charset(*text++, cs))); 230 | return matched; 231 | } 232 | 233 | bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 234 | RegExpMatch curr_match[static 1]) { 235 | if (!pattern[0]) { 236 | curr_match->end = text; 237 | return true; 238 | } 239 | if (pattern[0] == '(') { 240 | if (curr_match->group_size >= 10) { 241 | error_state = ERROR_TOO_MANY_SUBGROUP; 242 | return false; 243 | } 244 | pattern++; 245 | const char* pattern_start = pattern; 246 | while (*pattern && (*++pattern != ')')); 247 | if (*pattern != ')') { 248 | error_state = ERROR_PARENTHESES; 249 | return false; 250 | } 251 | size_t length = pattern - pattern_start; 252 | pattern++; 253 | char* subpattern = calloc(length + 1, 1); 254 | strncpy(subpattern, pattern_start, length); 255 | curr_match->group_size++; // starts from 1. 256 | curr_match->subgroup[curr_match->group_size] = calloc(1, sizeof(RegExpMatch)); 257 | RegExpMatch* subgroup_match = curr_match->subgroup[curr_match->group_size]; 258 | *subgroup_match = (RegExpMatch) { 259 | .begin = text, 260 | .end = text, 261 | .next = subgroup_match, 262 | }; 263 | for (size_t i = 0; i < curr_match->group_size; i++) { 264 | subgroup_match->subgroup[i] = curr_match->subgroup[i]; 265 | } 266 | subgroup_match->group_size = curr_match->group_size; 267 | if (regex_match_recursive(text, subpattern, subgroup_match)) { 268 | RegExpMatch* curr_group_curr_node = subgroup_match; 269 | bool subgroup_matched = false; 270 | size_t curr_group_length = 0; 271 | do { 272 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 273 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 274 | subgroup_matched = true; 275 | break; 276 | } 277 | curr_group_curr_node = curr_group_curr_node->next; 278 | } while (curr_group_curr_node->next != subgroup_match); 279 | if (!subgroup_matched) { 280 | return false; 281 | } else { 282 | text += curr_group_length; 283 | return regex_match_recursive(text, pattern, curr_match); 284 | } 285 | } else { 286 | return false; 287 | } 288 | } 289 | 290 | CharSet* cs = 0; 291 | if (pattern[0] == '[') { 292 | cs = regex_parse_bracket_charlist(text, ++pattern); 293 | while (*pattern && *pattern++ != ']'); 294 | } 295 | 296 | if (pattern[0] == '\\') { 297 | if (pattern[1] >= '1' && pattern[1] <= '9') { 298 | size_t curr_group_index = pattern[1] - '0'; 299 | RegExpMatch* curr_group_head = curr_match->subgroup[curr_group_index]; 300 | if (!curr_group_head) { 301 | return false; 302 | } else { 303 | RegExpMatch* curr_group_curr_node = curr_group_head; 304 | bool subgroup_matched = false; 305 | size_t curr_group_length = 0; 306 | do { 307 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 308 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 309 | subgroup_matched = true; 310 | break; 311 | } 312 | curr_group_curr_node = curr_group_curr_node->next; 313 | } while (curr_group_curr_node->next != curr_group_head); 314 | if (!subgroup_matched) { 315 | return false; 316 | } else { 317 | pattern += 2; 318 | text += curr_group_length; 319 | return regex_match_recursive(text, pattern, curr_match); 320 | } 321 | } 322 | } else { 323 | error_state = ERROR_INVALID_EXPRESSION; 324 | return false; 325 | } 326 | } 327 | 328 | if (pattern[1] == '*') { 329 | if (cs) { 330 | CharSet* aux_cs = calloc(1, sizeof(CharSet)); 331 | for (size_t i = 0; i < 16; i++) { 332 | aux_cs->mask[i] = cs->mask[i]; 333 | } 334 | add_char(pattern[0], aux_cs); 335 | return regex_match_star_cs(aux_cs, text, pattern + 2, curr_match); 336 | } else { 337 | return regex_match_star(pattern[0], text, pattern + 2, curr_match); 338 | } 339 | } 340 | if (*text && (pattern[0] == '?' || pattern[0] == *text || (cs && is_in_charset(*text, cs)))) { 341 | if (!pattern[0]) { 342 | curr_match->end = text + 1; 343 | return true; 344 | } else { 345 | return regex_match_recursive(text + 1, pattern + 1, curr_match); 346 | } 347 | } 348 | return false; 349 | } 350 | 351 | bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 352 | RegExpMatch curr_match[static 1]) { 353 | bool matched = false; 354 | do { 355 | if (regex_match_recursive(text, pattern, curr_match)) { 356 | matched = true; 357 | } 358 | } while (*text && (*text++ == ch || ch == '?')); 359 | return matched; 360 | } 361 | 362 | bool regex_match(const char text[restrict static 1], const char pattern[restrict static 1], 363 | RegExpMatch* curr_match) { 364 | bool matched = false; 365 | *curr_match = (RegExpMatch) { 366 | .begin = text, 367 | .end = text, 368 | .next = curr_match, 369 | }; 370 | do { 371 | if (regex_match_recursive(text, pattern, curr_match)) { 372 | matched = true; 373 | RegExpMatch* next_match = calloc(1, sizeof(RegExpMatch)); 374 | if (!next_match) { 375 | error_state = ERROR_MALLOC_FAILED; 376 | return matched; 377 | } 378 | *next_match = (RegExpMatch) { 379 | .begin = text, 380 | .end = text, 381 | .next = curr_match->next, 382 | }; 383 | curr_match->next = next_match; 384 | curr_match = next_match; 385 | } 386 | } while (*text++ && (curr_match->begin = text) && !(curr_match->group_size = 0)); 387 | return matched; 388 | } 389 | 390 | void print_regex_result(RegExpMatch result[static 1]) { 391 | RegExpMatch* head = result; 392 | RegExpMatch* curr = result; 393 | while (curr->next != head) { 394 | const char* ptr = curr->begin; 395 | if (!*ptr || curr->begin == curr->end) { 396 | curr = curr->next; 397 | continue; 398 | } 399 | while (*ptr && ptr != curr->end) { 400 | putchar(*ptr++); 401 | } 402 | putchar('\n'); 403 | curr = curr->next; 404 | } 405 | } 406 | 407 | const char* regex_replace(const char text[restrict static 1], RegExpMatch result[static 1], 408 | const char new_word[restrict static 1]) { 409 | RegExpMatch* head = result; 410 | RegExpMatch* curr = result; 411 | size_t word_length = strlen(new_word); 412 | size_t list_length = 0; 413 | const char* text_pos = text; 414 | size_t text_length = 0; 415 | while (curr->next != head) { 416 | const char* ptr = curr->begin; 417 | if (!*ptr || curr->begin == curr->end) { 418 | curr = curr->next; 419 | continue; 420 | } 421 | text_length += curr->begin - text_pos; 422 | text_length += word_length; 423 | text_pos = curr->end; 424 | list_length++; 425 | curr = curr->next; 426 | } 427 | size_t rest_length = 0; 428 | if (!list_length) { 429 | return text; 430 | } else { 431 | rest_length = strlen(text) - (text_pos - text); 432 | text_length += rest_length; 433 | } 434 | text_pos = text; 435 | char* new_text = calloc(text_length + 1, 1); 436 | curr = result; 437 | char* new_text_pos = new_text; 438 | while (curr->next != head) { 439 | const char* ptr = curr->begin; 440 | if (!*ptr || curr->begin == curr->end) { 441 | curr = curr->next; 442 | continue; 443 | } 444 | size_t preceding_unmatched = curr->begin - text_pos; 445 | strncpy(new_text_pos, text_pos, preceding_unmatched); 446 | new_text_pos += preceding_unmatched; 447 | strncpy(new_text_pos, new_word, word_length); 448 | new_text_pos += word_length; 449 | text_pos = curr->end; 450 | curr = curr->next; 451 | } 452 | strncpy(new_text_pos, text_pos, rest_length); 453 | return new_text; 454 | } 455 | 456 | int main() { 457 | const wchar_t* wsample_text = L"f\\u00dfur people live for the fortune"; 458 | setlocale(LC_ALL, "en_US.utf8"); 459 | char sample_text[256] = {0}; 460 | const wchar_t* wquery = L"f\\u00dfr"; 461 | char query_text[256] = {0}; 462 | 463 | int return_value1 = wcstombs(sample_text, wsample_text, sizeof sample_text); 464 | int return_value2 = wcstombs(query_text, wquery, sizeof query_text); 465 | if (return_value1 > 0 && return_value2 > 0) { 466 | assert(search(sample_text, query_text)); 467 | } 468 | 469 | const wchar_t* wreplace = L"\\U0001f34c"; 470 | char replace_text[256] = {0}; 471 | 472 | int return_value3 = wcstombs(replace_text, wreplace, sizeof replace_text); 473 | 474 | if (return_value3 > 0) { 475 | const char* new_sample_text = replace(sample_text, query_text, replace_text); 476 | wchar_t wnew_sample_text[256] = {0}; 477 | mbstowcs(wnew_sample_text, new_sample_text, sizeof wnew_sample_text); 478 | wprintf(L"%s\n", wnew_sample_text); 479 | } 480 | 481 | RegExpMatch result = (RegExpMatch) {0}; 482 | regex_match(sample_text, query_text, &result); 483 | print_regex_result(&result); 484 | 485 | const char* new_sample_text3 = regex_replace(sample_text, &result, replace_text); 486 | wchar_t wnew_sample_text3[256] = {0}; 487 | mbstowcs(wnew_sample_text3, new_sample_text3, sizeof wnew_sample_text3); 488 | wprintf(L"%s\n", wnew_sample_text3); 489 | 490 | } -------------------------------------------------------------------------------- /src/16_text_processing_in_streams.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef enum ERROR ERROR; 11 | 12 | enum ERROR { 13 | SUCCESS, 14 | ERROR_NOMATCH, 15 | ERROR_MALLOC_FAILED, 16 | ERROR_INVALID_EXPRESSION, 17 | ERROR_INVALID_CHARCLASS, 18 | ERROR_TRAILING_ESCAPE, 19 | ERROR_BRACKET, 20 | ERROR_PARENTHESES, 21 | ERROR_BRACES, 22 | ERROR_INVALID_CHARRANGE, 23 | ERROR_TOO_MANY_SUBGROUP, 24 | ERROR_EMPTY 25 | }; 26 | 27 | ERROR error_state = SUCCESS; 28 | 29 | bool search(const char text[restrict static 1], const char word[restrict static 1]) { 30 | if (strstr(text, word)) { 31 | fprintf(stdout, "Found the word %s\n", word); 32 | return true; 33 | } else { 34 | fprintf(stdout, "The word %s was not found\n", word); 35 | return false; 36 | } 37 | } 38 | 39 | const char* replace(const char text[restrict static 1], const char old_word[restrict static 1], 40 | const char new_word[restrict static 1]) { 41 | char* pos = strstr(text, old_word); 42 | if (pos) { 43 | size_t new_text_size = strlen(text) - strlen(old_word) + strlen(new_word) + 1; 44 | char* new_text = calloc(new_text_size, sizeof(char)); 45 | if (new_text) { 46 | memcpy(new_text, text, pos - text); 47 | memcpy(new_text + (pos - text), new_word, strlen(new_word)); 48 | strcpy(new_text + (pos - text) + strlen(new_word), text + (pos - text) + strlen(old_word)); 49 | return new_text; 50 | } else { 51 | error_state = ERROR_MALLOC_FAILED; 52 | fprintf(stderr, "Memory allocation failed\n"); 53 | return text; 54 | } 55 | } else { 56 | return text; 57 | } 58 | } 59 | 60 | typedef struct RegExpMatch RegExpMatch; 61 | 62 | // circular linked list 63 | struct RegExpMatch { 64 | const char* begin; 65 | const char* end; 66 | RegExpMatch* next; 67 | size_t group_size; 68 | RegExpMatch* subgroup[10]; 69 | }; 70 | 71 | static bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 72 | RegExpMatch* curr_match); 73 | static bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 74 | RegExpMatch* curr_match); 75 | 76 | typedef struct CharClass CharClass; 77 | 78 | static struct CharClass { 79 | const char* name; 80 | const char* chars; 81 | } char_classes[] = { 82 | {"alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, 83 | {"alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}, 84 | {"blank", " \t"}, 85 | {"cntrl", "\\007\\b\\t\\n\\v\\f\\r\\1\\2\\3\\4\\5\\6\\16\\17\\20\\21\\22\\23\\24" 86 | "\\25\\26\\27\\30\\31\\32\\33\\34\\35\\36\\37\\177"}, 87 | {"digit", "0123456789"}, 88 | {"graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 89 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 90 | {"lower", "abcdefghijklmnopqrstuvwxyz"}, 91 | {"print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 92 | "0123456789!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~ "}, 93 | {"punct", "!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~"}, 94 | {"space", "\t\n\v\f\r "}, 95 | {"upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 96 | {"xdigit", "0123456789ABCDEFabcdef"}, 97 | }; 98 | 99 | typedef struct CharSet CharSet; 100 | 101 | struct CharSet { 102 | uint8_t mask[16]; 103 | }; 104 | 105 | void add_char(char c, CharSet cs[static 1]) { 106 | assert(c > 0); 107 | cs->mask[c / 8] |= (1u << (c % 8)); 108 | } 109 | 110 | bool is_in_charset(char c, CharSet cs[static 1]) { 111 | assert(c >= 0); 112 | if (!c) return false; 113 | return (cs->mask[c / 8] & (1u << (c % 8))); 114 | } 115 | 116 | size_t regex_parse_bracket_charclass(const char pattern[restrict static 1], CharSet cs[static 1]) { 117 | const char* pattern_start = pattern; 118 | while (*pattern && isalpha(*pattern++)) ; 119 | size_t length = pattern - pattern_start - 1; 120 | CharClass* char_class = 0; 121 | for (char_class = char_classes; char_class->name; char_class++) { 122 | if (!strncmp(char_class->name, pattern_start, length) && !char_class->name[length]) { 123 | break; 124 | } 125 | } 126 | if (!char_class->name) { 127 | error_state = ERROR_INVALID_CHARCLASS; 128 | fprintf(stderr, "Invalid character class\n"); 129 | return 0; 130 | } 131 | 132 | const char* chars = char_class->chars; 133 | char ch; 134 | while ((ch = *chars++)) { 135 | add_char(ch, cs); 136 | } 137 | return length; 138 | } 139 | 140 | size_t regex_parse_bracket_charlist_unit(const char pattern[restrict static 1], CharSet cs[static 1]) { 141 | size_t parsed = 0; 142 | switch (pattern[0]) { 143 | case ':': // character class 144 | pattern++; 145 | parsed++; 146 | if (!pattern[0]) { 147 | error_state = ERROR_BRACKET; 148 | fprintf(stderr, "Bracket does not match\n"); 149 | return 0; 150 | } 151 | if (pattern[0] == ']') { 152 | error_state = ERROR_INVALID_CHARCLASS; 153 | fprintf(stderr, "Invalid character class\n"); 154 | return 0; 155 | } 156 | size_t length = regex_parse_bracket_charclass(pattern, cs); 157 | pattern += length; 158 | parsed += length; 159 | if (!pattern[0]) { 160 | error_state = ERROR_BRACKET; 161 | fprintf(stderr, "Bracket does not match\n"); 162 | return 0; 163 | } 164 | if (!(pattern[0] == ':' && pattern[1] == ']')) { 165 | error_state = ERROR_INVALID_CHARCLASS; 166 | fprintf(stderr, "Invalid character class\n"); 167 | return 0; 168 | } else { 169 | parsed += 1; 170 | } 171 | break; 172 | default: 173 | if (!pattern[0]) { 174 | error_state = ERROR_BRACKET; 175 | fprintf(stderr, "Bracket does not match\n"); 176 | return 0; 177 | } 178 | char start = pattern[0]; 179 | char finish; 180 | if (pattern[1] == '-' && pattern[2] && pattern[2] != ']') { // range 181 | finish = pattern[2]; 182 | parsed += 3; 183 | } else { 184 | finish = start; 185 | parsed += 1; 186 | } 187 | if (start > finish) { 188 | error_state = ERROR_INVALID_CHARRANGE; 189 | fprintf(stderr, "Invalid character range\n"); 190 | return 0; 191 | } 192 | for (char ch = start; ch <= finish; ch++) { 193 | add_char(ch, cs); 194 | } 195 | break; 196 | } 197 | return parsed; 198 | } 199 | 200 | CharSet* regex_parse_bracket_charlist(const char star[restrict static 1], const char pattern[restrict static 1]) { 201 | CharSet* cs = calloc(1, sizeof(CharSet)); 202 | if (!cs) { 203 | error_state = ERROR_MALLOC_FAILED; 204 | fprintf(stderr, "Memory allocation failed\n"); 205 | return 0; 206 | } 207 | bool invert = false; 208 | if (pattern[0] == '^') { 209 | pattern++; 210 | invert = true; 211 | } 212 | while (pattern[0] && pattern[0] != ']') { 213 | pattern += regex_parse_bracket_charlist_unit(pattern, cs); 214 | } 215 | if (pattern[0] != ']') { 216 | error_state = ERROR_BRACKET; 217 | fprintf(stderr, "Bracket does not match\n"); 218 | free(cs); 219 | return 0; 220 | } 221 | if (invert) { 222 | for (size_t i = 0; i < 16; i++) { 223 | cs->mask[i] = ~cs->mask[i]; 224 | } 225 | } 226 | 227 | return cs; 228 | } 229 | 230 | bool regex_match_star_cs(CharSet cs[static 1], const char text[restrict static 1], const char pattern[restrict static 1], 231 | RegExpMatch curr_match[static 1]) { 232 | bool matched = false; 233 | do { 234 | if (regex_match_recursive(text, pattern, curr_match)) { 235 | matched = true; 236 | } 237 | } while (*text && (is_in_charset(*text++, cs))); 238 | return matched; 239 | } 240 | 241 | bool regex_match_recursive(const char text[restrict static 1], const char pattern[restrict static 1], 242 | RegExpMatch curr_match[static 1]) { 243 | if (!pattern[0]) { 244 | curr_match->end = text; 245 | return true; 246 | } 247 | if (pattern[0] == '(') { 248 | if (curr_match->group_size >= 10) { 249 | error_state = ERROR_TOO_MANY_SUBGROUP; 250 | fprintf(stderr, "Too many subgroups\n"); 251 | return false; 252 | } 253 | pattern++; 254 | const char* pattern_start = pattern; 255 | while (*pattern && (*++pattern != ')')); 256 | if (*pattern != ')') { 257 | error_state = ERROR_PARENTHESES; 258 | fprintf(stderr, "Parentheses does not match\n"); 259 | return false; 260 | } 261 | size_t length = pattern - pattern_start; 262 | pattern++; 263 | char* subpattern = calloc(length + 1, 1); 264 | strncpy(subpattern, pattern_start, length); 265 | curr_match->group_size++; // starts from 1. 266 | curr_match->subgroup[curr_match->group_size] = calloc(1, sizeof(RegExpMatch)); 267 | RegExpMatch* subgroup_match = curr_match->subgroup[curr_match->group_size]; 268 | *subgroup_match = (RegExpMatch) { 269 | .begin = text, 270 | .end = text, 271 | .next = subgroup_match, 272 | }; 273 | for (size_t i = 0; i < curr_match->group_size; i++) { 274 | subgroup_match->subgroup[i] = curr_match->subgroup[i]; 275 | } 276 | subgroup_match->group_size = curr_match->group_size; 277 | if (regex_match_recursive(text, subpattern, subgroup_match)) { 278 | RegExpMatch* curr_group_curr_node = subgroup_match; 279 | bool subgroup_matched = false; 280 | size_t curr_group_length = 0; 281 | do { 282 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 283 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 284 | subgroup_matched = true; 285 | break; 286 | } 287 | curr_group_curr_node = curr_group_curr_node->next; 288 | } while (curr_group_curr_node->next != subgroup_match); 289 | if (!subgroup_matched) { 290 | return false; 291 | } else { 292 | text += curr_group_length; 293 | return regex_match_recursive(text, pattern, curr_match); 294 | } 295 | } else { 296 | return false; 297 | } 298 | } 299 | 300 | CharSet* cs = 0; 301 | if (pattern[0] == '[') { 302 | cs = regex_parse_bracket_charlist(text, ++pattern); 303 | while (*pattern && *pattern++ != ']'); 304 | } 305 | 306 | if (pattern[0] == '\\') { 307 | if (pattern[1] >= '1' && pattern[1] <= '9') { 308 | size_t curr_group_index = pattern[1] - '0'; 309 | RegExpMatch* curr_group_head = curr_match->subgroup[curr_group_index]; 310 | if (!curr_group_head) { 311 | return false; 312 | } else { 313 | RegExpMatch* curr_group_curr_node = curr_group_head; 314 | bool subgroup_matched = false; 315 | size_t curr_group_length = 0; 316 | do { 317 | curr_group_length = curr_group_curr_node->end - curr_group_curr_node->begin; 318 | if (!strncmp(curr_group_curr_node->begin, text, curr_group_length)) { 319 | subgroup_matched = true; 320 | break; 321 | } 322 | curr_group_curr_node = curr_group_curr_node->next; 323 | } while (curr_group_curr_node->next != curr_group_head); 324 | if (!subgroup_matched) { 325 | return false; 326 | } else { 327 | pattern += 2; 328 | text += curr_group_length; 329 | return regex_match_recursive(text, pattern, curr_match); 330 | } 331 | } 332 | } else { 333 | error_state = ERROR_INVALID_EXPRESSION; 334 | fprintf(stderr, "Invalid expression\n"); 335 | return false; 336 | } 337 | } 338 | 339 | if (pattern[1] == '*') { 340 | if (cs) { 341 | CharSet* aux_cs = calloc(1, sizeof(CharSet)); 342 | for (size_t i = 0; i < 16; i++) { 343 | aux_cs->mask[i] = cs->mask[i]; 344 | } 345 | add_char(pattern[0], aux_cs); 346 | return regex_match_star_cs(aux_cs, text, pattern + 2, curr_match); 347 | } else { 348 | return regex_match_star(pattern[0], text, pattern + 2, curr_match); 349 | } 350 | } 351 | if (*text && (pattern[0] == '?' || pattern[0] == *text || (cs && is_in_charset(*text, cs)))) { 352 | if (!pattern[0]) { 353 | curr_match->end = text + 1; 354 | return true; 355 | } else { 356 | return regex_match_recursive(text + 1, pattern + 1, curr_match); 357 | } 358 | } 359 | return false; 360 | } 361 | 362 | bool regex_match_star(char ch, const char text[restrict static 1], const char pattern[restrict static 1], 363 | RegExpMatch curr_match[static 1]) { 364 | bool matched = false; 365 | do { 366 | if (regex_match_recursive(text, pattern, curr_match)) { 367 | matched = true; 368 | } 369 | } while (*text && (*text++ == ch || ch == '?')); 370 | return matched; 371 | } 372 | 373 | bool regex_match(const char text[restrict static 1], const char pattern[restrict static 1], 374 | RegExpMatch curr_match[static 1]) { 375 | bool matched = false; 376 | *curr_match = (RegExpMatch) { 377 | .begin = text, 378 | .end = text, 379 | .next = curr_match, 380 | }; 381 | do { 382 | if (regex_match_recursive(text, pattern, curr_match)) { 383 | matched = true; 384 | RegExpMatch* next_match = calloc(1, sizeof(RegExpMatch)); 385 | if (!next_match) { 386 | error_state = ERROR_MALLOC_FAILED; 387 | fprintf(stderr, "Memory allocation failed\n"); 388 | return matched; 389 | } 390 | *next_match = (RegExpMatch) { 391 | .begin = text, 392 | .end = text, 393 | .next = curr_match->next, 394 | }; 395 | curr_match->next = next_match; 396 | curr_match = next_match; 397 | } 398 | } while (*text++ && (curr_match->begin = text) && !(curr_match->group_size = 0)); 399 | return matched; 400 | } 401 | 402 | void print_regex_result(RegExpMatch result[static 1]) { 403 | RegExpMatch* head = result; 404 | RegExpMatch* curr = result; 405 | while (curr->next != head) { 406 | const char* ptr = curr->begin; 407 | if (!*ptr || curr->begin == curr->end) { 408 | curr = curr->next; 409 | continue; 410 | } 411 | while (*ptr && ptr != curr->end) { 412 | fputc(*ptr++, stdout); 413 | } 414 | fputc('\n', stdout); 415 | curr = curr->next; 416 | } 417 | } 418 | 419 | size_t count_occurrence(const char text[restrict static 1], const char pattern[restrict static 1], 420 | RegExpMatch curr_match[static 1]) { 421 | regex_match(text, pattern, curr_match); 422 | RegExpMatch* head = curr_match; 423 | RegExpMatch* curr = curr_match; 424 | size_t num_occurrence = 0; 425 | while (curr->next != head) { 426 | const char* ptr = curr->begin; 427 | if (!*ptr || curr->begin == curr->end) { 428 | curr = curr->next; 429 | continue; 430 | } 431 | num_occurrence++; 432 | curr = curr->next; 433 | } 434 | return num_occurrence; 435 | } 436 | 437 | const char* regex_replace(const char text[restrict static 1], RegExpMatch result[static 1], 438 | const char new_word[restrict static 1]) { 439 | RegExpMatch* head = result; 440 | RegExpMatch* curr = result; 441 | size_t word_length = strlen(new_word); 442 | size_t list_length = 0; 443 | const char* text_pos = text; 444 | size_t text_length = 0; 445 | while (curr->next != head) { 446 | const char* ptr = curr->begin; 447 | if (!*ptr || curr->begin == curr->end) { 448 | curr = curr->next; 449 | continue; 450 | } 451 | text_length += curr->begin - text_pos; 452 | text_length += word_length; 453 | text_pos = curr->end; 454 | list_length++; 455 | curr = curr->next; 456 | } 457 | size_t rest_length = 0; 458 | if (!list_length) { 459 | return text; 460 | } else { 461 | rest_length = strlen(text) - (text_pos - text); 462 | text_length += rest_length; 463 | } 464 | text_pos = text; 465 | char* new_text = calloc(text_length + 1, 1); 466 | curr = result; 467 | char* new_text_pos = new_text; 468 | while (curr->next != head) { 469 | const char* ptr = curr->begin; 470 | if (!*ptr || curr->begin == curr->end) { 471 | curr = curr->next; 472 | continue; 473 | } 474 | size_t preceding_unmatched = curr->begin - text_pos; 475 | strncpy(new_text_pos, text_pos, preceding_unmatched); 476 | new_text_pos += preceding_unmatched; 477 | strncpy(new_text_pos, new_word, word_length); 478 | new_text_pos += word_length; 479 | text_pos = curr->end; 480 | curr = curr->next; 481 | } 482 | strncpy(new_text_pos, text_pos, rest_length); 483 | return new_text; 484 | } 485 | 486 | int main() { 487 | char sample_text[256]; 488 | char query_text[256]; 489 | char replacing_text[256]; 490 | 491 | fprintf(stdout, "Input the text.\n"); 492 | if (fgets(sample_text, sizeof sample_text, stdin)) { 493 | fprintf(stdout, "Input the query text.\n"); 494 | if (fgets(query_text, sizeof query_text, stdin)) { 495 | RegExpMatch result = (RegExpMatch) {0}; 496 | size_t num_occurrence = count_occurrence(sample_text, query_text, &result); 497 | fprintf(stdout, "Number of occurrence of %s is %zu\n", query_text, num_occurrence); 498 | } else { 499 | fprintf(stderr, "Invalid query text\n"); 500 | return EXIT_FAILURE; 501 | } 502 | } else { 503 | fprintf(stderr, "Invalid text\n"); 504 | return EXIT_FAILURE; 505 | } 506 | fprintf(stdout, "Input the replacing text.\n"); 507 | if (fgets(replacing_text, sizeof replacing_text, stdin)) { 508 | RegExpMatch result = (RegExpMatch) {0}; 509 | regex_match(sample_text, query_text, &result); 510 | const char* replaced_text = regex_replace(sample_text, &result, replacing_text); 511 | fprintf(stdout, "Replaced text is: %s\n", replaced_text); 512 | } else { 513 | fprintf(stderr, "Invalid replacing text\n"); 514 | return EXIT_FAILURE; 515 | } 516 | 517 | } --------------------------------------------------------------------------------