Главная страница
Навигация по странице:

  • 3.4 Логический тип

  • 3.5. Символьный и строковый ( string ) типы

  • 3.6 Указатели

  • Пример 1.

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

  • Проблемы, возникающие при использовании указателей

  • Учебное пособие по дисциплине Разработка языков программирования высокого уровня


    Скачать 1.74 Mb.
    НазваниеУчебное пособие по дисциплине Разработка языков программирования высокого уровня
    Дата05.03.2023
    Размер1.74 Mb.
    Формат файлаdocx
    Имя файлаLektsii_YaPVU_Lukinova_2_semestr.docx
    ТипУчебное пособие
    #970477
    страница11 из 20
    1   ...   7   8   9   10   11   12   13   14   ...   20

    3.3. Числа с фиксированной запятой.


    Большинство компьютеров, разработанных для коммерческих приложений, содержат аппаратное обеспечение, поддерживающее типы десятичных чисел fixed. Числа типа fixed представляются в форме с фиксированной точкой, которая стоит в установленном месте и определяет целую часть от дробной части (простые дроби). Такие типы данных в коммерческих приложениях и ЯП и КОБОЛ являются основными. К достоинствам следует отнести возможность осуществлять точную арифметику в установленном диапазоне.

    3.4 Логический тип


    Впервые логический тип данных появился в языках АЛГОЛ-60 и с 1960г. Данные этого типа были включены во все универсальные ЯПВУ, кроме C ( в языке C истинное значение кодируется любым числом, большим от нуля, ложное – 0).
    Три стандартные логические операции применяются к операндам логического типа, давая в результате логическое значение: логическое дополнение (not), логическое «И» (and), логическое «ИЛИ» (or). Основное назначение логического типа состоит в реализации условий для условного оператора и оператора цикла.
    Диапазон данного типа состоит из двух значений: true и false. Значения представляются в машине минимальной ячейкой памяти (байт). Основные операции: not – логическое дополнение, and – логическое «и», or – логическое «или». Используется в операторах условного перехода, операторах цикла, для организации в алгоритмах переключателей, флагов и т.п.

    3.5. Символьный и строковый (string) типы


    Символьный тип данных представляет собой один символ, внутреннее представление которого в компьютере реализуется одной из следующих систем кодирования:
    ASCII – код в диапазоне 0 – 127 занимает 7 бит,
    – код в диапазоне 0 – 255 занимает 8 бит (байт)
    Unicode – код символа реализуется двумя байтами, занимает 16 бит.
    Символьные строки – это последовательности символов. При этом реализация в разных зыках программирования различна. Так, в языках C, C++ строки вводятся как символьные массивы типа char. Набор операций над такими массивами вызывается из стандартной библиотеки string.h. Строки символов здесь завершаются специальным символом, который называется «нуль-байт» - /0. Этот нуль-байт заносится автоматически при создании строки символов. В языках Pascal (с версии 5.0), Delphi, Ada, Fortran77, 90, Бэйсик, Java тип string является встроенным.
    Существует несколько проектных решений, касающихся длины строковых величин:
    1. Статическая реализация.
    Длина может быть статической и задаваться в объявлении: var str :
    string[10];
    Строки со статической длиной всегда полные: если строковой переменной присвоили строку меньшей длины, то свободные места автоматически дополняются нулями.



    Дескриптор такой строки имеет следующий вид:



    2. Строки переменной длины с ограничением. Текущая длина при этом ограничивается специальным символом, в C и C++ ставится нулевой байт.


    Дескриптор такой строки имеет следующий вид:



    3. Строки с переменной неограниченной длинной (SNOBOL4, Perl). Такая реализация требует больших временных затрат на размещение и удаление из оперативной памяти, но обеспечивает высокую гибкость.
    Операции над строками делятся на два класса:
    1. Встроенные: конкатенация (слияние строк), операции отношений и присваивания;
    2. Реализованные в виде функций: выделение подстроки, определение длины строки, сравнение строк, определение индекса элемента и др.

    3.6 Указатели


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

    Указатели используются в следующих случаях:
    1. Организация косвенной адресации для нединамических объектов. В частности, в языке C указатели широко используются при обращении к массивам, строкам, структурам. И это является одним из факторов ненадежности данного языка.
    2.Для организации обращения к ячейкам динамической памяти (кучи). Переменные, размещенные в куче, не имеют имен, обращаться к ним можно только с помощью указателей и ссылок.

    Как любая переменная, указатель должен иметь тип. Тип указателя определяет объем динамической памяти в байтах, выделяемой из кучи. Однако в языках существует два вида указателей:

    1.Типизированные, когда тип указателя определяется типом переменной, на которую он будет указывать. В нижеприведенном примере все объявленные указатели являются типизированными.

    Пример 1.




    2. Нетипизированные, когда объем выделяемой памяти определяется с помощью специальных функций. Нетипизированные указатели существуют в языке Pascal, для их объявления задействован специальный тип pointer:

    Var
    p : pointer;

    Операции над указателями:
    1. Инициализация указателя – присваивание указателю адреса. Может происходить в следующих случаях:

    – присваивание динамического адреса. По запросу пользовательской программы операционная система отводит блок ячеек динамической памяти и помещает адрес начальной ячейки в указатель, тем самым устанавливается связь между указателем и адресом. Для этого в языках используются специальные функции, например,
    Pascal – new(i); C – malloc(i);

    – обеспечение косвенной адресации для нединамического объекта, например, массива:
    int*(A+индекс)=*А+индекс*длина;

    – посредством операции взятия адреса (операция «амперсант»):
    i=ⅈ

    2. Разыменование указателя – взятие (присваивание) значения из/в ячейки, на которую указывает указатель. Если, например, указатель i указывает на ячейку, которая содержит число 206, то оператор
    ii=*i;
    поместит это число в переменную ii, а оператор
    *i = 220;
    присвоит значение 220 в динамическую переменную, адрес которой содержится в указателе i.

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

    Dispose(i); (Pascal),
    Free(i); (C).
    Следует заметить, что, вообще говоря, эти функции не освобождают указатель, они только возвращают динамическую переменную в кучу. Для надежной работы программы необходимо производить и освобождение указателя (см. следующий пункт 4), хотя в некоторых языках операции 3 и 4 совмещены.

    4. Освобождение указателя – помещение в него нулевого адреса (на примере языка Pascal).
    const c : pointer = NIL //нулевой адрес в Pascal

    dispose(i);
    i = c;
    Только после того, как в указатель занесли 0, его можно использовать для другого адреса.

    5. Присваивание.
    Операцию присваивания можно реализовывать только для однотипных указателей:

    var
    p1, p2 : ^int;
    p3 : ^real;
    pp : pointer;
    begin p1 = p2;
    p1 = p3; //ошибка,чтобы ее обойти, надо использовать
    // указатель pp:
    // pp = p3:
    // p1 = pp;
    end.


    5. Арифметические операции над указателями (осуществляются в адресном пространстве):

    – операция «+»:
    int *p1; //длина int равно 4-м байтам
    p1 = 2000;
    p1 = p1+3; //оператор поместить в p1 адрес 2012

    – операция «-»:
    int *p1, *p2, a;
    a = p2-p1; //смещение p2 относительно p1

    6. Операция отношений: > , < , = , <= , >=.

    7. Операция идентификация поля записи:
    p1 : ^record; //указатель на запись
    p1^ . fio;
    *p1.fio;

    Проблемы, возникающие при использовании указателей

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

    1.Висячий указатель – указатель, содержащий адрес динамической переменной, которая уже удалена из доступной памяти и возвращена в кучу.
    Они создаются в следующей ситуации:

    Шаг 1: Пусть p1 указывает на некоторую ячейку;
    Шаг 2: p2 = p1; //присваиваем p2 значение p1
    Шаг 3: возвращаем ячейку в кучу и освобождаем p1, но p2 при этом продолжает содержать адрес ячейки.

    Такая ситуация может привести к следующим последствиям:

    – в эту ячейку могут загрузиться новые данные или данные другой пользовательской программы, а, поскольку p2 имеет доступ к данной ячейке, то есть большая вероятность их испортить;

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

    2. Потерянные переменные – это ячейки, размещенные в динамической памяти и переставшие быть доступными для пользовательской программы. Такие переменные называются мусором. Они создаются в случае, если:

    Шаг 1: с целью указателя p1 устанавливается некоторая динамическая переменная,
    Шаг 2: целью того же p1 становится другая динамическая переменная.

    Тогда первая ячейка становится недоступной для программы, т.к. связь с ней теряется. Но она недоступна также и для операционной системы, т.к. тоже выделена программе. Эта проблема называется утечкой памяти и затрагивает ЯПВУ, в которых требуется явное удаление из памяти переменных. В некоторых языках организована автоматическая сборка такого мусора, который удаляет все эти ячейки, например, в языке Java.
    1   ...   7   8   9   10   11   12   13   14   ...   20


    написать администратору сайта