Базовые элементы языка С. Алфавит и словарь языка 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Базовые элементы языка С. Алфавит и словарь языка



Основные типы данных. Классификация их типов. Модификация базовых типов.

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

над переменной данного типа. Переменные можно инициализировать ы месте их описания.

Пример:

int heigh=71;

float k=26034.12;

Переменная любого типа может быть объявлена как немодифицируемая. Это достигается добавлением

ключевого слова const к спецификатору-типа. Объекты с типом const представляют собой данные,

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

Отметим, что если после слова const отсутствует спецификатор-типа, то подразумевается

спецификатор типа int. Если ключевое слово const стоит перед объявлением составных типов (массив,

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

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

Примеры:

const double A=2.128E-2;

const B=286; // подразумевается const int B=286

Целый тип данных

Для определения данных целого типа используются различные ключевые слова, которые определяют

диапазон значений и размер области памяти, выделяемой под переменные (таблица 5).

Таблица 5

Тип Размер памяти в байтах Диапазон значений
char 1 от -128 до 127
int Для IBM XT,AT,SX,DX 2  
short 2 от -32768 до 32767
long 4 от -2 147 483 648 до 2 147 483 647
unsigned shar 1 oт 0 до 255
unsigned int Для IBM XT,AT,SX,DX 2  
unsigned short 2 от 0 до 65535
unsigned long 4 от 0 до 4 294 967 295

Ключевые слова signed и unsigned необязательны. Они указывают, как интерпретируется нулевой бит

объявляемой переменной, т.е., если указано ключевое слово unsigned, то нулевой бит

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

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

если спецификатор типа состоит из ключевого типа signed или unsigned и далее следует

идентификатор переменной, то она будет рассматриваться как переменная типа int. Например:

unsigned int n;

unsigned int b;

int c;   //подразумевается signed int c

unsigned d; //подразумевается unsigned int d

signed f; //подразумевается signed int f

Типы данных с плавающей точкой

Для переменных, представляющих число с плавающей точкой, используются следующие модификаторы-

типа:

 Таблица 6

Тип Размер памяти в байтах Диапазон значений
float 4 от 3,4*10 -38 до 3,4*10 + 38
double 8 от 1,7 *10 -3 0 8 до 3,4*10 + 3 0 8
long double 10 от 3,4*10 - 4932 до 1,1 *10 +4932

Пример:

float f, a, b;

double x,y;

Символы

Символьный тип в языке С относится к целым типам данных. Отметим, что модификатор-типа char

используется для представления символа (из массива представление символов) или для объявления

строковых литералов.

Таблица 7

Тип Размер памяти в байтах Диапазон значений
char 1 от -128 до 127
signed char 1 от -128 до 127
unsigned char 1 от 0 до 255

Отметим также, что восьмеричные и шестнадцатеричные константы также могут иметь модификатор

unsigned. Это достигается указанием префикса u или U после константы, константа без этого

префикса считается знаковой.

Например:

0xA8C (int signed);

01786l (long signed);

0xF7u (int unsigned);

Тип void

Используется для определения функций, которые не возвращают значения для указания пустого списка

аргумента функций, как базовый тип для указателей и в операуии приведения типов.

Преобразование типов

Приведение типов – изменение (преобразование) типа объекта. Для выполнения преобразования

необходимо перед объектом записать в скобках нужный тип:

(имя-типа) операнд;

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

Пример:

int i;

double x;

x=(double)i+2.0;

В этом примере целая переменная i с помощью операции приведения типов приводится к плавающему

типу, а затем уже участвует в вычислении выражений.


 

Константы.

Константы – фиксированные величины, которые не могут быть изменены в программе. В языке С разделяют четыре типа констант: целые константы, константы с плавающей запятой, символьные константы и строковые литералы.

Целая константа – это десятичное, восьмеричное или шестнадцатеричное число, которое представляет целую величину в одной из следующих форм: десятичной, восьмеричной или шестнадцатеричной.

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

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

Шестнадцатеричная константа начинается с обязательной последовательности 0х или 0Х и содержит одну или несколько шестнадцатеричных цифр (цифры представляющие собой набор цифр шестнадцатеричной

системы счисления: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F).

Примеры целых констант:

    Десятичная Восьмеричная  Шестнадцатеричная

    константа  константа     константа

        16        020           0x10

       127        0117          0x2B

       240        0360          0XF0

Если требуется сформировать отрицательную целую константу, то используют знак "-" перед записью константы (который будет называться унарным минусом). Например: -0x2A, -088, -16.

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

- десятичные константы рассматриваются как величины со знаком, и им присваивается тип int (целая) или long (длинная целая) в соответствии со значением константы. Если константа меньше 32768, то ей присваивается тип int в противном случае long.

- восьмеричным и шестнадцатеричным константам присваивается тип int, unsigned int (беззнаковая целая), long или unsigned long в зависимости от значения константы согласно табл 8.

Таблица 8

Диапазон шестнадцатеричных констант Диапазон восьмеричных констант Тип
0x0 - 0x7FFF 0 - 077777 int
0X8000 - 0XFFFF 0100000 - 0177777 unsigned int
0X10000 - 0X7FFFFFFF 0200000 - 017777777777 long
0X80000000 - 0XFFFFFFFF 020000000000 - 037777777777 unsigned long

Для того чтобы любую целую константу определить типом long, достаточно в конце константы поставить

букву "l" или "L". Пример:

5l, 6l, 128L, 0105L, OX2A11L.

Константа с плавающей точкой - десятичное число, представленное в виде действительной величины с десятичной точкой или экспонентой. Формат имеет вид:

[ цифры ].[ цифры ] [ Е|e [+|-] цифры ]

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

Примеры: 115.75, 1.5Е-2, -0.025,.075, -0.85Е2

Символьная константа - представляется символом заключенном в апострофы. Управляющая последовательность рассматривается как одиночный символ, допустимо ее использовать в символьных константах. Значением символьной константы является числовой код символа. Примеры:

’ ’- пробел,

’Q ’- буква Q,

’\n’ - символ новой строки,

’\\’ - обратная дробная черта,

’\v’ - вертикальная табуляция.

Символьные константы имеют тип int и при преобразовании типов дополняются знаком.

Строковая константа (литерал) - последовательность символов (включая строковые и прописные буквы русского и латинского а также цифры) заключенные в кавычки ("). Например: "Школа N 35", "город Тамбов", "YZPT КОД".

Отметим, что все управляющие символы, кавычка ("), обратная дробная черта (\) и символ новой строки в строковом литерале и в символьной константе представляются соответствующими управляющими последовательностями. Каждая управляющая последовательность представляется как один символ.

Например, при печати литерала "Школа \n N 35" его часть "Школа" будет напечатана на одной строке, а вторая часть "N 35" на следующей строке.

Символы строкового литерала сохраняются в области оперативной памяти. В конец каждого строкового литерала компилятором добавляется нулевой символ, представляемый управляющей последовательностью \0.

Строковый литерал имеет тип char[]. Это означает, что строка рассматривается как массив символов.

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

тому, что следующая строка является продолжением предыдущей. Например:

"строка неопределенной \n длины" полностью идентична литералу "строка неопределенной длинны"

 

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


 

Переменные.

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

 

Функция main()

Обычная С-программа представляет собой определение функции main, которая для выполнения необходимых действий вызывает другие функции. Общая структура функции main такова:

                                    main()

                                                        {

                                                        /*Код, реализующий функцию main */

                                                        }

                                                            

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

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

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

Поразрядные операции

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

Таблица 9

 

 

Знак операции Операция Группа операций
& Поразрядное И

Поразрядные операции

| Поразрядное ИЛИ
^ Поразрядное исключающее ИЛИ
<< Сдвиг влево
>> Сдвиг вправо
~ НЕ

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

Операция поразрядного логического И (&) сравнивает каждый бит первого операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае в 0.

Операция поразрядного логического ИЛИ (|) сравнивает каждый бит первого операнда с

соответствующим битом второго операнда. Если любой (или оба) из сравниваемых битов равен 1, то соответствующий бит результата устанавливается в 1, в противном случае результирующий бит равен 0.

Операция поразрядного исключающего ИЛИ (^) сравнивает каждый бит первого операнда с соответствующими битами второго операнда. Если один из сравниваемых битов равен 0, а второй бит равен 1, то соответствующий бит результата устанавливается в 1, в противном случае, т.е. когда оба бита равны 1 или 0, бит результата устанавливается в 0.

Пример.

int i=0x45FF, /* i= 0100 0101 1111 1111 */

     j=0x00FF; /* j= 0000 0000 1111 1111 */

char r;

  r = i^j; /* r=0x4500 = 0100 0101 0000 0000 */

  r = i|j; /* r=0x45FF = 0100 0101 0000 0000 */

  r = i&j; /* r=0x00FF = 0000 0000 1111 1111 */

                 

Поразрядные операторы сдвига сдвигают все биты переменной вправо или влево. Формат:

               Переменная >> количество разрядов

               Переменная << количество разрядов

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

Поразрядная операция отрицания НЕ (~) инвертирует состояние каждого бита операнда, т.е. 0 преобразуется в 1, а 1 – в 0.


 

7. Операции языка С. Операция присваивания и отношения. Операция определения размера. Оператор последовательного вычисления.

 Комбинация знаков операций и операндов, результатом которой является определенное значение, называется выражением. Знаки операций определяют действия, которые должны быть выполнены над операндами. Каждый операнд в выражении может быть выражением. Значение выражения зависит от расположения знаков операций и круглых скобок в выражении, а также от приоритета выполнения операций.При вычислении выражений тип каждого операнда может быть преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при выполнении операций приведения типов. Операнд - это константа, литерал, идентификатор, вызов функции, индексное выражение, выражение выбора элемента или более сложное выражение, сформированное комбинацией операндов, знаков операций и круглых скобок. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип. Оператор – это часть программы, которая может быть выполнена отдельно, т.е. оператор определяет некоторое действие.Язык С содержит большое количество встроенных операций. Существует 5 основных класса операций:– арифметические;– логические;– поразрядные;– сравнения (присваивания);– присваивания.

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

Пример:

  int t;

                char f;

  long z;

  t=f+z;

Значение переменной f преобразуется к типу long, вычисляется f+z,результат преобразуется к типу int и затем присваивается переменной t.

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

Таблица 10

Знак операции Операция Группа операций
= Присваивание

Операции присваивания

*= Умножение с присваиванием
/= Деление с присваиванием
%= Остаток от деления с присваиванием
–= Вычитание с присваиванием
+= Сложение с присваиванием
<<= Сдвиг влево с присваиванием
>>= Сдвиг вправо присваиванием
&= Поразрядное И с присваиванием
|= Поразрядное ИЛИ с присваиванием
^= Поразрядное исключающее ИЛИ с присваиванием

Каждая операция составного присваивания выполняет преобразования, которые осуществляются соответствующей бинарной операцией. Левым операндом операций (+=) (-=) может быть указатель, в то время как правый операнд должен быть целым числом.

Примеры:

double arr[4]={ 2.0, 3.3, 5.2, 7.5 };

double b=3.0;

b+=arr[2]; /* эквивалентно b=b+arr[2]       */

arr[3]/=b+1; /* эквивалентно arr[3]=arr[3]/(b+1) */

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

Отношение (сравнение) – операции, в которых 2 переменные сравниваются друг с другом.

Таблица 11

Знак операции Операция Группа операций
< Меньше

Операции отношения

<= Меньше или равно
> Больше
>= Больше или равно
== Равно
!= Не равно
Операция определения размера С помощью операции sizeof можно определить размер памяти, которая соответствует идентификатору или типу. Операция sizeof имеет следующий формат:                                     sizeof(выражение);                                    В качестве выражения может быть использован любой идентификатор, либо имя типа, заключенное в скобки. Отметим, что не может быть использовано имя типа void, а идентификатор не может относится к полю битов или быть именем функции. Например, если компилятор числа типа int отводит 4 байта, а для чисел типа double – 8, то программа напечатает 8 4:Пример: double f; printf("%d", sizeof f); printf("%d", sizeof(int)); Оператор последовательного вычисления Операция последовательного вычисления обозначается запятой (,) и используется для вычисления двух и более выражений там, где по синтаксису допустимо только одно выражение. Эта операция вычисляет два операнда слева направо. При выполнении операции последовательного вычисления, преобразование типов не производится. Операнды могут быть любых типов. Результат операции имеет значения и тип второго операнда. Отметим, что запятая может использоваться также как символ разделитель, поэтому необходимо по контексту различать, запятую, используемую в качестве разделителя или знака операции.

 

8. Операции языка С. Условная операция. Операция (), операция [].

Комбинация знаков операций и операндов, результатом которой является определенное значение, называется выражением. Знаки операций определяют действия, которые должны быть выполнены над операндами. Каждый операнд в выражении может быть выражением. Значение выражения зависит от расположения знаков операций и круглых скобок в выражении, а также от приоритета выполнения операций.При вычислении выражений тип каждого операнда может быть преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при выполнении операций приведения типов. Операнд - это константа, литерал, идентификатор, вызов функции, индексное выражение, выражение выбора элемента или более сложное выражение, сформированное комбинацией операндов, знаков операций и круглых скобок. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип. Оператор – это часть программы, которая может быть выполнена отдельно, т.е. оператор определяет некоторое действие.Язык С содержит большое количество встроенных операций. Существует 5 основных класса операций:– арифметические;– логические;– поразрядные;– сравнения (присваивания);– присваивания.

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

Условная операция

Тернарное выражение состоит из трех операндов, разделенных знаками тернарной операции (?) и (:),и имеет формат: выражение1? выражение 2: выражение 3 Сначала вычисляется выражение 1. Если оно истинно, то вычисляется выражение 2 и его значение присваивается всему выражению. Если выражение 1 ложно, то вычисляется выражение 3 и всему выражению присваивается его значение.
Операции() и []

() Операция преобразования (или приведения) типа.

Эта бинарная операция в контексте так называемого постфиксного выражения и в контексте выражения приведения обеспечивает изменение типа значения выражения, представляемого вторым операндом. Информация о типе, к которому преобразуется значение второго операнда, кодируется первым выражением, которое является спецификатором типа. Существуют две формы операции преобразования типа: каноническая, при которой в скобки заключается первый операнд (в выражениях приведения), и функциональная (в постфиксных выражениях), при которой в скобки заключается второй операнд. При функциональной форме операции преобразования типа спецификатор типа представляется одним идентификатором. Для приввведениия значения к типу unsigned long следует использовать лишь каноническую форму операции преобразования. Механизм преобразования типа рассматривается ниже

Операция индексации

[]             Операция индексации.

Играет роль бинарной операции при индексации элементов массива (определение массива приводится ниже). Левый операнд представляет собой выражение, значением которого является адрес первого элемента массива. Правый операнд является выражением, определяющим значение индекса, т.е. смещения относительно первого элемента массива.


 

Подавление ввода

Спецификация преобразования записывается в виде:

%[флаг][W]F

Флаг (*) – дополнительный признак гашения присваивания, при котором значения пропускаются.


 

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

Массивы – это группа элементов одинакового типа (double, float, int и т.п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве. Объявление массива имеет два формата:                спецификатор-типа описатель [константное - выражение];                спецификатор-типа описатель [ ]; Описатель – это идентификатор массива. Спецификатор-типа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void. Константное-выражение в квадратных скобках задает количество элементов массива. Константное-выражение при объявлении массива может быть опущено в следующих случаях: - при объявлении массив инициализируется, - массив объявлен как формальный параметр функции, - массив объявлен как ссылка на массив, явно определенный в другом файле. Одномерные массивы Одномерный массив будет записан как:               тип <имя массива>[размер];Тип – базовый тип элементов массива.Размер – количество элементов одномерного массива.Пример:               int x[] = { 1, 3, 5 };               double b[10];                                // вектор из 10 элементов, имеющий тип double

 

Связь массивов и указателей

В языке Си имя массива трактуется как указатель-константа на массив. Пусть в программе объявлен массив:

int X[10];

В таком случае Х является указателем на нулевой элемент массива в памяти компьютера. В связи с этим является истинным отношение

X==&X[0]

Следовательно, для доступа к элементам массива кроме индексированных имен можно использовать разадресованные указатели по принципу:

Имя[индекс] тождественно *(имя+индекс)

Например, для описанного выше массива Х взаимозаменяемы следующие обозначения элементов:

X[5], или *(Х+5), или *(5+Х).

В языке Си операция [ играет роль знака операции сложения адреса массива с индексом элемента.


 

25. Функции динамического распределения памяти.

Calloc

Функция Выделяет оперативную память.

Синтаксис #include <stdlib.h

void * calloc(size_t nitems, size_t size);

Файл, содержащий stdlib.h,alloc.

прототип

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

 calloc выделяет блок памяти размером nitems x size.

Блок обнуляется. Если вы хотите выделить блок, размер которого превышает 64К то нужно использовать функцию farcalloc.

Возвращаемое calloc возвращает указатель на выделенный блок.

значение calloc возвращает NULL, если недостаочно памяти для выделения нового блока, или nitems или size равны 0.

Переносимость Поддерживается в системах UNIX и определена в ANSI

C. Описана в Керниган и Риччи. Смотрите также faralloc, free, malloc, realloc.Пример:

#include<stdio.h>

#include<alloc.h>

#include<string.h>

int main(void)

{

 char *str = NULL;

 /* выделить память для строки */

 str = calloc(10,sizeof(char));

 if(str)

 {

 /* скопировать в строку "Hello" */

 strcopy(str,"Hello");

 /* вывести строку */

 printf("Строка: %s\n",str);

 /* освободить память */

 free(str);

 }

 else

 printf("Недостаточно памяти\n");

 }

return(0);

}

Malloc

Функция.Выделяет память.

Синтаксис #include<stdlib.h>

#include<alloc.h>

void *malloc(size_t size);

Файл, содержащий stdlib.h и alloc.h прототип

Описание

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

Динамическая область памяти доступна для динамического размещения блоков памяти переменной длины. Многие структуры данных, такие как "деревья" или "списки" – естественным образом используют динамическое распределение памяти. В малых моделях памяти, вся область памяти между концом сегмента данных и вершиной программного стека доступна для использования, за исключением 256-байтовой границы, находящейся непосредственно перед вершиной стека. Данная граница предназначена для наращивания стека прикладной программы (плюс небольшое количество, требуемое для DOS). В больших моделях памяти все пространство после программного стека до конца физической памяти доступно для динамической области.

Возвращаемое

 Функция malloc возвращает указатель на блок выде значени ленной памяти. Если для размещения блока недостаточно памяти, функция malloc возвращает NULL.

Содержимое блока остается неизменным. Если аргумент size равен 0, то функция возвращает NULL.

Переносимость Функция доступна в системах UNIX и поддерживается стандартом ANSI C.

Смотрите также allocmem, calloc, coreleft, farcalloc, farmalloc, free, realloc.

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

Никакого ранее скомпилированного массива фиксированного размера, из которого выделяются куски памяти, не будет. Функция malloc запрашивает память у операционной системы по мере надобности. Поскольку и другие действия программы могут вызывать запросы памяти, которые удовлетворяются независимо от этого распределителя памяти, пространство, которым заведует malloc, необязательно представляет собой связный кусок памяти. Поэтому свободная память хранится в виде списка блоков. Каждый блок содержит размер, указатель на следующий блок и само пространство. Блоки в списке хранятся в порядке возрастания адресов памяти, при этом последний блок (с самым большим адресом) указывает на первый.

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

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

 

Существует проблема, состоящая в том, что память, выдаваемая функцией malloc, должна быть соответствующим образом выровнена с учетом объектов, которые будут в ней храниться. Хотя машины и отличаются друг от друга, но для каждой из них существует тип, предъявляющий самые большие требования на выравнивание, и, если по некоему адресу допускается размещение объекта этого типа, то по нему можно разместить и объекты всех других типов. На некоторых машинах таким самым "требовательным" типом является double, на других это может быть int или long.

 

Свободный блок содержит указатель на следующий блок в списке, свой размер и собственно свободное пространство. Указатель и размер представляют собой управляющую информацию и образуют так называемый "заголовок". Чтобы упростить выравнивание, все блоки создаются кратными размеру заголовка, а заголовок соответствующим образом выравнивается. Этого можно достичь, сконструировав дддобъединение, которое будет содержать соответствующую заголовку структуру и самый требовательный в отношении выравнивания тип. Для конкретности выберем тип long.


 

Функции. Определения функций. Оператор return.

Функция – это совокупность объявлений и операторов, обычно предназначенная для решения определенной задачи. Каждая функция должна иметь имя, которое используется для ее объявления, определения и вызова. В любой программе на С должна быть функция с именем main (главная функция), именно с этой функции, в каком бы месте программы она не находилась, начинается выполнение программы.

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

С использованием функций в языке С связаны три понятия – определение функции (описание действий, выполняемых функцией), объявление функции (задание формы обращения к функции) и вызов функции.

Определения функций

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

В соответствии с синтаксисом языка С определение функции имеет следующую форму:

[спецификатор-класса-памяти] [спецификатор-типа] имя-функции

([список-формальных-параметров])

{ тело-функции }

  

Необязательный спецификатор-класса-памяти задает класс памяти функции, который может быть static (видимость в пределах модуля, в котором определена функция) или extern (глобальная видимость во всех модулях программы по умолчанию).

Спецификатор-типа функции задает тип возвращаемого значения и может задавать любой тип. Если спецификатор-типа не задан, то предполагается, что функция возвращает значение типа int. Список-формальных-параметров – это последовательность объявлений формальных параметров, разделенная запятыми. Формальные параметры – это переменные, используемые внутри тела функции и получающие значение при вызове функции путем копирования в них значений соответствующих фактических параметров. Список-формальных-параметров может заканчиваться запятой (,) или запятой с многоточием (,...), это означает, что число аргументов функции переменно. Однако предполагается, что функция имеет, по крайней мере, столько обязательных аргументов, сколько формальных параметров задано перед последней запятой в списке параметров. Такой функции может быть передано большее число аргументов, но над дополнительными аргументами не проводится контроль типов.

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

Пример программы, возвращающий сумму двух целых величин:

      #include < stdio.h >

      int sum(int a, int b);

      int main()

      {

                          int a = 2, b = 3, c, d;

                          c = sum(a,b);

                          scanf("%d", d);

                          printf("%d", sum(c,d));

                          return 0;

      }

      int sum(int a, int b);

      {

                          return(a+b);

      }

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

               return [выражение];



Поделиться:


Последнее изменение этой страницы: 2021-08-16; просмотров: 39; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.218.55.14 (0.175 с.)