Назад | Начало урока | Вперед
Содержание

Глава 2

5 февраля

Кроме класса string и связанного списка,еще интересная тема -ШАБЛОНЫ
#include <vector>
#include <list>
#include <map>

Шаблоны названия которых я знаю:

Последовательные контейнеры:
вектор - vector
список - list
двухсторонняя очередь- deque
стек- stack
очередь- queue
Ассоциативный контейнеры:
карта- map
мулиткарта- multimap
- set
- multiset

Фрагмент программы "класс-контейнер <map>" :

#include <map>
-.-.-.-.-.-.-.-.-.-.
// Объявление шаблона и его функции

template<class T, class A>
void ShowMap(const map<T, A> & v); // функция показать свойства карты

typedef map<string, Student> SchoolClass;//объявление класса SchoolClass
//этот класс объявлен но не инициализирован,а следовательно он пуст
//его необходимо будет инициализировать (заполнить) экземплярами.
//В данном случае это будут студенты
//Этот класс в данном случае объявлен как карта элементов,а у карты есть
//свои свойства а именно -два ключа
-.-.-.-.-.-.-.-.-.

// Display map properties
//Функция которая отображает свойства карты при помощи итератора а также
//при помощи выражений ci->first и ci->second

template
void ShowMap(const map& v) {

for (map::const_iterator ci = v.begin();
ci != v.end(); ++ci)
cout << ci->first << ": " << ci->second << "\n";

cout << endl;

}


Может быть можно создать класс допустим по имени EnergoSchet
в котором отображено имя месяца-номер года (для быстрого доступа к нему),
(по аналогии с имя студента -возраст).А внутри этого класса
могут находиться такие данные как расход энергии:показания
счетчиков 1 и 2 тариф,активной и реактивной энергии .И высчитываться
потребление за месяц этих видов энергии.

Или можно создать допустим класс ZarplataMoya в него входят
имя месяца - номер года как два ключа для поиска в массиве типа
И внутри класса данные о вычетах и так далее все данные по зарплате.

Или можно создать допустим класс ZarplataImya в него входят
имя работника - номер месяца как два ключа для поиска в массиве типа
И внутри класса данные о вычетах и так далее все данные по зарплате
этого работника.

Выделить надо отдельную директорию для помещения туда объявлений и определений различных классов ,таких как класс Student,Animal,EnergoSchet,
Cat и прочие,чтобы можно было лучше разобраться в строении классов вообще.

Продолжить работу над шаблонами
Почему то компилятор Borland отказался сегодня компилировать
примеры из главы 19 Либерти.А компилятор Microsoft нормально
работал в этих программах!.

8 февраля

1.То есть как инициализировать массив типа string данными из текстового
файла?
Надо сделать так,чтобы программа считывала из текстового файла слова
и выводила их в массив указателей,который объявлен и находится в
динамической допустим памяти.
Этот массив можно будет передавать в функции и тд.
Например этот массив можно будет поместить в функцию,которая сортирует слова
по алфавиту.А потом отсортированные слова поместить снова в текстовый
файл.

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

Дополнение на эту тему (от 22 февраля)

Вышеуказанная задача решена в программе :

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

Думаю надо сделать так:

Module1(string * curword5) {

int kolSlov=490;
curword5 = new string[kolSlov];
string * pStr5 = curword5;

while(!eof) {
for(int i=0;i < kolSlov;I++) {
fin1>>curword5[i];
}
}
}

main() {

string pCurword5;
Module1(&pCurword5);
}


Или такой вариант:

Module1(string * pStr5) {

int kolSlov=490;

string * curword5 = new string[kolSlov];
pStr5 = curword5;

while(!eof) {

for(int i=0;i < kolSlov;I++) {
fin1>>curword5[i];
}
}
}

main() {

string pCurword5;
Module1(&pCurword5);
}

Или как частный случай предыдущей задачи:
Если переменная расположена в динамической памяти,и на нее указывает
указатель. То как передать этот указатель в другой модуль,чтобы он и там
указывал на эту переменную ?

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

