Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

LS-Sb87108

.pdf
Скачиваний:
36
Добавлен:
13.02.2021
Размер:
393.97 Кб
Скачать

void OutResultL(ofstream* f, unsigned N);

};

// реализация функций класса StrLType вне его определения void StrLType::InputStrL(ifstream* f)

{ … }

void StrLType::ProcessL(unsigned* N); { … }

void StrLType::OutResultL(ofstream* f, unsigned N); { … }

class StrMType

{char Mk; char StrM[MaxLen+1]; public:

void InputStrM(ifstream* f); void ProcessM(unsigned* N);

void OutResultM(ofstream* f, unsigned N);

};

// реализация функций класса StrMType вне его определения void StrMType::InputStrL(ifstream* f)

{ … }

void StrMType::ProcessL(unsigned* N); { … }

void StrMType::OutResultL(ofstream* f, unsigned N);

{… }

//основная функция работает с объектами соответствующих классов void main()

{unsigned N_Space=0;

StrLType StrL; StrMType StrM; // оба варианта представления строк объектами классов

if((ch=='L')||(ch=='l')) {StrL.InputStrL(&f_in); StrL.ProcessL(&N_Space); StrL.OutResultL(&f_out, N_Space);

}

else {StrM.InputStrM(&f_in); StrM.ProcessM(&N_Space);

StrM.OutResultM(&f_out, N_Space);

}

cout<<endl<<"Конец работы. "<<endl;

}

21

2.7. Задания на представление и обработку строк

Для практических занятий и выполнения лабораторных работ могут быть использованы задания из [2, разд. 3]: задачи 1–29 (с. 35–37).

3. МОДУЛИ. МНОГОМОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ

На данном этапе рассмотрения процесса программирования в качестве модуля рассматривается фрагмент программы, оформленный в виде отдельного файла, который компилируется автономно от аналогичных фрагментов программы. При таком подходе части программы, которые включаются в ее текст на основе препроцессорной директивы include, модулями не являются.

Трансляция многомодульной программы предусматривает следующие стандартные этапы:

1)предварительный этап, заключающийся в препроцессорной обработке препроцессорных директив, содержащихся в исходном тексте программы, с получением «чистого» текста программы без этих директив;

2)собственно первый этап трансляции, проводимый над преобразованным текстом программы с целью получения модулей объектного кода (имеющих расширение obj) на машинно-зависимом языке с собственным адресным пространством;

3)вторая стадия трансляции, объединяющая все полученные на первом этапе объектные модули, а также имеющиеся в системе программирования стандартные модули и библиотеки (с расширение lib), реализующие базовый набор операций, в единый исполняемый модуль (с расширением exe). При этом согласуются размещенные в программе внешние имена (переменные, объекты и функции) и выстраивается единое адресное пространство.

На рисунке представлен общий взгляд на этапы трансляции.

Наличие этапного процесса трансляции с разделением текста программы на модули с переводом их в объектный код и последующим объединением только на втором этапе ускоряет процесс трансляции. Тем же способом подключаются все стандартные функции, которые оформлены в стандартные библиотеки объектных модулей. От программиста требуется составить перечень имен своих модулей в соответствии с правилами используемой среды программирования. Если модуль имеет расширение cpp, то он будет подвергнут всем этапам. Если же подключается объектный модуль с расширением obj, который уже предварительно сформирован, то он будет обрабатываться только на втором этапе. А стандартные библиотечные модули под-

22

ключаются на втором этапе автоматически в том случае, если в программе требуется обращение к именам, определенным в таких модулях.

 

 

 

 

Файл 1

 

 

 

 

 

 

 

Файл 2

 

. . .

 

 

 

Файл m

 

 

 

 

 

 

 

( *f1.h )

 

 

 

 

 

 

( *f2.cpp )

 

 

 

 

( *m.h )

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Включение include

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

. . .

 

 

 

 

$

 

 

 

Модуль 2

 

 

 

 

Модуль 3

 

 

 

Модуль N

 

 

 

Модуль 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(файл *1.cpp)

 

 

(файл *2.cpp)

 

 

 

(файл *3.cpp)

 

 

 

 

 

(файл *N.cpp)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0-й этап препроцессорной обработки

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Модуль 1

 

 

Модуль 2

 

 

 

 

Модуль 3

 

 

 

 

 

 

Модуль N

 

 

 

(без директив)

 

 

(без директив)

 

 

 

(без директив)

 

 

 

 

 

(без директив)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1-й этап подготовки объектного кода

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Модуль 1

 

 

Модуль 2

 

 

 

 

Модуль 3

 

 

 

 

 

 

Модуль N

 

 

 

(файл *1.obj)

 

 

(файл *2.obj)

 

 

 

 

(файл *3.obj)

 

 

 

 

 

