Программа должна после запуска на исполнение выводить информацию об авторе, назначении программы (приводится лабораторное задание полностью), перед запросом ввода данных с клавиатуры обязательно должно быть сообщение о типе и количестве вводимых данных
Вид материала | Программа |
СодержаниеТема №6. Строки и использование библиотечных функций для их обработки. Краткая теоретическая справка и рекомендации по выполнению Пример выполнения лабораторного задания № 6 |
- Задание для вариантов 1-11, 100.34kb.
- 11. 09. 2008 Практическая работа №1 ms access. Основные приемы работы с данным Задание, 795.97kb.
- Инструкция по эксплуатации и меры предосторожности, 148.38kb.
- Инструкция по эксплуатации и меры предосторожности, 251.98kb.
- Инструкция по эксплуатации и меры предосторожности, 277.51kb.
- Инструкция по эксплуатации и меры предосторожности, 825.93kb.
- Разработка реляционной структуры данных, 255.43kb.
- Р. С. Енгалычев Научный руководитель А. А. Малюк, к т. н., профессор, 26.91kb.
- Любая программа для обработки данных должна выполнять три основных функции: ввод новых, 298.05kb.
- Базы данных, 55.38kb.
Тема №6. Строки и использование библиотечных функций для их обработки.
Задание: Введите с клавиатуры предложение, выделите из предложения отдельные слова в массив слов, проведите преобразование предложения и слов в соответствии с индивидуальным заданием, распечатайте результат обработки на экран монитора. Используйте как можно больше библиотечных функций для работы со строками.
Индивидуальные задания на лабораторную работу даны в конце описания к теме № 6. Длина вводимого предложения не более 80 символов (ширина экрана). При выполнении задания необходимо во всех случаях, где это можно, использовать функции для работы со строками. Все задания подразумевают необходимость применения не менее трех разных функций.
Краткая теоретическая справка и рекомендации по выполнению
Строка в языке Си представляет собой одномерный массив символов, последним элементом которой является символ конца строки – нуль (строка, завершающаяся нулем, то есть NULL terminated string).
Объявление переменной типа строка в языке Си возможно тремя способами, два из которых инициализируют строку во время объявления. Первый способ ничем не отличается от объявления массива символов (не забудьте добавить место для завершающего нуля):
char s[40+1];
Второй способ предусматривает присваивание строковой переменной начального значения (при этом длину строки компилятор может вычислить сам):
char s[] = "Пример инициализации строки";
Справа от знака присваивания записана строковая константа. В конце строки автоматически добавляется ноль ('\0'). Константы символьных строк помещаются в класс статической памяти.
В третьем способе явно не указывается, что используется массив. В левой части от знака присваивания указывается указатель на символ:
char *s="Второй вариант инициализации";
Переменная s будет указателем на то место в оперативной памяти, где располагается строковая константа. В такой форме записи кроется потенциальная ошибка, заключающаяся в том, что указатель на символ часто называют строкой. Представленная ниже запись – это только указатель на символ, так как для размещения строки место не предусмотрено:
char *s;
Для работы со строками есть набор функций. Для ввода со стандартного устройства ввода (клавиатуры) чаще всего используются библиотечные функциями из модуля стандартного ввода-вывода: scanf и gets.
Для ввода строки с помощью функции scanf, использует формат «%s», причем обратите внимание на то, что перед идентификатором строки не используется знак адреса «&», так как одномерный массив уже представлен указателем на его начало:
scanf("%s", s);
Функция gets() считывает символы до тех пор, пока не достигнет символа перехода на новую строку. Функция принимает все символы вплоть до символа перевода строки, но не включает его. К концу строки добавляется завершающий ноль ('\0'). Функция gets() помещает считанную с клавиатуры последовательность символов в параметр типа строка и возвращает указатель на эту строку (если операция завершилась успешно), или NULL (в случае ошибки). В приведенном ниже примере при успешном завершении операции, на экран будет выведено две одинаковые строки:
#include
int main()
{ char s[50];
char *p;
p=gets(s);
printf(" \n Введена строка %s. ",s);
if (p) printf(" \n Введена строка %s. ",p);
return 0;
}
Попутно заметим, что функция gets часто используется для ввода любых данных с клавиатуры в виде строки с целью дальнейшего преобразования функцией sscanf к нужному формату или для предварительного анализа вводимых данных, например:
#include
#include
#include
int main()
{ char s[50]; int x, err;
do
{ printf(" \n Введите целое число -> ");
gets(s);
err=sscanf(s, "%d",&x);
if (err!=1) printf(" \n Ошибка ввода. ");
} while (err!=1);
printf("\n Введено целое число -> %d", x);
return 0;
}
Для вывода строк на стандартное устройство вывода (экран монитора) можно использовать две функции printf и puts. В функции printf в качестве формата передается "%s". Удобство использования этой функции заключается в том, что помимо строки можно сразу выводит данные других типов. Особенность функции puts заключается в том, что после вывода строки автоматически происходит переход на следующую строку.
Для преобразования строк в языке Си предусмотрена библиотека string. Каждая из функций имеет свой формат записи (прототип). Некоторые из функций представлены ниже. Более подробное описание функций смотрите в указанных библиографических источниках.
void *strcat(char *s1,const char *s2) – дополняет строку s1 строкой s2.
char *strncat(char *s1,const char *s2, size_t n) – дополняет строку s1 символами из строки s2, но не более чем n штук.
char *strcpy(char *s1,const char *s2) – копирует строку, указанную указателем s2, на место, указанное указателем s1; возвращает s1.
char *stpcpy(char *dest, const char *src) – копирует строку, указанную указателем src, на место, указанное указателем dest; не копирует символ конца строки;
char *strncpy(char *s1, const char *s2, size_t n) – – копирует строку, указанную указателем s2, на место, указанное указателем s1; возвращает s1; копируется не более чем n символов.
int strcmp(const char *s1,const char *s2) – сравнивает строки, указанные указателями s1 и s2; символы строк сравнивают с помощью значений их кодов; функция возвращает 0, если строки одинаковы; значение, которое меньше 0, если первая строка меньше второй; и значение, превышающее 0, если первая строка больше второй.
int strncmp(const char *s1,const char *s2, size_t n ) – сравнивает первые n символов или до первого пустого символа строки, указанные указателями s1 и s2.
int stricmp(const char *s1,const char *s2) – сравнивает строки, указанные указателями s1 и s2, игнорируя регистр символов (строчные или заглавные);
int strcmpi(const char *s1,const char *s2) – сравнивает строки, указанные указателями s1 и s2, игнорируя регистр символов (строчные или заглавные);
chat *strchr(const chat *s, int c) – ищет первое появление c (преобразованного в char) в строке, указанной указателем s; пустой символ является частью строки; возвращает указатель на первое появление или NULL, если ничего не найдено.
chat *strrchr(const chat *s, int c) – ищет последнее появление символа c в строке, то есть поиск идет с конца строки, заданной указателем s; пустой символ является частью строки; возвращает указатель на первое появление или NULL, если ничего не найдено.
char *strstr(const chat *s1, const char *s2) – возвращает указатель на положение первого появления последовательности символов из s2 в строке s1 (исключая завершающие пробелы); возвращает NULL, если совпадений не найдено.
chat *strtok(chat *s1,const chat *s2) – эта функция переформирует строку s1 в отдельные знаки; строка s2 содержит символы, которые используются в качестве разделителей. Функция вызывается последовательно. Для первого вызова s1 должен указывать на строку, которую необходимо разбить на знаки. Функция находит разделитель, который следует за символом, не являющимся разделителем, и заменяет, его пробелом. Она возвращает указатель на строку, содержащую первый знак. Если ни оного знака не найдено, она возвращает NULL. Чтобы найти следующий знак в строке, необходимо вызвать функцию опять, но первым аргументом поставить NULL. Каждый последовательный вызов возвращает указатель на следующий знак или на NULL, если больше знаков не найдено.
int strlen(const char *s) – возвращает число символов (исключая завершающие пробелы) в строке s.
void setmem(void *dest, unsigned length, char value) – присваивает значение value диапазону памяти, начиная с адреса dest;
size_t strspn(const char *s1, const char *s2) – находит начальный сегмент строки s1, которая состоит из символов строки s2; возвращает длину найденного сегмента.
size_t strсspn(const char *s1, const char *s2) – находит начальный сегмент строки s1, которая не состоит из символов строки s2; возвращает длину найденного сегмента.
char *strdup(const char s) – резервирует оперативную память и помещает на это место копию строки s; возвращает указатель на зарезервированную область памяти.
char *strlwr(char *s) – преобразует все символы строки к нижнему регистру (от a до z); возвращает указатель на строку s.
char *strupr(char *s) – преобразует все символы строки к верхнему регистру (от A до Z); возвращает указатель на строку s.
char *strpbrk(const char *s1, const char *s2) – сканирует строку s1 на присутствие любого символа строки s2; возвращает указатель на найденный символ или NULL, если совпадение не найдено.
char *strrev(char *s) – переписывает символы в строке в обратной последовательности; возвращает указатель на строку s.
char *strset(char *s, int ch) – все символы в строке делает равными ch; возвращает указатель на строку s.
size_t strxfrm(char *s1, char *s2, size_t n) – символы строки s2 заменяет на соответствующие символы строки s1, но не более чем n символов; возвращает количество замененных символов.
Кроме функций для работы со строками в библиотеке string есть ряд функций для преобразования одномерных массивов байтов памяти:
int memcmp (const void *s1, const void *s2, size_t n) – сравнивает два блока памяти, начинающиеся с адресов s1 и s2, но не более, чем n байтов; возвращает 0, если блоки равны, число меньшее 0, если первый блок меньше второго, число большее 0, если первый блок больше второго.
void *memcpy (void *dest, const void *src, size_t n) – копирует блок памяти src в блок памяти dest, но не более, чем n байтов; если блоки пересекаются, то результат не определен.
void *memccpy(void *dest, const void *src, int c, size_t n) – копирует блок памяти src в блок памяти dest; копирование останавливается по достижении количества в n байтов или после копирования символа c.
void *memmove(void *dest, const void *src, size_t n) – копирует блок памяти src в блок памяти dest, но не более, чем n байтов; копирование корректное даже если блоки памяти пересекаются.
void *memchr (const void *s, int c, size_t n) – в блоке памяти в n байтов ищет символ c, начиная с адреса s; если символ найден – возвращается указатель на найденный элемент, в противном случае NULL.
Пример выполнения лабораторного задания № 6
Индивидуальное задание: Слова исходного предложения расположить в обратном порядке. Расположение знаков препинания не менять.
Решение предусматривает выполнение нескольких действий:
- Вывод информации о назначении программы (заголовок программы).
- Ввод исходного предложения.
- Выделение из предложения слов.
- Выделение из предложения разделительных знаков.
- Сборка нового предложения из слов и знаков поочередно.
- Распечатка результата.
В соответствии с общим заданием на лабораторную работу каждое из перечисленных действий должна выполнять отдельная функция. Далее дадим краткие пояснения к каждой из функций. Но сначала опишем общую структуру программы. Программа может строиться так же, как и на языке Паскаль, – сначала объявление функций, а потом основная часть программы. Здесь используем другую форму: сначала будет предварительное объявление функций, потом основная функция, и только потом подробное описание предварительно записанных функций.
Напомним, что при объявлении функций записываются формальные параметры. Параметры могут быть переменными и значениями. Если параметр – это указатель, то это – параметр переменная, в противном случае – это значения. Параметр также будет значением, если он записан как константа.
Функция Title() – без параметров, так как только лишь выводит на экран набор строк.
Функция ввода предложения InpPredl (char predl[]) имеет один параметр – предложение, которое надо заполнить. В записи этого параметра есть сразу два момента, на которые надо обратить внимание: во-первых, в качестве параметра передается одномерный массив символов, то есть указатель (параметр переменная), во-вторых, в записи массива не указана размерность массива, а только открывающие и закрывающие квадратные скобки, так как достаточно передать только адрес начала строки.
Выделение из предложения слов и разделительных знаков реализуется одним алгоритмом, поэтому могут выполняться одной и той же функцией выделения Select(const char *predl, char m[][N],char *sel, int *n). Функция имеет четыре параметра:
- predl – предложение, из которого идет выделение,
- m – массив слов результата (под каждое слово предусмотрен размер в N символов),
- sel – адрес символов, располагаемых между выделяемыми элементами,
- указатель на переменную, в которой будет располагаться количество выделенных элементов, этот параметр используется как переменная, так как есть необходимость сохранить изменения.
Функция сборки нового предложения Constructor(char slova[][N], char razd[][N], int sl, int rz) – это действительно функция, так как возвращает указатель на первый символ полученного предложения. Назначение параметров понятно по названиям: массив слов, массив разделителей, количество слов, количество разделителей.
Вывод предложения функцией OutPredl(char *s1, char *s2) использует два параметра: исходное предложение и результат.
Функция strdup служит для создания в оперативной памяти дубликата передаваемой в качестве параметра строки. Функция strdup запрашивает у операционной системы оперативную память динамически, то есть в процессе работы программы, получает ее и возвращает указатель на занятую область. По завершении работы программы необходимо память опять отдать операционной системе. Это действие выполняется функцией free.
Главная функция последовательно использует (вызывает на исполнение) перечисленные функции одну за другой. Даже если функции используются в программе всего один раз, программа становится гораздо проще и понятнее. Перед вызовом некоторых функций делаются подготовительные операции, например, строчные и заглавные буквы объединяются в единый массив.
Теперь можете проанализировать весь текст программы:
#include
#include
#include
#include
#define N 20
// ПРЕДВАРИТЕЛЬНОЕ ОБЪЯВЛЕНИЕ ФУНКЦИЙ
// Заголовок программы
void Title();
// Ввод предложения
void InpPredl (char predl[]);
// Выделение из предложения
void Select(const char *predl, char m[][N],char *sel, int *n);
// Сборка предложения
char *Constructor(char slova[][N], char razd[][N], int sl, int rz);
// Вывод результата
void OutPredl(char *s1, char *s2);
inline void rus() // Русификация вывода в консольное окно
{
setlocale( LC_CTYPE, ".1251" );
setlocale( LC_MONETARY, ".1251" );
}
// ОСНОВНАЯ ФУНКЦИЯ
int main()
{
// ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ
char predl[80]; // Введенное предложение
char *res; // Результирующее предложение
char slova[N][N]; // Массив слов в предложении
char razd [N][N]; // Массив разделителей в предложении
int sl=-1, rz=-1; // Счетчики слов и разделителей
char buk[80]; // все буквы алфавита
char *bs="йцукенгшщзхъфывапролджэячсмитьбю";// Буквы строчные
char *bz ="ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";/* заглавные */
char *r="`!;:,.?- _"; // Разделительные знаки
//ВЫЗОВ ФУНКЦИЙ НА ИСПОЛНЕНИЕ
rus();
// Заголовок программы
Title ();
// Ввод предложения
InpPredl (predl);
// Выделение из предложения слов
Select (predl, slova, r, &sl);
// Выделение из предложения разделителей
strcpy(buk,"");
strcat (buk, bs);
strcat (buk, bz);
Select (predl, razd, buk, &rz);
// Сборка предложения
res = Constructor(slova, razd, sl, rz);
// Вывод результата
OutPredl (predl, res);
free (res);
return 0;
}
// ОПИСАНИЕ ИСПОЛЬЗУЕМЫХ ФУНКЦИЙ
// Заголовок программы
void Title()
{
puts (" Лабораторное задание по теме № 6\n");
puts (" Во введенном предложении расположите слова");
puts (" в обратной последовательности.");
puts(" Порядок следования знаков препинания не менять.");
puts(" В предложении используются русские буквы и знаки. \n");
}
// Ввод предложения
void InpPredl(char *s)
{
puts("Введите предложение \n");
strcpy (s,"Верите ли вы, что задача решена?");
// gets (s);
}
// Вывод результата
void OutPredl (char *s1, char *s2)
{
puts ("Исходное предложение");
puts (s1);
puts (" Результат ");
puts (s2);
}
// Выделение из предложения
void Select(const char *predl, char m[][N], char *sel, int *n)
{
char *p, *s;
s=strdup (predl); // Сделать копию исходного предложения
// так как передается константа, strtok требует
// внесения изменений при своей работе
p = strtok (s, sel);
while (p)
{
(*n)++;
strcpy (m[*n],p);
p = strtok (NULL, sel);
}
free (s);
}
// Сборка предложения
char *Constructor(char slova[][N], char razd[][N], int sl, int rz)
{
int i, j;
char res[80];
char *s;
*res=0; // Начальное значение результата
i = sl;
j=-1;
while ((i>=0)||(j<=rz))
{
if ((i>=0)) strcat (res, slova[i]); // Добавление слова
i--;
j++;
if ((j<=rz)) strcat (res, razd[j]); // Добавление знаков
}
s = strdup (res);
return s;
}
Контрольные вопросы к теме № 6
- Представление строк в языке Си.
- Примеры инициализации строк в теле программы.
- Библиотечные функции языка Си для обработки строк.
- Библиотечные функции ввода-вывода строк.