Пример инициализации массива указателей на тип string ,словами
из тексового файла,а затем инициализация отдельных объектов
типа стринг находится по адресу :
В программе

2.Или еще задача.Считывается слово из текстового файла,присваивается
переменной типа string ее имя допустим temp.Затем эта переменная проверяется
подходит ли она нам по тем или иным параметрам,например по длине и
если подходит то записываем ее в новый текстовый файл,если не подходит
то очищаем эту переменную (clear()).Так в цикле можно перешерстить весь
исходный текстовый файл.

Вышеописанные действия делаются у меня в программе, где слова сортируются
на предмет убирания повторяющихся слов.
Пример в программе по адресу:

3.Еще тема:
Надо создать фрагменты текстов программ где проверяются входные значения
от неправильного ввода.Эти фрагменты должны использоваться почти во всех
программах.
Примеры по адресу:

13 февраля

Считывать из файла слова можно так:
Считал из файла слова в массив указателей на тип string,
затем записал в новый файл,но уже с кавычками спереди и сзади.
Если перед тем,как выводить этот массив слов в файл вывести
название и двойной индекс,то получится файл,в котором инициализирован
двумерный массив типа char.И не надо будет как дятел стучать
подолгу вводя кавычки,а просто перенести этот фрагмент в ту программу,
которая у меня сортирует слова по алфавиту.
Еще замечание:при считывании слов из файла надо инкременировать
переменную,чтобы потом использовате ее в качестве индекса
в цикле вывода слов в следующий файл.И использовать еще одну
переменную которая будет указывать на количество букв в слове.
Здесь речь идет только о таких файлах,в которых все слова
уже отсортированны по длине.
Программа на эту тему написана!13 февраля05г
Пример такой программы в файле:

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

2.Неожиданно возникла проблема:как вывести в файл двойные кавычки,
затем слово(объект типа string) затем снова двойные кавычки?
Любой знак выводится,а кавычки нет!
Проблема решена!Кавычки выводятся при помощи cout<<"\"";

Писать далее программу которая составляет кроссворд Ромб

14 февраля

Как уже говорилось функция может возвращать только одно значение.
Что делать если необходимо получить от функции сразу два значения?
Решением этой проблемы является передача функции по ссылкам двух объектов.
В ходе выполнения функция присвоит этим объектам нужные значения.
--------------------------------------------------------------------------
Передача объектов по ссылке,позволяющая функции изменить исходные объекты,
равносильна разрешению функции возвратить два значения.
---------------------------------------------------------------------------
В этом случае можно обойтись вообще без возвращаемого значения,
которое(зачем же добру пропадать ) можно использовать для сообщения
об ошибках.

Вот примеры использования в программах вышеприведенных идей:

1. Listing8_11.cpp

bool GetWord(char* theString,
char* word, int& wordOffset);
Программа которая выделяет из текста отдельные слова и помещает
их каждое с новой строки.
Эдесь char* theString и char* word -переменные типа char
int& wordOffset - числовая переменная типа int

Это очень эффективная и красивая программа.

2.Listing9_8.cpp
Вот функция:
short Factor(int n, int *pSquared, int *pCubed) {

short Value = 0;
if (n > 20)
Value = 1;
else {
*pSquared = n*n;
*pCubed = n*n*n;
Value = 0;
}
return Value;
}


а вот она вызывается в программе:
int number, squared, cubed;//объявление переменных
short error;

cout << "Enter a number (0 - 20): "; //ввод значения
cin >> number;

error = Factor(number, &squared, &cubed);//вызов функции
причем видим что во втором и третьем аргументах передаются адреса
переменных,значит указатели ,находящиеся в параметрах функции
инициализированы адресами переменных.То что будет присвоено этим
указателям,фактически будет присвоено этим переменным,то есть
будут изменены значения переменных.В этом и есть задача функции,
-изменить значения переменных.Фактически функция вернула несколько
значений!.