(файл *N.obj)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2-й этап редактирования внешних связей

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Стандартные модули

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Стандартные

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

объектного кода

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

библиотеки

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(файлы *.obj)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(файлы *.lib)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Исполняемый

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

модуль (файл *.exe)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Этапы трансляции программы

Рекомендуется объединять в модуль (текстовый файл) реализации функций, имеющих сходный смысл. Например, работа по вводу/выводу информации через внешние устройства, работа с файлами, функциональная обработка, расчетные операции и т. д. Названия объектных файлов соответствуют названиям файлов с исходными модулями. Название исполняемого файла формируется автоматически в соответствии с соглашениями по именованию соответствующей среды программирования.

В качестве основных преимуществ модульного программирования и этапной процедуры трансляции можно выделить следующие:

1) такой механизм позволяет повысить эффективность разработки сложных программ, так как транслируются только те модули, которые были изменены либо включают (директивой include) измененные файлы;

23

2) появляется возможность формировать исполняемый модуль на основе модулей, созданных на разных языках программирования, через этап редактирования внешних связей, так как формат объектных модулей единый.

Пример. Рассмотрим программу, состоящую из двух модулей и одного подключаемого файла описаний разработанных в одном из модулей функций. Задача заключается в перемножении минимума имаксимуматрех чисел.

// Модуль 0 (fundef.h) – заголовочный с описаниями функций float min(float, float, float); // минимальное значение из 3

float max(float, float, float); // максимальное значение из 3

//Модуль 1 (mod1.cpp) – основной

#include <iostream.h> #include "fundef.h" void main ()

{float a = -8.72, b = 1.34, c = 9.23;

//вывод на экран произведения минимального и максимального чисел cout << "Для " << a << ", " << b << ", " << c << "\n"

"Результат их min * max = " << max(a, b, c) * min(c, b, a) << "\n";

}

// Модуль 2 (mod2.cpp) – вспомогательный float max(float a, float b, float c)

{if(a > b)

{if(c > a) return c; else return a;} else

{if(b > c) return b; else return c;}

}

float min(float a, float b, float c) {if(a < b)

{if(c < a) return c; else return a;} else

{if(b < c) return b; else return c;}

}

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

4. ПРЕДСТАВЛЕНИЕ И ОБРАБОТКА ТЕКСТА КАК НАБОРА СТРОК

Синтаксис языка С++ позволяет объединять структуры (классы) в массивы структур (классы), но правильнее говорить о массивах объектов соответствующих структур (классов). Объявляют такие массивы аналогично объявлению массива переменных.

24

Пример 1. Рассмотрим программу, предназначенную для обслуживания хранения учетных данных. Пусть необходимо иметь сведения о фамилии, городе рождения, зарплате, номерах дома и квартиры служащего.

#include <iostream.h> struct worker

{char *name, town[15]; int salary, Numb[2];};

worker Otdel[ ] = // фактическая инициализация массива служащих

{{ "Петров", "Москва", 5800, { 2, 17 } },

{"Артемов", "Таллин", 4500, { 16, 23 } },

{"Яблоков", "Иркутск", 6200, { 30, 4 } },

{NULL, "", -1, { -1, -1 } } // Признаки конца списка служащих

};

void main() {worker* p;

p = &Otdel[1]; // Обращение к информации об Артемове

cout << p->name << " родился в " << p->town << ", имеет зарплату " << p->salary

<<", номера дома и квартиры: " << p->Numb[0] << ", " << p->Numb[1] << "\n";

//Выводим на экран весь массив служащих

for(p = Otdel; p->name; p++ )

cout << p->name << " родился в " << p->town << ", имеет зарплату " << p->salary << "\n";

}

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

Для лучшего восприятия при работе со структурами (классами), массивами на их основе и указателями большую помощь оказывают рисунки.

По аналогии с рассмотренным примером при решении задач по обработке текста для его структурированного представления в программе можно использовать вложенное совмещение структур (классов). Первая из них должна содержать 2 элемента:

1)число – фактическое количество строк в тексте;

2)массив, который в качестве элементов содержит символьные строки, представленные второй структурой (классом) по одному из рассмотренных

25

ранее вариантов – с длиной (рис. 4.1) или маркером, причем, если маркер единый для всех строк, то он может быть вынесен в первую (рис. 4.2).

 

Массив

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1-й символ

Последний символ

 

 

символьных

 

 

 

 

 

 

 

 

 

 

 

 

 

 

строк

 

 

 

 

 

 

Представление

 

 

 

 

Число символов в строке

 

 

1-я строка

 

 

 

 

1-й строки

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k-я строка

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1-й символ

Последний символ

 

 

M-я строка

 

 

 

 

 

 

 

Представление

 

 

 

 

 

 

 

 

 

 

 

 

 

Число символов в строке

 

 

