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

Вопросы - Ответы Программирование

.pdf
Скачиваний:
25
Добавлен:
01.05.2015
Размер:
1.75 Mб
Скачать

1. Простые типы данных языка программирования. Примеры применения.

Типы данных бывают следующие:

Простые.

oПеречислимый тип. Может хранить только те значения, которые прямо указаны в его описании.

oЧисловые. Хранятся числа. Могут применяться обычные арифметические операции.

Целочисленные: со знаком, то есть могут принимать как положительные, так и отрицательные значения; и без знака, то есть могут принимать только неотрицательные значения.

Вещественные: с запятой (то есть хранятся знак и цифры целой и

дробной частей) и с плавающей запятой (то есть число приводится к виду m*be, где m — мантисса, b — основание показательной функции, e — показатель степени (порядок) (в англоязычной литературе экспонента), причѐм в нормальной форме 0<=m<b, а в

нормализованной форме 1<=m<b, e — целое число и хранятся знак и числа m и e).

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

поддержкой таких типов является UBASIC, часто применяемый среди криптографов.

o Символьный тип. Хранит один символ. Могут использоваться различные кодировки.

o Логический тип. Имеет два значения: истина и ложь, при троичной логике может иметь и третье значение — «не определено» (или «неизвестно»). Могут применяться логические операции. Используется в операторах ветвления и циклах. В некоторых языках является подтипом числового типа, при этом ложь=0, истина=1.

oМножество. В основном совпадает с обычным математическим понятием множества. Допустимы стандартные операции с множествами и проверка на принадлежность элемента множеству. В некоторых языках рассматривается как составной тип.

Составные (сложные).

oМассив. Является индексированным набором элементов одного типа. Одномерный массив вектор, двумерный массив матрица.