3.Функция Listing9_9.cpp делает то же самое что и предыдущая описанная
функция,только в ее параметрах стоят не указатели ,а ссылки.
Таким образом в качестве аргументов можно передать просто сами переменные.
Результат работы функции будет присвоен ссылкам на эти переменные,
и в результате произойдет изменение переменных.Опять функция вернет
несколько значений!
----------------------------------------------------------------------------
Благодаря ссылкам и указателям функция может возвращать несколько
значений и даже это может быть много значений.!
----------------------------------------------------------------------------

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

Например ясно видно это в программе Listing9_10.cpp когда объект Cat
один раз передается в функцию как значение,другой раз передается
в функцию как ссылка.В первом случае создается два конструктора копий
а затем два деструктора,а во втором случае ни каких конструкторов
не вызывается о копий объектов не создается! Просто передается в стек
адрес(!) этого объекта и все. А с объектом происходят все те же действия,
что и в первом случае. Вот чем хороши ссылки! Ссылки повышают оптимизацию
программы. Ее эффективность.
Причем на примере этой программы(смотри текст) у меня получилось,
когда я заменил указатель на ссылку, что указатели более эффективны
чем ссылка. По крайней мере в данном конкретном случае, поскольку когда
а поставил в параметр ссылку вместо указателя, то копирующий конструктор
был вызван все же один раз и деструктор при вызове второй функции.

При передаче в функцию объекта в качестве ссылок может возникнуть одна
небезопасная проблема:
----------------------------------------------------------------------------
Передача объекта в функцию по значению безопасна для объекта. Передача по
ссылке способна изменить сам объект поэтому не безопасна.
---------------------------------------------------------------------------
Решить проблему можно передав в функцию указатель на постоянный объект.
В этом случае к объекту могут применяться только постоянные методы,
не имеющие прав на изменение объекта.
То есть мы обезопасиваем себя от нежелательного может быть случайного
или непредвиденного нами изменения объекта.

Вот пример программы Listing9_11.cpp в этотй программе объект CAt
в главной функции объявлен обычным,не постоянным.И обращаясь к нему
непрямую из главной функции мы можем менять его значение,как нам
заблагорассудится.Но в этой программе есть функция,в которой этот
объект объявлен постоянным.Вернее объявлена ссылка на постоянный объект.
И в результате если изнутри функции мы попытаемся изменить объект намеренно
или нечаянным образом,то у нас ничего не получится.Компилятор возвратит
сообщение об ошибке.Вот когда мы можем использовать компилятор как
нашего союзника и помощника в поиске ошибок!Это наглядный пример.
Если мы хотим проверить не изменяется ли наш объект во время испольнения
программы,то можем применить этот метод.Использовать функцию,которая
объявляет постоянные указатели на постоянный объект.Все!Теперь не получится
какому нибуть злоумышленнмку,или неверному аргументу,или неверному
результату изменить наш объект.

К программе Listing9_11.cpp:

Обратите внимание что объект создаваемый в функции main() не является
постоянным,и объект Frisky может вызвать функцию SetAge().Адрес этого
обычного объекта передается функции FunctionTwo() но поскольку в объявлении
функции FunctionTwo() заявлено что передаваемый указатель должен быть
постоянным указателем на постоянный объект(!) ,то с этим объектом функция
обращается так,как если бы он был постоянным!.

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

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

Когда использовать ссылки а когда указатели. стр 265

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

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

int *pInt=new int;
if(pInt!=NULL)
int &rInt=*pInt;

В этом примере объявлен указатель pInt на переменную типа int ,который
инициализируется областью памяти,возвращаемой оператором new.
Адрес этой области памяти (в указателе pInt) проверяется,и если он не равен
значению null,то этим результатом инициализируется ссылка rInt.Следовательно
ссылка rInt становится псевдонимом для гарантированно существующей переменной
типа int,возвращаемой оператором new.

--------------------------------------------------------------------------------------
Передавайте функциям параметры по ссылке везде где это возможно.
Возвращайте значения по ссылке везде где это возможно.
Используйте оператор const для защиты ссылок и указателей везде где это
возможно.
--------------------------------------------------------------------------------------
Не используйте указатели если вместо них можно использовать ссылки.
--------------------------------------------------------------------------------------

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