Число k

 

 

 

 

последней (k-й строки)

 

количество

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

строк

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 4.1. Структурное представление текста (с длиной)

Массив символьных строк

1-й символ

Маркер

1-я строка

Представление 1-й строки

 

 

 

 

 

k-я строка

 

 

 

1-й символ

Маркер

M-я строка

Представление последней (k-й строки)

 

Число k – количество строк

 

 

 

Единый маркер

 

 

 

Рис. 4.2. Структурное представление текста (с маркером)

Проанализируйте реализацию на языке С++ представленных на рисунках вариантов:

const unsigned M=20, // максимально возможное число строк

N=78; // максимально возможное для размещения число символов в строке

struct strLen

{char Str[N]; unsigned Len; /* фактическая длина строки */}; struct txtLen

{strLen T[M]; unsigned k; /* фактическое число строк текста */}; struct strMark {char Str[N+1];};

struct txtMark

{strMark T[M]; unsigned k; /* фактическое число строк текста */ char Mark; /* единый маркер для строк*/};

26

Целесообразно размещать исходный текст в файле, а затем загружать его в программу. Однако в связи с ограничением на количество размещаемых

вмассивах элементов могут возникнуть ограничения как на количество фактически читаемых из файла строк, так и на число символов в каждой строке. В этом случае программа будет работать не с исходным текстом, а с его усеченным вариантом, что в большинстве случаев может привести к искажению желаемого результата.

Для устранения этого недостатка можно разбить исходный текст в файле на логические блоки по максимально возможному для представления числу строк и предельному количеству размещаемых в них символов. Программа же должна подкачивать в память необходимый для работы логический блок. Такой вариант реализации подходит для случаев, когда текст из файла можно использовать без изменений. Если же необходима модификация содержимого очередного логического блока (при изменении в нем числа строк или количества символов в отдельных строках), появляется задача приведения содержимого исходного файла в соответствие с осуществленными изменениями, что может оказаться достаточно затруднительным.

Более интересный и эффективный для случая модификации текста вариант заключается в использовании динамических массивов в обеих структурах. В этом случае необходимо предварительно определить количество строк

вфайле и выделить по нему в памяти динамический массив указателей на предполагаемый вариант реализации строк. Для каждой строки необходимо определять фактическое число символов в ней и также выделять для их размещения динамический массив. В этом случае базовый набор структур (классов) предстанет в обновленном виде:

struct strLen

{char* pStr; // указатель на динамически выделяемую память unsigned Len; // фактическое число символов в строке

};

struct txtLen

{strLen** pT; // указатель на динамический массив указателей на динамические строки unsigned k; // фактическое число строк

};

struct strMark {char* pStr; /* последним символом всегда будет маркер*/}; struct txtMark

{strMark** pT; // указатель на динамический массив указателей на динамические строки unsigned k; // фактическое число строк

27

char Mark; };

Пример 2. Рассмотрим программу, обеспечивающую выделение слов, заканчивающихся на определенный символ, в тексте, читаемом из файла в ограниченную структуру представления. Реализация основана на модульном разбиении программы. Справа представлена модификация фрагментов программы при работе с динамически выделенной памятью для строк.

// TYPES.h – файл определения типов для представления исходного текста и результата

const unsigned MaxStr=30,MaxLen=60;

 

const int MaxWords=MaxStr*MaxLen/2;

 

struct S // строка с длиной

struct S

{char str[MaxLen]; unsigned dl;};

{char* str; unsigned dl;};

struct T // текст как массив строк с длиной

 

{S txt[MaxStr]; unsigned Len;};

 

struct W // набор выделенных слов

 

{unsigned numberW; S words[MaxWords];};

 

//def.h – описания используемых функций void inputText(ifstream& f, T* txt1);

void outText(ofstream& f, T txt1, W* r1); void NewWords(char bukva, T txt1, W* res1);

//FORMWORD.cpp – модуль с текстом основной функции

#include <fstream.h> #include "types.h" #include "def.h" void main()

{T t1; W Res; char name[20]; ifstream f1; ofstream f2; char sim; cout<<"input file name: "; cin>>name; f1.open(name); if(f1.bad()) cout<<"bad file";

else

if(f1.eof()) {cout<<"no data"; f1.close();} else

{f1.unsetf(ios::skipws); inputText(f1,&t1); f1.close(); cout<<"last symbol: "; cin>>sim; NewWords(sim,t1,&Res);

cout<<"output file name: "; cin>>name; f2.open(name);

if(f2.bad()) cout<<"bad result file"; else {outText(f2,t1,&Res); f2.close();}

}

}

//INTEXT.CPP – модуль ввода строк текста из файла

28

#include <fstream.h>

 

#include <fstream.h>

 

 

#include <stdlib.h>

#include "types.h"

 