Строковый тип. Хранит строку символов. Аналогом сложения в строковой алгебре является конкатенация (прибавление одной строки

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

вязыках более высокой абстракции зачастую выделяется в качестве простого.

oЗапись (структура). Набор различных элементов (полей записи), хранимый как единое целое. Возможен доступ к отдельным полям записи. Например, struct в C или record в Pascal.

oФайловый тип. Хранит только однотипные значения, доступ к которым осуществляется только последовательно (файл с произвольным доступом,

включѐнный в некоторые системы программирования, фактически является неявным массивом).

o Класс.

Другие типы данных. Если описанные выше типы данных представляли какие-либо

объекты реального мира, то рассматриваемые здесь типы данных представляют объекты компьютерного мира, то есть являются исключительно компьютерными терминами.

oУказатель. Хранит адрес в памяти компьютера, указывающий на какуюлибо информацию, как правило — указатель на переменную.

o Ссылка.

Преимущества от использования типов данных

Надѐжность. Типы данных защищают от трѐх видов ошибок:

1.Некорректное присваивание. Пусть переменная объявлена как имеющая числовой тип. Тогда попытка присвоить ей символьное или какое-либо другое значение в случае статической типизации приведѐт к ошибке компиляции и не даст такой программе запуститься. В случае динамической типизации код программы перед выполнением потенциально опасного действия сравнит типы данных переменной и значения и также выдаст ошибку. Всѐ это позволяет избежать неправильной работы и «падения» программы.

2.Некорректная операция. Позволяет избежать попыток применения выражений вида «Hello world» + 1. Поскольку как уже говорилось все переменные в памяти хранятся как наборы битов, то при отсутствии типов подобная операция была выполнима (и могла дать результат вроде «ello worldǼ»). С использованием типов (см. далее «Контроль типов») такие ошибки отсекаются опять же на этапе компиляции.

3.Некорректная передача параметров. Если функция «синус» ожидает, что ей будет передан числовой аргумент, то передача ей в качестве параметра строки «Hello world» может иметь непредсказуемые последствия. При помощи контроля типов такие ошибки также отсекаются на этапе компиляции.

Стандартизация. Благодаря соглашениям о типах, поддерживаемых большинством систем программирования, сложилась ситуация, когда программисты могут быстро менять свои рабочие инструменты, а программы не требуют больших переделок при переносе исходных текстов в другую среду. К сожалению, стандартизации по универсальным типам данных ещѐ есть куда развиваться.

2.Структурные типы данных, виды, методы работы. Типы данных, определяемые программистом.

Массивы

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

Количество используемых индексов массива может быть различным. Массивы с одним индексом называют одномерными, с двумя — двумерными и т. д. Одномерный массив нестрого соответствует вектору в математике, двумерный — матрице. Чаще всего применяются массивы с одним или двумя индексами, реже — с тремя, ещѐ большее количество индексов встречается крайне редко.

Пример статического массива

на Паскале -

 

wordArray : array [Word]

of Integer;

{ Статический, размер = High(Word)

+ 1 }

 

 

 

multiArray : array [Byte,

1..5] of Char;

{ Статический массив, 2 измерения

}

 

 

 

rangeArray : array [5..20] of String;

{ Статический массив, размер = 16

}

 

 

 

Пример статического массива на С/С++ -

 

int Array[10];

//

Статический, размер 10, базовый тип данных -

целое число (int)

 

 

 

double Array[12][15];

//

Статический массив, 2 измерения, базовый тип

данных - число

 

 

 

 

//

с дробной частью (double)

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

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

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

Объявление типа «массив» в Паскале -

type

TArrayType = array [0..9] of Integer; (* Объявления типа "массив" *) var

arr1, arr2, arr3: TArrayType; (* Объявление трѐх переменных-массивов одного типа *)

Динамические массивы

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

Пример динамического массива на Delphi

byteArray :

Array

of

Byte;

 

// Одномерный массив

multiArray :

Array

of

Array

of string;

// Многомерный массив

Пример динамического массива на Си

float *array1; // Одномерный массив int **array2; // Многомерный массив

array1=(float*)malloc(10*sizeof(float)); // выделение 10 блоков по

sizeof(float)байт каждый

 

array2=(int**)malloc(16*sizeof(int *));

// выделение 16*8 блоков по

sizeof(int) байт каждый

 

for(i=0;i<16;i++)

array2[i]=(int*)malloc(8*sizeof(int));

Пример динамического массива на С++

float *array1; // Одномерный массив int **array2; // Многомерный массив

array1=new float[10]; // выделение 10 блоков размером типа float array2=new int*[16]; // выделение 16*8 блоков размером типа int for(int i=0;i<16;i++)

array2[i]=new int[8];

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

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

Приведем пример описания переменной, имеющей структуру записи:

Var

Address : Record

HouseNumber : Integer;

StreetName : String[20];

CityName : String[20];

PeopleName : String;

End;

Отметим, что поля StreetName и CityName имеют одинаковый тип: String[20]. Поскольку в описании эти поля могут располагаться в любом порядке, то можно сократить описание записи с полями одинакового типа. Сокращенное описание записи Address выглядит следующим образом:

Var

Address : Record

HouseNumber : Integer;

StreetName, CityName : String[20];

PeopleName : String;

End;

Каждый компонент записи называется полем. В переменной записи Address поле с именем HouseNumber является переменной типа Integer, поле StreetName - двадцатисимвольной строкой и т.д.

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

Оператор, который присваивает полю HouseNumber значение 45, выглядит так:

Address.HouseNumber := 45;

Таким же образом присваиваются значения другим полям записи Address :

Address.StreetName := 'Профсоюзная';

Address.CityName := 'Сургут';

Address.PeopleName := 'Петрова Алла Ивановна';

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

Предположим, имеется следующее описание:

Type

Date = Record

Day : 1..31;

Month : (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec); Year : Integer;

End;

Var

HisBirth, MyBirth : Date;

После приведенного описания переменные HisBirth и MyBirth имеют тип записи Date. Помимо действий над отдельными полями записей HisBirth и MyBirth можно выполнять операции над всей записью. Следующий оператор присваивания устанавливает равенство значений записей HisBirth и MyBirth :

HisBirth := MyBirth;

Это присваивание эквивалентно следующей последовательности операторов:

HisBirth.Day := MyBirth.Day;

HisBirth.Month := MyBirth.Month;

HisBirth.Year := MyBirth.Year;

Для переменных одного типа можно проверить выполнение отношения равенства или неравенства ("=", "<>"). После выполнения приведенных выше присваиваний следующее булево выражение будет иметь значение True:

3.Управляющие конструкции языка программирования (условные операторы, операторы цикла и т.п.)

Операторы управления выполнением программы

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

while a <> b do { цикл с предусловием } writeln('Ожидание');

if a

> b then {

условный оператор }

writeln('Условие

выполнилось')

else

{

else-секция - может отсутствовать}

writeln('Условие

не выполнилось');

for i := 1 to 10 do { итерационный цикл } writeln('Итерация №', i:1);

repeat { цикл с постусловием } a := a + 1

until a = 10;

case i of { условный оператор множественного выбора }

0:write('ноль');

1:write('один');

2:write('два')

else write('неизвестное число') { else-секция - может отсутствовать} end;

В операторах while, for, if, case в качестве выполняемого оператора может использоваться блок. Такая конструкция, представляющая собой обычный оператор или блок, называется сложным оператором.

4.Понятие указателя, объявление указателя. Операции над указателями. Динамические структуры данных.

Указатель (пойнтер, англ. pointer) — переменная, диапазон значений которой состоит из адресов ячеек памяти и специального значения — нулевого адреса. Значение нулевого

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

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

Переменные, размещаемые в куче, называются динамическими. Часто они не содержат связанных с ними идентификаторов, и

ссылаться на них можно только с помощью указателей и ссылок.

Операции над указателями

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

В случае, если указатель хранит адрес какого-либо объекта, то говорят, что указатель

ссылается или указывает на этот объект p.

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

Указатель, как и любая другая переменная программы, должен быть объявлен в разделе объявления переменных. В общем виде объявление указателя выглядит следующим образом:

Имя: ^ Тип;

где:

имя — имя переменной-указателя;

Тип — тип переменной, на которую указывает переменная-указатель;

значок ^ показывает, что объявляемая переменная является указателем.

Приведем примеры объявления указателей:

p1: ^integer; р2: ^real;

В приведенном примере переменная p1 — это указатель на переменную типа integer, a p2

— указатель на переменную типа real.

Тип переменной, на которую ссылается указатель, называют типом указателя. Например, если в программе объявлен указатель р: ^integer, то говорят: ^р — указатель целого типа" или "р — это указатель на целое".

В начале работы программы переменная-указатель "ни на что не указывает". В этом случае говорят, что значение указателя равно NIL. Зарезервированное слово NIL соответствует значению указателя, который ни на что не указывает.

Идентификатор NIL можно использовать в инструкциях присваивания и в условиях. Например, если переменные pi и р2 объявлены как указатели, то инструкция

p1 := NIL;

устанавливает значение переменной, а инструкция

if р2 = NIL then ShowMessage('Указатель р2 не инициализирован!');

проверяет, инициализирован ли указатель р2.

Указателю можно присвоить значение — адрес переменной соответствующего типа (в тексте программы адрес переменной — это имя переменной, перед которым стоит оператор @). Ниже приведена инструкция, после выполнения которой переменная р будет содержать адрес переменной п.

р := @n;

Помимо адреса переменной, указателю можно присвоить значение другого указателя при условии, что они являются указателями на переменную одного типа. Например, если переменные pi и р2 являются указателями типа integer, то в результате выполнения инструкции

p2 := p1;

переменные pi и р2 указывают на одну и ту же переменную.

Указатель можно использовать для доступа к переменной, адрес которой содержит указатель. Например, если р указывает на переменную 1, то в результате выполнения инструкции

р^ : = 5;

значение переменной i будет равно пяти. В приведенном примере значок ^ показывает, что значение пять присваивается переменной, на которую указывает переменная-указатель.

Динамические переменные

Динамической переменной называется переменная, память для которой выделяется во время работы программы.

Выделение памяти для динамической переменной осуществляется вызовом процедуры new. У процедуры new один параметр — указатель на переменную того типа, память для которой надо выделить. Например, если р является указателем на тип real, то в результате выполнения процедуры new(p); будет выделена память для переменной типа real (создана переменная типа real), и переменная-указатель р будет содержать адрес памяти, выделенной для этой переменной.

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

Процедура, использующая динамические переменные, перед завершением своей работы должна освободить занимаемую этими переменными память или, как говорят программисты, уничтожить динамические переменные". Для освобождения памяти, занимаемой динамической переменной, используется процедура Dispose, которая имеет один параметр — указатель на динамическую переменную.

Например, если р — указатель на динамическую переменную, память для которой выделена инструкцией new(p), то инструкция dispose (р) освобождает занимаемую динамической переменной память.

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

Листинг 8.3. Создание, использование и уничтожение динамических переменных

procedure TForm1.Button1Click(Sender: TObject); var p1,p2,p3: Integer; // указатели на переменные типа integer

begin

//создадим динамические переменные типа integer

//(выделим память для динамических переменных)

New(p1);

New(p2);

New(p3);

р1^ := 5;

р2^ := 3;

р3^ := р1^ + р2^;