Сейчас пришло на ум,что у меня сделана программа которая содержит в себе
много модулей, но хорошо иметь программы,в каждой из которых содержится
только один модуль, но хорошо действующий. И можно с таким же успехом
запускать эти модули по очереди один за другим,запуская их exe формы.
И результат будет получен тот же, а отлаживать такую программу легче,
чем одну большую программу где много модулей. Так что я должен сохранить
все версии-и такую, и другую. И одну но сложную, которая делает в себе все
версии, и такую где много модулей!.

16 февраля
Как сделать так, чтобы слова считывались из текстового файла,
при этом они оказывались бы в динамически распределяемой
памяти компьютера?
Из динамической памяти слова должны вызываться в работу,
затем должны быть помещены обратно в текстовый файл.
Без использования библиотечного класса string.

Как сделать так, чтобы слова считывались из текстового файла,
затем помещались в символьный массив и затем из этого массива
помещались снова в текстовый файл. Без использования библиотечного
класса string.

Поскольку все эти действия должны быть проведены без использования
класса string ,то считывание из файла и запись в файл должны осуществляться
посимвольно.

16 февраля
Хороший программист -это такой программист, который пишет программы для
разных платформ, для компьютеров с разными возможностями, с разной оперативной
памятью. Например можно написать интересную программу для 486 компьютера,
которая составляет программу. Надо данные(слова) помещать в динамическую
память.Этот компьютер не поддерживает стандартные строки (такой уж
на нем стоит компилятор). Значит надо считывать из файла не пословно,
а посимвольно. И сначала создать базу слов хорошую, а потом посимвольно
считываеть из нее и помещать слова в динамическую память. Задача такая:
создать двумерный символьный массив в динамической памяти. И обращаться
к нему. Интересная задача!

21 февраля
Как из текстового файла прочитать(скопировать) данные(слова) в массив
элементов типа string расположенный в динамической памяти ?

string *Stroka1 = new string[500];//объявлен массив из 500 объектов класса
//string
string *pStr =Stroka1;//указателю на тип string присвоен адрес массива
// Stroka1 (адрес первого элемента)- Stroka1[0]

Можно так теперь инициализировать массив объектов типа string
n=0;
while(!eof) {

fin1>>word;
*pStr=word;
*pStr++;
n++;
}
cout< for(int i=0;i cout<<*pStr;
*pStr++;
}


Или так:

n=0;
while(!eof) {

fin1>>word;
Stroka1[n]=word;
n++;
}
cout< for(int i=0;i cout<}


Проверь работает ли этот код!

Вот как инициализируется строка в куче по Павловской:
Для строк не определена операция присваивания,поскольку строка является
не основным типом данных,а массивом.Присваивание выполняется с помощью
функций стандартной библиотеки или посимвольно вручную
(что менее предпочтительно так как чревато ошибками).Например чтобы
присвоить строке p строку a,можно воспользоваться функциями strcpy()
и strncpy() :

char a[100] = "Never trouble trouble);
char p = new char [m];
strcpy(p,a);
strncpy(p,a,strlen(a)+1);

Для использования этих функций к программе следует подключить заголовочный
файл <string.h>.

Функция strcpy(p,a) копирует все символы строки,указанной вторым параметром
(a),включая завершающий 0 в строку,указанную первым параметром(p).

Функция strncpy(p,a,n) выполняет то же самое но не более n символов,
то есть числа символов ,указанного третьим параметром.Если нуль-символ
в исходной строке встретится раньше,копирование прекращается ,а оставшиеся
до n символы строки p заполняются нуль-символвми.В противном случае
(если n меньше или равно длине строки a) завершающий нуль-символ в p
не добавляется.

Обе эти функции возвращают указатель на результирующую строкцу.Если
области памяти,занимаемые строкой-назначением и строкой источником
перекрываются,поведение программы не определено.
Функция strlen(a) возвращает фактическую длину строки a,не включая
нуль-символ.

