Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык Си. Лабораторные работы / Справочник. Часть 2 (СПбГУТ).doc
Скачиваний:
47
Добавлен:
10.09.2019
Размер:
801.79 Кб
Скачать

2.9. Работа со строками

2.9.1. Пользовательские аналоги библиотечных функций

Пример. 1 Вычисление длины строки.

Приведем два варианта вычисления длины строки. В первом из вариантов будет использоваться обращение к элементам строки с помощью оператора индексные скобки. Преимуществом этого решения является более высокая читабельность программного кода. Во втором варианте будут использованы указатели идиома *p++.

Первый вариант.

int my_strlen(const char* s) { int cnt_char = 0; //счетчик символов в строке for(int i = 0; s[i] != ‘\0’; i++) cnt_char++; return cnt_char; }

Особенностью этого варианта является использование двух переменных целого типа i и cnt_char. Переменная i управляет работой цикла, а вторая выполняет подсчет символов в строке. Такое разделение обязанностей между переменными делает программный код более понятным.

Второй вариант.

int my_strlen_2(const char* s) { const char* ptr_cur = s; while(*ptr_cur++) continue; return ptr_cur – s – 1;}

Достоинством второго варианта реализации является компактность программного кода. Это достигнуто за счет использования идиомы *ptr_cur++. В рассматриваемом случае одно это выражение *ptr_cur++ обеспечивает выполнение всех необходимых операций в цикле. Поэтому тело цикла должно быть пустым. С этой точки зрения было бы естественным. Заменить инструкцию continue пустым оператором (;). Однако инструкция continue более точно передает намерения программиста. При ее удалении у программиста, читающего код может возникнуть предположение о наличии в коде ошибки.

Остановимся на порядке вычисления выражения *ptr_cur++. Сложность анализа рассматриваемого выражения состоит в том, что в выражении имеется только один операнд ptr_cur, с которым взаимодействуют два оператора * и ++. Надо определить какой из них будет выполняться первым. Ответ на этот вопрос следует искать в таблице приоритетов операторов. Здесь следует учитывать, что оператор инкремента ++ в рассматриваемом выражении используется в постфиксной форме (оператор ++ находится после операнда). Итог этого рассмотрения таков: вначале будет выполняться инкремент ++, а затем разыменование *. Затем настает время учесть, что оператор ++ обладает побочным эффектом. При этом у оператора в постфиксной форме он проявляется после завершения вычисления всего выражения. Общий итог анализа: вначале выполняется разыменование текущего значения указателя, а затем выполняется его инкремент. Цикл закончит свою работу в тот момент времени, когда очередное разыменование текущего указателя вернет нуль символ. При этом текущий указатель продвинется и окажется за нуль символом. Это приводит к необходимости отнимать единицу при вычислении длины строки.

Пример 2. Копирование строк. Приведем только один вариант реализации функции копирования с использованием идиомы *p++.

char* my_strcpy(char* to, const char* from) { char* t = to; while(*t++ = *from++) continue; return to; }

2.9.2. Копирование чисел, находящихся в строке, в числовой массив

Постановка задачи. Имеется строковая переменная, содержащая вещественные числа. Требуется написать функцию, копирующую числа из строки в числовой массив. Кроме того, функция должна возвращать и количество скопированных чисел. В приведённом ниже решении использована библиотечная функция stdtod(), описание которой приведено в разделе 1.38.4. Там же имеется определение функции, вычисляющей сумму чисел, находящихся в строке.

Решение. Интерфейс функции. Имя функции – extract_num_from_str. Функция должна принимать два параметра: const char* str – входная строка и double ar_num – выходной числовой массив. Функция должна возвращать значение типа int – количество скопиованных из строки чисел. Заголовок функции:

int extract_num_from_str(const char* str, double ar_num[]).

Реализация функции. Реализацию данной функции нетрудно написать по аналогии с определением функции sum_in_string, которое приведено в разделе 1.38.4. Обратите внимание на некоторое отличие в организации цикла. Ниже использован более компактный вариант цикла while. Этот вариант цикла некоторые авторы называют циклом с выходом.

int extract_num_from_str(const char* str, double ar_num[]) { const char* ptr_str = str; char* ptr_end = NULL; int cnt = 0; while(1) { double x = strtod(ptr_start, &ptr_end); if(ptr_end == ptr_start)//Все ли числа просмотрены ? break;//Больше чисел нет ar[cnt++] = x; } return cnt; }