Основы программирования. Учебное пособие
.pdf5.3. ПРЕДСТАВЛЕНИЕ ТЕКСТА В ОПЕРАТИВНОЙ ПАМЯТИ
Исходный текст – это, как правило, последовательность символов, состоящая из слов, разделенных символами-разделителями и оканчивающаяся символом-признаком конца текста. При выборе структуры данных для отображения текста в оперативной памяти надо стремиться
ктому, чтобы текст занимал минимально необходимый объем памяти,
ивыбранная структура предоставляла средства для быстрого (непосредственного) обращения к элементам текста, которыми, как правило, являются его слова. Таким требованиям отвечает структура данных – массив. Текст можно представить:
1)массивом с элементом строкового типа, представляющим слово текста. Размер строки равен максимальной длине слова плюс один (символ ′\0′). Количество элементов массива равно максимальному числу слов в тексте. Обращение к элементу массива это обращение к слову. Чтобы создать такую структуру, надо читать текст посимвольно, помещая каждое очередное слово в новую строку массива и добавляя к слову символ ′\0′ или пословно.
Пример задания последовательности слов:
Дана последовательность, содержащая от 1 до 10 слов, в каждом из которых от 1 до 7 строчных латинских букв. Представить такую последовательность можно:
char text1[10][8], k;
Так как количество слов является меняющейся величиной (от 1 до 10 слов), то требуется еще ввести в употребление переменную k содержащую фактическое количество слов. Диапазон значений k : 1 ≤ k ≤ 10.
Либо представить: char text2[11][8];
Здесь для возможности определения фактического наличия слов используется дополнительное слово являющееся признаком конца последовательности слов. Таким признаком может являться пустое строковое значение. Обращение к слову: text1[i] (0≤ i ≤ k-1), text2[j] (0≤ j ≤ 10). Если text2[j] ==" ", то это пустое слово – признак конца последовательности слов.
Ввод слова можно осуществлять посимвольно или использовать функцию scanf со спецификацией преобразования %s, «нуль-символ» добавляется к строке в этом случае автоматически. Вводимое слово во входном файле должно завершаться символом перевод строки ′\n′ или
41
пробелом, который не включается в результирующую строку. Если вводимое слово завершается каким-то другим символом, то спецификация преобразования %s записывается в виде: %[^,.], где ,. это символы, которыми может завершаться слово;
2) одномерным массивом – строкой. Такая структура полностью соответствует внешнему представлению текста. Размер массива равен максимальной длине исходного текста с учетом разделителей слов. Чтобы обратиться к слову, необходимо последовательно просматривать символы массива, обнаруживая очередной символ-разделитель, который завершает текущее слово, за ним начинается новое слово. Так продолжаем, пока очередное слово не завершится признаком конца
строки.
Для создания массива-строки можно использовать функцию gets (из библиотеки stdio.h) – cчитывание строки из стандартного входного файла. Исходный текст во входном файле должен завершаться символом перевод строки ′\n′, который не включается в результирующую строку, символ ′\0′ добавляется к строке автоматически. Также можно использовать функцию scanf со спецификацией преобразования %s.
Для выделения слова из строки можно использовать функцию работы со строками strtok.
Например:
{
char stroka[80], sl[8], *razd = ", .;:?! "; gets (stroka);
sl = strtok (stroka, razd); while ( sl )
{
обработка выделенного слова sl; sl = strtok (NULL, razd);
}
}
42
5.4.ЗАДАЧИ И РЕШЕНИЯ
1.Определить необходимые переменные и записать последовательность операторов для решения задачи: дана последовательность не более чем из 40 латинских букв, за которыми следует пробел. Преобразовать ее следующим образом:
а) первое вхождение abc заменить на ABC;
char st [41], *r; scanf ("%s", &st); r =strstr (st, "abc");
if (r) { *r = ′A′; *(r+1) = ′B′; *(r+2) = ′C′; } printf ("\n %s ", st);
б) удалить все вхождения th;
char st [41], *r; scanf ("%s", &st); r = strstr (st, "th");
while (r) { strcpy (r, r + 2); r = strstr (r, "th"); printf ("\n %s ", st);
в) после каждой буквы a добавить букву s .
char st [81], *r, pr[80] = " "; scanf ("%s", &st);
r = strchr (st, ′a′);
while (r) { strcpy (pr, r + 1); *(r + 1) = ′s′;
strcpy (r + 2, pr); r = strchr (r + 2, ′a′);} printf ("\n %s ", st);
2. Написать программу решения задачи: дана последовательность, содержащая от 1 до 30 слов, в каждом из которых от 1 до 10 строчных латинских букв; между соседними словами запятая, за последним словом – точка. Найти все слова отличные от последнего и удовлетворяющие следующему свойству:
а) длина слова максимальна;
#include < string.h >
#include <stdio.h >
#include <conio.h >
const int m = 30; const int n = 11;
43
void main ( )
{
int k, i, j, l;
char A[m][n], B[m][n], max, sym = ′s′;
printf ("\n введите последовательность: "); i = 0;
while ( sym != ′.′ )
{ scanf ("%[^,.] ", &A[i]); scanf ("%c ", &sym); i++;} j = -1; for (k = i, i = 0, max = 0; i < k; i++ )
if ( strcmp (A[i], A[ k -1])
{l = strlen (A[i]); if ( l > max)
{max = l; j = 0; strcpy (B[j], A[i]);} else
if ( l == max) { j++; strcpy (B[j], A[i]);}
}
printf ("\n ");
for ( i = 0; i <= j; i++ ) printf (" %s ", B[i],);
getch ( );
}
б) первая буква слова входит в него еще раз;
#include < string.h >
#include <stdio.h >
#include <conio.h > const int m = 30; const int n = 11; void main ( )
{
int k, i, j;
char A[m][n], B[m][n], sym = ′s′;
printf ("\n введите последовательность: ");
44
i = 0; while ( sym != ′.′ )
{ scanf ("%[^,.] ", &A[i]); scanf ("%c ", &sym); i++;} j = -1; for ( k = i, i= 0; i < k; i++ )
if ( strcmp (A[i], A[ k - 1]) && strchr (A[i], A[i][0]) { j++; strcpy (B[j], A[i]);}
printf ("\n ");
for ( i = 0; i <= j; i++ ) printf (" %s ", B[i],);
getch ( );
}
3. Написать программу решения задачи: дана последовательность, содержащая от 1 до 30 слов, в каждом из которых от 1 до 10 строчных латинских букв; между соседними словами пробел, за последним словом – точка. Напечатать все слова отличные от последнего слова, предварительно преобразовав каждое из них по следующему правилу:
а) перенести последнюю букву в начало слова;
#include < string.h >
#include <stdio.h >
#include <conio.h >
const int m = 30; const int n = 11; void main ( )
{
int k, i, j;
char A[m][n], B[n], sym = ′s′;
printf ("\n введите последовательность "); i=0; while ( sym != ′.′ )
{ scanf ("%[^ .] ", &A[i]); scanf ("%c ", &sym); i++;} printf (" \n ");
for (k = i, i = 0; i < k - 1; i++ ) if ( strcmp (A[i], A[ k - 1]) )
{ j = strlen (A[i]) - 1; sym = A[i][j]; strcpy (B, A[i]); strcpy (&A[i][1], B); A[i][0] = sym;
printf (" %s ", A[i],);} getch ( );
}
45
б) удалить из слова все последующие вхождения первой буквы.
#include < string.h >
#include <stdio.h >
#include <conio.h > const int m = 30; const int n = 11;
void main ( )
{
int k, i, j, p;
char A[m][n], B[m][n], sym = ′s′;
printf ("\n введите последовательность "); i=0; while ( sym != ′.′ )
{ scanf ("%[^ .] ", &A[i]); scanf ("%c ", &sym); i++;} printf (" \n ");
for (k = i, i = 0; i < k - 1; i++ ) if ( strcmp (A[i], A[ k - 1])
{p = strchr (&A[i][1], A[i][0]); while (p)
{strcpy (p, p + 1); p = strchr (p, A[i][0]);
printf (" %s ", A[i],);} getch ( );
}
ТЕМА 6
ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ ПОДПРОГРАММ
6.1. ДЕКОМПОЗИЦИЯ ЗАДАЧИ
При нисходящей разработке проектирование программы ведется «сверху-вниз». В решаемой задаче сначала выделяется небольшое число достаточно самостоятельных, более простых задач (подзадач), а в проектируемой программе намечается соответствующее число блоков (частей программы), каждый из которых предназначен для решения
46
одной из подзадач. Определяется функциональное назначение каждого блока (модуля): что он должен делать, какие данные являются исходными для блока, какие – результатами. Если какие-то из подзадач оказываются достаточно сложными (алгоритмы их решения не являются очевидными), то к каждой из них применяется аналогичный процесс выделения подзадач. Этот процесс пошаговой детализации продолжается до тех пор, пока каждый из выделенных блоков программы не окажется таким, что его реализация (кодирование) на выбранном языке программирования уже не вызовет трудностей. Таким образом, программа может иметь многоуровневую структуру (см. рис.2). Если на каждом шаге детализации будут использоваться принципы структурного программирования, то это обеспечит хорошую структурированность и программы в целом.
Главный (управляющий) модуль (М1) |
|
|
Модуль 1 уровня |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Модули 2 уровня |
|
|
|
|
|
|
|
|
|
|
М2 |
М3 |
|
М4 |
|
|
||||
|
|
|
|
|
|
|
|
|
Модули 3 уровня |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
М5 |
М6 |
и т. д. |
|||
|
|
|
|
|
|||||
Рис. 2
6.2.ПОНЯТИЕ ПОДПРОГРАММЫ
Вязыках программирования одним из средств реализации модульной структуры программы является метод подпрограмм.
Подпрограмма – это самостоятельная программная единица, которая позволяет выделить из программы частичный алгоритм и записать его только один раз, но использовать столько раз, сколько это необходимо. В языке Си подпрограмма является минимальным исполняемым модулем программы.
Основные свойства подпрограмм:
1) подпрограмма должна иметь один вход и один выход; 2) подпрограмма должна решать самостоятельную задачу по прин-
ципу одна подпрограмма – одна функция. Например, ввод линейного массива, вычисление произведения матриц, поиск наибольшего элемента в одномерном массиве и т. д.;
47
3)подпрограмма должна возвращать управление в ту часть программы, которая ее вызвала;
4)подпрограмма может вызывать другую подпрограмму, в том числе и саму себя, в последнем случае мы имеем дело с рекурсивной подпрограммой;
5)подпрограмма должна настраиваться на входные данные вызывающей части и возвращать в вызывающую часть результат своих вычислений;
6)размер подпрограммы желательно ограничивать одной-двумя
страницами исходного текста.
Каждой подпрограмме дается имя, которое используется для активации действий, описанных в подпрограмме (вызова подпрограммы) в тех местах программы, где необходимо их выполнить. В точке вызова подпрограммы управление передается ее первой команде. Выполнение подпрограммы завершается действиями по возвращению управления в точку вызова – т. е. команде, непосредственно следующей за точкой вызова, называемой точкой возврата.
Таким образом, в структурированной программе между программными единицами устанавливается отношение вызываемая – вызывающая. Схема взаимодействия вызывающей и вызываемой может быть следующей:
Подпрограмма А |
В. . . |
С . . . |
В . . . |
Подпрограмма В |
С . . . |
Подпрограмма С |
Синтаксически подпрограмма состоит из:
–определения подпрограммы,
–обращения к подпрограмме.
Определение подпрограммы:
<определение подпрограммы> ::= <заголовок подпрограммы> <тело подпрограммы>
48
Тело подпрограммы является описанием того частичного алгоритма, который объявляется подпрограммой.
Заголовок подпрограммы задает ее имя и определяет ее входные и выходные данные.
Обращение к подпрограмме служит для ее активации. Большинство языков программирования допускает подпрограммы
двух видов – подпрограммы-процедуры и подпрограммы-функции (или просто процедуры и функции). В отличие от процедуры функция реализует функциональную зависимость, у которой обязательно должен быть хотя бы один результат. Кроме того, результат функции может быть, как правило, простого типа.
6.3. ФУНКЦИИ ЯЗЫКА СИ
Программа на языке Си это совокупность подпрограмм – функций (в дальнейшем просто функций), среди которых выделяется одна обязательная (главная) с именем main. Остальные функции вводятся в
структуру программы для улучшения ее структурированности. Их выполнение инициируется прямо или косвенно вызовами из функции main.
В простом случае определение функции на языке Си:
<Определение функции> ::= <заголовок функции> <блок> <заголовок функции> <составной оператор>
Таким образом, тело функции задается блоком (блок это последовательность спецификаций переменных и операторов, заключенная в фигурные скобки) или составным оператором.
<Заголовок функции> :: =
< тип результата функции> <имя функции> ( [ <cписок формальных параметров> ] )
| void <имя функции> ( [ <cписок формальных параметров> ] )
В заголовке функции задается тип ее результата, если функция имеет возвращаемый результат (будем называть его основной результат), иначе тип void. Функция с типом void является подпрограммойпроцедурой. Список формальных параметров, если он не опущен, содержит перечисленные через запятую спецификации формальных параметров. В теле функции, если она возвращает результат, обязательно должен быть хотя бы один оператор возврата в точку вызова:
return <выражение>;
49
Выражение определяет возвращаемый (основной) результат, его тип описан в заголовке функции. Если функция не возвращает никакого значения (т. е. имеет тип void), оператор возврата может опускаться.
Обращение к функции, возвращающей основной результат, это первичное выражение вида:
<имя функции>(<список фактических параметров>)
или <имя функции> ( ) , если у функции нет формальных параметров.
Вызов такой функции является операндом какого-либо выражения. Синтаксически обращение к функции, не возвращающей результат,
задается также, но в этом случае обращение – это оператор вызова: <имя функции>(<список фактических параметров>);
или <имя функции> ( );
Одним из важных моментов при организации подпрограмм является задание данных, над которыми будут выполняться действия подпрограммы. Данные в подпрограмму можно передавать двумя способами: 1) используя для этого глобальные объекты, 2) используя формальные параметры.
6.4. ФУНКЦИИ БЕЗ ПАРАМЕТРОВ
Если используется только первый способ, то в определении подпрограммы (ее теле) непосредственно используются данные определенные вне тела функции. Такие подпрограммы не имеют параметров.
Пример определения функции без параметров (задача нахожде-
ния наибольшего значения из двух переменных): int MAX1( )
{ return a > b ? a : b ; }
Функция MAX1 может выполнять действия только над переменными a и b (входные данные функции). Переменные a и b должны быть определены вне функции и называются внешними или глобальными переменными. Тело функции MAX1– составной оператор. Обращение к функции MAX1 – операнд выражения, например: x = MAX1 ( ); Переменной x будет присвоено значение функции MAX1, т. е. наибольшее из значений a и b.
В таких подпрограммах жестко зафиксированы объекты, над которыми выполняются действия подпрограммы. Если необходимо применить эту подпрограмму для других объектов требуется изменение самих глобальных объектов (их имен) в теле подпрограммы.
50
