- •Введение
- •1. ТИПЫ ДАННЫХ И ОПЕРАТОРЫ
- •1.1. Переменные и базовые типы данных
- •1.2. Операции и выражения
- •1.3. Символические константы
- •1.5. Несколько слов о функции main()
- •2. ВВОД И ВЫВОД В СИ
- •2.2. Форматный ввод-вывод
- •3. ЦИКЛЫ И ОПЕРАТОРЫ СРАВНЕНИЯ
- •3.1. Условный оператор
- •3.2. Оператор выбора switch
- •3.3. Операторы цикла
- •3.4. Операторы break и continue
- •3.5. Примеры
- •3.6. Вычисление значений элементарных функций
- •3.7. Задачи
- •4. ОБРАБОТКА ПОСЛЕДОВАТЕЛЬНОСТЕЙ
- •4.1. Примеры
- •4.2. Задачи
- •5. ОДНОМЕРНЫЕ МАССИВЫ
- •5.1. Начальные сведения о массивах
- •5.2. Примеры работы с массивами
- •5.3. Задачи
- •6. МНОГОМЕРНЫЕ МАССИВЫ
- •6.1. Определение и инициализация двумерных массивов
- •6.2. Примеры с двумерными массивами
- •6.3. Задачи
- •7. УКАЗАТЕЛИ И МАССИВЫ
- •7.1. Указатели и адреса
- •7.2. Указатели и аргументы функций
- •7.3. Указатели и массивы
- •7.4. Операции с указателями
- •7.5. Указатели с типом void
- •7.6. Модификатор const
- •7.7. Массивы переменного размера
- •7.8. Массивы указателей
- •7.9. Двумерные массивы переменного размера
- •8. СИМВОЛЫ И СТРОКИ
- •8.1. Представление символьной информации в ЭВМ
- •8.2. Библиотека обработки символов
- •8.3. Строки в языке Си
- •8.4. Функции обработки строк
- •8.5. Функции преобразования строк
- •8.6. Примеры работы со строками
- •8.7. Разбиение строки на лексемы
- •8.8. Задачи
- •9. СТРУКТУРЫ
- •9.1. Основные сведения о структурах
- •9.2. Объединения
- •10. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА
- •10.1. Директива #include
- •10.2. Директива #define
- •10.3. Директива #undef
- •10.4. Условная компиляция
- •11. ФУНКЦИИ
- •11.1. Основные сведения о функциях
- •11.2. Прототипы функций
- •11.3. Классы памяти
- •11.4. Указатели на функции
- •11.5. Рекурсия
- •11.6. Примеры с использованием рекурсии
- •11.7. Метод «разделяй и властвуй»
- •11.8. Задачи на применение рекурсии
- •12. РАБОТА С БИТАМИ ПАМЯТИ
- •12.1. Битовые операции
- •12.2. Примеры с использованием битовых операций
- •12.3. Задачи
- •13. РАБОТА С ФАЙЛАМИ
- •13.1. Файлы и потоки
- •13.2. Текстовые файлы
- •13.3. Двоичные файлы
- •13.4. Шифрование файлов
- •13.5. Задачи на текстовые файлы
- •13.6. Задачи на двоичные файлы
- •14. СТРУКТУРЫ ДАННЫХ
- •14.1. Односвязные списки
- •14.2. Примеры работы с односвязными списками
- •14.3. Задачи на односвязные списки
- •14.4. Стеки, очереди
- •14.5. Задачи на стеки и очереди
- •14.6. Двусвязные списки
- •14.7. Задачи на двусвязные списки
- •14.8. Бинарные деревья
- •14.9. Примеры с использованием бинарных деревьев
- •14.10. Задачи на бинарные деревья
- •Приложение 1. АЛГОРИТМЫ ПОИСКА
- •1. Линейный поиск
- •2. Поиск с барьером
- •3. Двоичный поиск
- •Приложение 2. АЛГОРИТМЫ СОРТИРОВКИ
- •Несколько слов о сложности алгоритмов
- •1. Метод прямого выбора
- •2. Метод прямого включения
- •3. Пузырьковая сортировка
- •4. Шейкерная сортировка
- •5. Быстрая сортировка
- •6. Сортировка подсчетом
- •Приложение 3. СОРТИРОВКА ИНДЕКСОВ И УКАЗАТЕЛЕЙ
- •1. Сортировка индексов на основе метода прямого выбора
- •2. Сортировка индексов на основе пузырьковой сортировки
- •3. Сортировка индексов на основе быстрой сортировки
- •4. Сортировка двумерных массивов
- •5. Сортировка строк
- •Приложение 4. СОРТИРОВКА ФАЙЛОВ И СПИСКОВ
- •1. Сортировка двоичных файлов
- •2. Сортировка линейных списков
- •Приложение 5. СОРТИРОВКА С УСЛОВИЕМ
- •1. Сортировка с условием на базе пузырьковой сортировки
- •2. Сортировка с условием на базе быстрой сортировки
- •3. Сортировка с условием двоичных файлов
- •4. Сортировка с условием линейного списка на базе пузырьковой сортировки
- •5. Сортировка с условием линейного списка на базе быстрой сортировки
- •ЛИТЕРАТУРА
i++; return i;
}
Пример 5. Копирование строки t в строку s.
void Strcpy(char *s, const char *t)
{
int i = 0;
while ((s[i] = t[i]) != '\0') i++;
}
Пример 6. Добавление строки t к строке s.
void Strcat(char *s, const char *t)
{
int i, j;
i = j = 0;
while (s[i] != '\0') i++;
while ((s[i++] = t[j++]) != '\0')
;
}
8.4. Функции обработки строк
Ниже приведены основные функции операций над строками
(библиотека <string.h>):
Прототип |
Описание функции |
int strlen(const char *s) |
возвращает длину строки s |
char *strcpy(char *s, const char *t) |
копирует строку t в строку s, |
|
включая ‘\0’; возвращает s |
char *strncpy(char *s, const char *t, |
копирует не более n символов |
size_t n) |
строки t в s; возвращает s. До- |
114
|
полняет результат символами |
|
‘\0’, если символов в t меньше, |
|
чем n |
char *strcat(char *s, const char *t) |
приписывает t к s; возвращает s |
char *strncat(char *s, const char *t, |
приписывает не более n симво- |
size_t n) |
лов t к s, возвращает s |
int strcmp(const char *s, |
сравнивает s и t; возвращает |
const char *t) |
<0, если s<t, 0, если s == t, и >0, |
|
если s>t |
int strncmp(const char *s, const char *t, |
аналогична функции strcmp(), |
size_t n) |
только сравниваются не более |
|
n первых символов в строках s |
|
и t |
char *strchr(const char *s, int c) |
возвращает указатель на пер- |
|
вое вхождение символа с в |
|
строку s, либо NULL, если та- |
|
кого символа не оказалось |
char *strrchr(const char *s, int c) |
возвращает указатель на по- |
|
следнее вхождение символа с в |
|
строку s, либо NULL, если та- |
|
кого символа не оказалось |
char *strpbrk(const char *s, |
возвращает указатель в строке |
const char *t) |
s на первый символ, который |
|
совпал с одним из символов, |
|
входящих в t, либо NULL, если |
|
такового не оказалось |
char *strstr(const char *s, const char *t) |
возвращает указатель на пер- |
|
вое вхождение строки t в стро- |
|
ку s, либо NULL, если такой |
|
подстроки в s не оказалось |
char *strtok(char *s, const char *t) |
ищет в s лексему, ограничен- |
|
ную символами из t. Возвра- |
|
щает указатель на первый сим- |
|
вол лексемы, либо NULL, если |
|
лексемы не существует |
Приведем пример использования функции strchr(). После выполнения следующих строчек программы
115
char *s, c; s = "check"; c = 'e';
printf("%s%c%s%s%s\n", "symbol ", c, strchr(s, c) ? " was " : " was not ", "found in ", s);
на экране появится такой результат: symbol e was found in check.
Функцию strchr можно использовать для подсчета количества символов строки s со значением c:
int Count(char *s, char c)
{
int count = 0; while(s = strchr(s, c))
{
count++;
s++;
}
return count;
}
С помощью функций strchr и strcpy можно организовать удаление всех символов c в строке s:
void Del(char *s, char c)
{
char *ps = s;
while (ps = strchr(ps, c)) strcpy(ps, ps + 1);
}
Заметим при этом, что если символов c в строке s будет более одного, то данный алгоритм будет неэффективным. Эффективный алгоритм для произвольного случая решения данной задачи был приведен в функции DeleteSymbol() в предыдущем параграфе.
116
Рассмотрим также пример использования функции strstr():
char *s, *t;
s = "this is a test!!!"; t = "a test";
printf("%s\n", strstr(s, t));
После выполнения данных строк на экранепоявится такой результат: a test!!!.
Функцию strstr можно также использовать для подсчета количества вхождения некоторой строки t в строку s:
int Count(char *s, char *t)
{
int count = 0;
while (s = strstr(s, t))
{
count++;
s++;
}
return count;
}
С помощью функций strstr и strcpy также можно организовать удаление всех вхождений строки t в строку s:
void Del(char *s, char *t)
{
int len; char *ps;
len = strlen(t); ps = s;
while (ps = strstr(ps, t)) strcpy(ps, ps + len);
}
117
Функция strtok() применяется для разбиения строки на лексемы, ограниченные разделительными символами (пробелы, знаки пунктуации). Первое обращение к strtok() возвращает значение указателя на первый символ первой лексемы в строке s и записывает нулевой символ (‘\0’) в s непосредственно за возвращенной лексемой.
#include <stdio.h> #include <string.h>
#define DELIMITERS " .,:;\n\t" /* символы-разделители */ int main( )
{
char sentence[500]; /* строка, разбиваемая на лексемы */ char *word; /* адрес начала очередной лексемы в строке */ fgets(sentence, 500, stdin);
word = strtok(sentence, DELIMITERS); while (word != NULL)
{
puts(word);
word = strtok(NULL, DELIMITERS);
}
return 0;
}
При последующих обращениях с нулевым значением первого аргумента функция strtok() продолжает разбивать ту же строку на лексемы. Аргумент NULL показывает, что при вызове strtok() должна продолжать разбиение с того места строки sentence, которое было записано при последнем вызове функции. Большим недостатком данного метода является то обстоятельство, что строка sentence после действия функции strtok будет испорчена. Ниже будет показано как можно писать свои (очень быстрые) алгоритмы выделения слов из строки.
Приведенные выше функции из библиотеки <string.h> можно легко прописать и самостоятельно. Ниже, в качестве примера, приведены два варианта функции Strlen() с использованием указателей, которые возвращают длину строки s.
118