Программист должен сам заботиться о том,чтобы в строке-приемнике
хватило места для строки-источника(в данном случае при выделении памяти
значение переменной m должно быть больше или равно 100),и о том,чтобы
строка всегда имела завершающий нуль-символ.
--------------------------------------------------------------------------
Выход за длину строки и отсутствие нуль-символа являются распространенными
причинами ошибок в программах обработки строк.
--------------------------------------------------------------------------

Еще по Павловской:
Следующая программа покажет вывод содержимого текстового файла на
экран.(Имя файла задается аргументом командной строки)

//MyCopy.cpp

#include <fstream.h>
#include <iostream.h>
using namespace std;

int main( int argc,char* argv[]) {

ifstream from1("text1");//открываем файл для считывания

if(!from1) {

cout<<"Vhodnoi fail ne naiden:" ;
char enterchar;
cout< cin>>enterchar;
return (1);
}
char buf[1024];

while (!from1.eof()) //пока не достигнут конец файла {

from1.getline(buf,sizeof(buf));
cout<
}


char enterchar;
cout< cin>>enterchar;

return 0;

}


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
А из buf в массив в куче (смотри предыдущий пример)

22 февраля 23 часа

Сейчас посмотрел структуры с диска MicrosoftVisual 6.0
У меня в прогамме кроссвордов можно применить структуры
в том месте,где программа находит все три слова для кроссворда
и можно поместить их как поля структур.Три поля

#include <iostream.h>
#include <string.h>
// Объявление структуры.
struct MYSTRUCTURE {

char Slovo05_01[6];
char Slovo05_02[6];
char Slovo05_03[6];
int kolSlov5;
};
void main( void ) {
MYSTRUCTURE MyStructure;

strcpy(MyStructure.Slovo05_01, curword );
MyStructure.kolSlov5 = 13;

cout << "Slovo05_01 ";
cout << MyStructure.Slovo05_01;
cout << " Slovo05_02 ";
cout << MyStructure.kolSlov5;
cout << " ." << endl;

}

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

23 февраля 11час

Следуя инструкциям из пособия создал интересное Visual приложение
в среде Microsoft Visual Studio 6.0.Это пока для меня такая редкость:
действующее Win -приложение!
Всю работу делал по пособию,расположенному в
d:\Docs C++\!Docs\Уроки и примеры по С++\Lesson1

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

Приобрел книгу Керниган и Пайк "Практика программирования"
"The Practice of prigramming" http:\tpop.awl.com

25 февраля

Попробуем переделать программу,взятую у Павловской (стр 186) для подсчета
слов в файле.Если программа сама сосчитает количество слов из файла это полезно
в моих программах кроссвордов

// Main.cpp
#include <fstream>
#include <string>
#include "CyrIOS.h" // for Visual C++ 6.0
using namespace std;

bool kolSlov1a(const string& cw,int &lenWord) {

char punct[] = {
'.',',','?','!'
};

if (length(cw) == lenWord) return true;
for (int i=0; i < sizeof(punct); ++i)
if (length(cw) + punct[i]==(lenWord+1)) return true;
return false;

}


int main() {

string curword;
cout << " Введите количество букв в слове: ";
cin >>kolBukv ;


ifstream fin("infile.txt"); if (!fin) {
cout << "Ошибка открытия файла." << endl; return 1;
}

int count = 0; while (!fin.eof()) {

fin >> curword;
if (equal(curword,kolBukv)) count++;
}
cout << "Количество слов в файле: " << count << endl;
return 0;
}


Попробуй сегодня применить макрос с кириллицей.

26 февраля

Попробуй применить в программе когда сравнивается длина слова, сравнить ее,
вернее поставить условие: если длина слова больше 1 то инкременировать счетчик.
Так ты сосчитаешь количество слов в файле. Возьми программу LovitZZbukv

Я применяю этот прием в программах.Открываю текстовый файл,считаю количество слов,
закрываю файл.

28 февраля

Пришла идея что можно составлять и другие формы кроссвордов
Попробуй на основе этого составить другие формы
Попробуй составить программу на кроссворд Romb100


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz