diff --git a/README.md b/README.md index 0644f40..9f4b773 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,6 @@ $ ./wcl ./test/wiki_ci ./test/nullfile * realloc(3) -- функции для работы с динамической памятью * memset(3) -- функция, заполняющая буфер константным значением * memcpy(3) -- функция, копирующая данные между двумя массивами -* strlen(3) -- функция, вычисляющая длинну строки +* memmove(3) -- функция, копирующая данные между массивами (входящий и исходящий массивы могут пересекаться) +* strlen(3) -- функция, вычисляющая длину строки +* strcpy(3) -- функция, копирующая строку в буфер diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4581ca5 --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gcc -Wall -g -o str_test str.c str_test.c util.c diff --git a/str.c b/str.c index 0abe502..8036bd5 100644 --- a/str.c +++ b/str.c @@ -6,6 +6,24 @@ #define INIT_SZ 20 +//Внутренняя функция, +//позволяет убедиться что строка может вместить как минимум newsz символов +void +_str_ensure(str *s, int newsz) +{ + int tmp; + newsz += 1; // добавляем единичку чтобы влез нулевой байт + if (newsz < s->capacity) + return; + + tmp = s->capacity * 2; + if (tmp > newsz) { + newsz = tmp; + } + s->ptr = xrealloc(s->ptr, newsz); + s->capacity = newsz; +} + void str_init(str *s) { @@ -36,6 +54,13 @@ str_data(str *s) return NULL; } +void +str_set(str *s, char *cstr) +{ + assert(s && cstr); + // +} + str str_copy(str *s) { @@ -43,15 +68,61 @@ str_copy(str *s) // } -void -str_append(str *s, char *p) +int +str_count(str *s, char ch) { + assert(s); + // + return 0; +} + +void +str_append(str *s, char *cstr) +{ + assert(s && cstr); // } void -str_shrink(str *s, int sz) +str_append_n(str *s, char *cstr, int len) { - assert(s && sz >= 0); + assert(s && cstr); // -} \ No newline at end of file +} + +void +str_shrink(str *s, int len) +{ + assert(s && len >= 0); + // +} + +int +str_find(str *s, char *substr) +{ + assert(s && substr); + char *p = strstr(s->ptr, substr); + if (p == NULL) + return -1; + return p - s->ptr; +} + +str +str_sub(str *s, int start_idx, int length) +{ + assert(s && start_idx >= 0 && length >= 0); + + str s2; + str_init(&s2); + // + return s2; +} + +// Hint: you can create temporary string object! +int +str_replace(str *s, char *substr, char *replacement) +{ + assert(s && substr && replacement); + // + return 0; +} diff --git a/str.h b/str.h index ebc65ff..8cf04b4 100644 --- a/str.h +++ b/str.h @@ -2,12 +2,11 @@ #include // Str это структура, которая хранит в памяти строки произвольной длинны -// sz -- содержит текущий размер строки (0 если строка не инициализирована или нулевого размера) -// Размер строки -- количество байт, занятое под символы (за исключением последнего нулевого байта) +// len -- содержит текущую длину строки (0 если строка не инициализирована или нулевого размера) // capacity содержит размер динамически инициализированного массива ptr struct Str { - int sz; + int len; int capacity; char *ptr; }; @@ -25,11 +24,39 @@ void str_deinit(str *s); // Функция должна вернуть указатель на ptr char *str_data(str *s); +//Функция копирует в строку содержимое cstr. +void str_set(str *s, char *cstr); + //Функция создаёт и возвращает новую строку, копию s str str_copy(str *s); -//добавляет к строке строку suffix -void str_append(str *s, char *suffix); +// Функция возвращает количество символов ch в строке str +int str_count(str *s, char ch); -//уменьшает размер строки до sz байт -void str_shrink(str *s, int sz); +//добавляет к строке строку cstr +void str_append(str *s, char *cstr); + +//добавляет к строке строку cstr +void str_append_n(str *s, char *cstr, int len); + +//Если строка s содержит больше len байт, то уменьшает размер строки до len байт +void str_shrink(str *s, int len); + +//Искать подстроку subsr в строке s. Вернуть индекс в строке или -1 +int str_find(str *s, char *substr); + +//Функция создаёт новую строку, которая должна содержать подстроку s, начиная с символа по индексу start_idx, и быть длины length символов (или меньше, если в строке s не хватает символов). +//Пример использования: +// str_init(&s, "hello world"); +// str s2 = str_sub(&s, 6, 5); +// В s2 должна оказаться подстрока "world" +str str_sub(str *s, int start_idx, int length); + +//Функция ищет в исходной строке s подстроки substr и заменяет их на replacement +//Возвращает число заменённых подстрок. +//Пример использования: +// str_init(&s, "foo bar baz foo"); +// str_replace(&s, "foo", "test"); +//В результате в строке &s должна получиться строка "test bar baz test", +//функция должна вернуть 2 +int str_replace(str *s, char *substr, char *replacement); diff --git a/str_test.c b/str_test.c index ed260e8..898a292 100644 --- a/str_test.c +++ b/str_test.c @@ -5,12 +5,12 @@ #include "str.h" -#define my_assert(cond, reason, ...) do { \ - if (!(cond)) { \ +#define my_assert(cond, reason, ...) do { \ + if (!(cond)) { \ printf("[-] ERROR " reason "\n", ##__VA_ARGS__); \ printf("\t%s:%d " #cond "\n", __FILE_NAME__, __LINE__); \ - exit(1); \ - } \ + exit(1); \ + } \ } while (0) @@ -22,35 +22,89 @@ test_it() //TEST str_init str_init(&s); - my_assert(s.sz == 0, "initial size should be 0"); - my_assert(s.ptr == str_data(&s), "str_data должна вернуть то же самое что хранится в ptr поле"); + my_assert(s.len == 0, + "initial size should be 0"); + my_assert(s.ptr == str_data(&s), + "str_data, должна вернуть то же самое что хранится в ptr поле"); str_deinit(&s); // TEST str_init_data str_init_data(&s, "hello"); - my_assert(s.sz == strlen("hello"), "str_init_data, неправильный размер строки"); - my_assert(strcmp(str_data(&s), "hello") == 0, "не правильная строка '%s' != 'hello'", str_data(&s)); + my_assert(s.len == strlen("hello"), + "str_init_data, неправильный размер строки"); + my_assert(strcmp(str_data(&s), "hello") == 0, + "str_init_data, не правильная строка '%s' != 'hello'", str_data(&s)); + + // TEST str_set + str_set(&s, ""); + my_assert(s.len == 0, + "str_set, нулевая строка, неверный размер"); + my_assert(strcmp(str_data(&s), "") == 0, + "str_set, нулевая строка, не верное содержимое %s", str_data(&s)); + + char *lazyfox = "The quick brown fox jumps over the lazy dog"; + str_set(&s, lazyfox); + my_assert(s.len == strlen(lazyfox), + "str_set, lazyfox s.len error"); + my_assert(strcmp(str_data(&s), lazyfox) == 0, + "str_set, нулевая строка, не верное содержимое %s", str_data(&s)); // TEST str_copy str s2; s2 = str_copy(&s); - my_assert(s2.sz == s.sz, - "str_copy. размеры строк разные!"); + my_assert(s2.len == s.len, + "str_copy, размеры строк разные!"); my_assert(strcmp(str_data(&s), str_data(&s2)) == 0, - "str_copy получились разные строки '%s' != '%s'", str_data(&s), str_data(&s2)); - my_assert(s.ptr != s2.ptr, "str_copy s.ptr и s2.ptr не должны указывать на одну строку. Указатели строк должны быть разными"); + "str_copy, получились разные строки '%s' != '%s'", str_data(&s), str_data(&s2)); + my_assert(s.ptr != s2.ptr, + "str_copy, s.ptr и s2.ptr не должны указывать на одну строку. Указатели строк должны быть разными"); + str_deinit(&s2); // TEST str_append + str_set(&s, "hello"); str_append(&s, " world"); - my_assert(strcmp(s.ptr, "hello world") == 0, "str_append, неправильная строка %s", s.ptr); + my_assert(strcmp(s.ptr, "hello world") == 0, + "str_append, неправильная строка %s", s.ptr); str_append(&s, "loooooooooooooooooooooooooooooooooooooooooooooooong str"); - my_assert(strcmp(s.ptr, "hello worldloooooooooooooooooooooooooooooooooooooooooooooooong str") == 0, "str_append вторая проверка, неправильная строка"); + my_assert(strcmp(s.ptr, "hello worldloooooooooooooooooooooooooooooooooooooooooooooooong str") == 0, + "str_append, вторая проверка, неправильная строка"); + // TEST str_append_n + str_set(&s, "hello "); + str_append_n(&s, lazyfox, 9); + my_assert(strcmp(str_data(&s), "hello The quick") == 0, + "str_append_n, неверная строка %s", str_data(&s)); // TEST str_shrink str_shrink(&s, 5); - my_assert(s.sz == 5, "str_shrink неправильный размер строки"); - my_assert(strcmp(str_data(&s), "hello") == 0, "str_shrink не правильная строка"); + my_assert(s.len == 5, + "str_shrink, неправильный размер строки"); + my_assert(strcmp(str_data(&s), "hello") == 0, + "str_shrink, не правильная строка"); + str_deinit(&s); + + // TEST str_find + str_init_data(&s, "hello"); + my_assert(str_find(&s, "hello") == 0, + "str_find, не могу найти `hello` в строке `hello`"); + my_assert(str_find(&s, "llo") == 2, + "str_find, не могу найти `llo` в строке `hello`"); + my_assert(str_find(&s, "world") == -1, + "str_find, могу найти `world` в строке `hello`"); + + //TEST str_sub + str_set(&s, lazyfox); + s2 = str_sub(&s, 4, 5); + my_assert(strcmp(str_data(&s2), "quick") == 0, + "str_sub, не правильная строка %s", str_data(&s2)); + str_deinit(&s2); + + //TEST str_replace + str_set(&s, "foo bar baz foo"); + str_replace(&s, "foo", "test"); + my_assert(strcmp(s.ptr, "test bar baz test") == 0, + "str_replace, не верное значение %s", s.ptr); + str_deinit(&s); printf("[+] ALL_TESTS_PASSED\n"); }