#include "types.h"

 

 

void getmem(char** str,unsigned j)

 

 

{*str=new char[j];}

void inputStr(ifstream& f,S& str1)

 

void inputStr(ifstream& f,S* str1)

{char j=0, sim;

 

{unsigned j=0; char sim; long int o;

while(!f.eof()&&(j<MaxLen))

 

f>>sim;

{f>>sim; if(sim=='\n') break;

 

while(!f.eof())

str1.str[j]=sim; j++;

 

{if(sim=='\n') break; j++; f>>sim;}

}

 

str1->dl=j;

str1.dl=j;

 

if(j!=0)

if((sim!='\n')&&(!f.eof()))

 

{getmem(&str1->str,j+1);

while(!f.eof()) {f>>sim; if(sim=='\n') break;}

 

o=-j;

}

 

if(f.eof())

 

 

{f.seekg(o,ios::cur); f.clear();}

 

 

else f.seekg(o-2,ios::cur);

 

 

f.getline(str1->str,j+1,'\n');

 

 

f>>sim;

 

 

} else str1->str=NULL;

 

 

}

void inputText(ifstream& f,T* txt1)

 

 

{char i=0;

 

 

while(!f.eof()&&(i<MaxStr))

 

 

{inputStr(f,(*txt1).txt[i]); i++;}

 

 

txt1->Len=i;

 

 

}

 

 

// OUTWORDS.cpp – модуль вывода строк текста в файл

#include <fstream.h>

 

#include <fstream.h>

 

 

 

#include <stdlib.h>

#include "types.h"

 

#include "types.h"

void OutStr(ofstream& f,S str1)

 

void OutStr(ofstream& f,S str1)

{char j;

 

{char j;

for(j=0;j<str1.dl;j++) f<<str1.str[j];

 

for(j=0;j<str1.dl;j++) f<<str1.str[j];

f<<endl;

 

f<<endl;

}

 

if(str1.str!=NULL) delete []str1.str;

 

 

}

void outText(ofstream& f,T txt1,W* r1)

 

 

{unsigned i;

 

 

f<<"Input:"<<endl;

 

 

for(i=0; i<txt1.Len; i++) OutStr(f,txt1.txt[i]);

 

 

 

 

 

29

f<<endl<<"Result:"<<endl; if(r1->numberW==0) f<<"pusto"<<endl; else

{f<< "Find " << r1->number << " words:" << endl; for(i=0;i<r1->numberW;i++)

OutStr(f,r1->words[i]);

}

}

// SEARCH.cpp – модуль выделения слов, оканчивающихся на определенный символ

#include "types.h"

#include "types.h"

#define false 0

#define false 0

#define true 1

#define true 1

void NewWords(char bukva,T txt1,W* res1)

void NewWords(char bukva,T txt1,W* res1)

{char slovo, fl; char i, j, k, pos, num;

{char slovo,fl; char i, j, k, pos, num;

char unsigned sim; unsigned r=0;

char unsigned sim; unsigned r=0;

for(i=0;i<txt1.Len;i++)

for(i=0;i<txt1.Len;i++)

{j=0; slovo=false; fl=false;

{j=0; slovo=false; fl=false;

while(j<txt1.txt[i].dl)

while(j<txt1.txt[i].dl)

{sim=txt1.txt[i].str[j];

{sim=txt1.txt[i].str[j];

if(((127<sim)&&(sim<176))||

if(((127<sim)&&(sim<176))||

((223<sim)&&(sim<242))||

((223<sim)&&(sim<242))||

(('A'<=sim)&&(sim<='Z'))||

(('A'<=sim)&&(sim<='Z'))||

(('a'<=sim)&&(sim<='z')))

(('a'<=sim)&&(sim<='z')))

{if(slovo==false)

{if(slovo==false)

{slovo=true; pos=j; num=1;}

{slovo=true; pos=j; num=1;}

else num++;

else num++;

if(j==txt1.txt[i].dl-1)

if(j==txt1.txt[i].dl-1)

if(txt1.txt[i].str[j]==bukva) fl=true;

if(txt1.txt[i].str[j]==bukva) fl=true;

}

}

else

else

if(slovo)

if(slovo)

{slovo=false;

{slovo=false;

if(txt1.txt[i].str[j-1]==bukva) fl=true;

if(txt1.txt[i].str[j-1]==bukva) fl=true;

}

}

if(fl==true)

if(fl==true)

{

{res1->words[r].str=new char[num];

for(k=0;k<num;k++)

for(k=0;k<num;k++)

res1->words[r].str[k]

res1->words[r].str[k]

=txt1.txt[i].str[pos+k];

=txt1.txt[i].str[pos+k];

res1->words[r].dl=num; r++; fl=false;

res1->words[r].dl=num; r++; fl=false;

 

 

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]