Элементы языка.
Под элементами понимают базовую конструкцию, содержащую алфавит, константы, идентификаторы, ключевые слова и комментарии.
Компилятор С-программ понимает текст программы как совокупность строк, каждая из которых завершается признаком конца строки. Компилятор считывает строки и и разбивает каждую из них на лексемы (единицы текста программы, имеющие самостоятельный смысл для компилятора и не содержащий в себе другие лексемы). Внутри идентификаторов, ключевых слов и знаков недопустимы пробельные символы.
I. Алфавит.
Состоит из латинских букв строчных и прописных (от A до Z)и цифр (от 0 до 9). Строчные и прописные буквы – различные символы.
Комментарии:
/*…*/
//…
\t – табуляция
\l –возврат каретки
\v –вертикальная таблица
\n –новая строка
Несут ту же смысловую информацию, что и пробелы. Компилятор игнорирует пробельные символы, если не является компонентами строковых констант.
Разделители(:?)
Являются частью оператора. Результат 2-го или 3-го операнда, в зависимости от значения «истина» или «ложь» 1-го операнда.
‘ – ограничитель символьной константы
“ – ограничитель строковой константы
! – логическое отрицание
Для хранения значений логических выражений используются целые значения (0-ложь, все остальные - истина).
(!) – логическое или (логическое сложение, дизъюнкция)
| - побитовое «или»
|| - логическое «или»
5|7=12
101|111=1111
8|5=13
1000|0101=1101
/ - целочисленное деление через конструкции комментариев
5/3=1
\ - часть конструкции, задающая специальный символ
~ - побитная инверсия (тильда)
~5=.65630
Замечание: отрицательных целых констант нет. Используется выражение из унарного минуса и положительного целого.
- символ используется наравне с буквами
_ - смысловой разделитель
( ) – для изменения приоритета операции в выражении
А( ) – указывает, что идентификатор имя функции
{} – начало и конец группового оператора. Тело функции – групповой оператор.
<> - операции сравнения (используются в директиве препроцессора include. В угловые скобки включается имя включаемого файла, если он размещается в директориях, указанных компилятору с помощью специальных функций. Имя файла тоже может быть в двойных кавычках. Поиск данного файла осуществляется в директориях переменной среды окружения ОС).
[] – используется для доступа к элементам массива по их индексам, используется при описании массива для определения количества по данной размерности
int A[4][3] – матрица 4х3
# - начало директивы препроцессора
% - деление по модулю (определение остатка по целочисленному делению)
48%45=3
используется в стандартных функциях потока ввода, вывода (scanf, printf), для обозначения спецификатора ввода, вывода
& - логическое «и» (конъюнкция, логическое умножение)
&& -логическое «и»
& - побитовое «и»
5&7=5
Унарная операция взятия адреса
&x – значение адреса в формате текущей адресации
int X[4][3] – идентификатор массива
& X[0][0]=X - первый элемент массива
^ - исключающее «или»
- - бинарная операция вычитания (унарная операция смены знака), унарный минус
= - оператор присваивания (часть операции отношения)
+ - сложение
- бинарная операция умножения (операция определения значения по адресу)
int X[4][3]
X= X[0][0]
Замечание:
В соответствии с правилом образования идентификатора типа матрица 4х3 определяется как массив из 4 элементов, каждый из которых является массивом из 3-х элементов, каждый из которых предназначен для хранения целого значения. Запись *х означает значение адреса начала нулевой строки.
>> - операция побитового сдвига вправо
<< - операция побитового сдвига влево
1>>1=0
1<<1=2
\b – шаг назад
\t – табуляция, символ управления позиции курсора, переносящий курсор на следующую позицию табуляции. Используется для распечатки таблицы, позволяет вне зависимости от длины слова в ячейке таблицы разграничитель колонок выводить с одного места
\r – возврат каретки (перевод на начало строки)
\f – новая страница
\a – звуковой сигнал
\’ – обозначение одиночной кавычки
\” – обозначение кавычек
\\ - обратный слеш
‘ - апостроф
“ – ограничение строки. Также в программе имеется возможность обозначать нетерминальные символы, для этого используется их код из таблицы кодирования ASCII, KOH-7, KOH-8.
Код символа –порядковый номер в таблице кодирования.
Операции.
Комбинации символов, точно описывающие специфицирующие действия по преобразованию значения. В С компилятор расценивает операции как отдельные лексемы, имеет отношение к парсингу (синтаксический анализ).
10<<2=40
10>>2=2
Операции отношения.
На аппаратном уровне вычисляется разность операндов, разность не сохраняется, устанавливаются биты признака результата в слове состояния программы.
Z – признак 0
N – признак отрицательного результата
a>b a-b>0 N= 0 Z=0
a<b a-b<0 N= 1 Z=0
a= =b a-b=0 N= 0 Z=1
a>=b a-b>=0 N= 0 Z= или N=0 Z=1
a<=b a-b<=0 N= 1 Z=0
a!=b a-b !=0 N= Z=0
, - операция последовательного выполнения
в языке С каждое значение имеет выражение равное результату вычисления выражения.
2+3 имеет значение 5
х=2 имеет значение 2
Вместо 1-го выражения можно использовать последовательность выпажений, разделенных запятыми. Результат – значение последнего выражения.
Х=2, н=3 будет иметь значение 3.
Отличие оператора присваивания С от Паскаля:
В Паскале эта операция чисто переноса значения, в С также сохраняется результат.
Операция последовательного выполнения обычно используется внутри оператора, если требуется вместо 1-го разместить сразу несколько выражений.
For (i=0,j=10…)
?: - условная тринарная операция.
<оператор 1>?< оператор 2>:< оператор 3>
Если в результате 1 – «истина», выполняется 2-ой операнд, «ложь» - 3-ий операнд
Результат – вычисленное значение 2-го или 3-го.
<x>0>?<|x|=x>:<|x|=-x>
если требуется заменить значение х , то третий операнд заменяем на х=-х
х=5&7=5
y=5&&7=1 (истина)
++ - инкремент – увеличение на 1
различают:
прединкремент (++ перед переменной) – результат изменяется на 1, переменная меняется на 1
постинкремент (после переменной ++) - результат значение переменной до увеличения, переменная меняется на 1
а=0
в=а++
с=++в
а=в=с=1
-- - декремент (--а – преддекремент; а-- - постдекремент)
к=10
l=--k—
n=--l—
k=8 l=7 n=8
x=15
y=-- --x++ ++
x=15 y=13
= - присваивание. Значение правого операнда присваивается левому операнду. Значение, хранящееся по адресу правого переносится в место хранения левого операнда. Машинный язык: команда переслать. Накладываются ограничения на вид операндов. Левый операнд должен являться 1-value выражением.
Значение может состоять в левой части оператора присваивания. L-value – выражение специфицирует место, в которое может быть записано выражение.
Например, вызов функции не является 1-value выражением. В правой части должны стоять r-value выражения, то есть выражение, имеющее конкретное значение, которое можно использовать.
Например, строка массива не является r-value выражением, поэтому значения массивов можно переносит только перед присваиванием значения каждого элемента массива.
В качестве левого операнда в С можно использовать адрес функции (вместо строки – адрес строки)
Char *s=”aбв” - хранит адрес строки из 4 символов abc\0.
В s хранится адрес строки (адрес буквы а).
Char с;
С=*s (в с запишем букву «а»)
C1=*(s+2) (в с1 запишем букву «в»)
*s=«х» (замена символа «а» на «х», строка «хбв»)
qsort – быстрая сортировка, в этой функции адрес сравнения 2-х элементов
Операции присваивания с изменением:
+=
-=
*=
/=
%=
>>=
<<=
*- доступ к значению, хранящегося по адресу
& - определить значение, хранящееся по адресу
объявим р как указатель на целое, х как целое
int *p;
int x;
x=1;p=&x;
printf (“%d”,*p);
sizeof – определение размера памяти в байтах, занимаемой операндом. В качестве операнда имя типа, имя переменой. Sizeof(int) во всех случаях, когда требуется использовать константы равные объему памяти, рекомендуется использовать операцию sizeof.
Пример: требуется сохранить информацию об аттестации студенческой группы. Количество студентов от 8 до 9 человек, количество предметов от 9.
Применяют динамическое распределение памяти. Объявляют указатель на значение типа int. Пользователь вводит количество студентов и предметов.в программе вызывается функция выделения памяти, которой необходимо указать точное количество байт, требуемых для хранения информации. Количество байт=число строк* количество столбцов* sizeof(int)
Альтернативным является выделение фиксированного количества памяти, в максимально необходимых размерах, что приводит к неэкономному использованию памяти.
Х= sizeof(int)=2 – 2 байта
Приоритет операций и порядок их выполнения.
Группирование операндов и последовательность их выполнения определяются приоритетом и ассоциативностью операций языка С. Ассоциативность влияет на выполнение операций одинакового приоритета.
A>B (А более первично, чем В)
C=D (D более первично, чем С)
Операции в порядке убывания приоритета:
Первичные:
Ø Ассоциативность слева направо
Ø Вызов функции f( )
Ø Индексация элементов массива x[i]
Ø Взятие элементов структуры
Ø Взятие элемента структуры на ссылке (p→b(*p).b)\унарные^
Унарные:
Ø Ассоциативность справа налево
Ø УНАРНЫЙ МИНУС –
Ø ИНВЕРСИЯ
Ø ВЗЯТИЕ АДРЕСА &
Ø Инкремент++
Ø Декремент –
Ø Ретипизация (приведение значения к определенному типу (type))
Ø Sizeof
Мультипликативные:
Ø Ассоциативность слева направо
Ø *, /, %
Аддитивные:
Ø Ассоциативность слева направо
Ø Сложение, вычитание
Сдвига:
Ø Ассоциативность слева направо
Ø Сдвиг вправо, влево (>>,<<)
2 1 5 4 3 6
-_-x+-_-y+a
Отношения:
Ø Ассоциативность слева направо
Ø <,>,>=,<=,!=,=
единственные операции:
1. поразрядное «и» &
2. исключающее «или»^
3. поразрядное «или» | 1-5 слева направо
4. логическое «и» &&
5. логическое «или» | |
6. условная тринарная операция справа налево
7. простое и составное присваивание справа налево
8. последовательное вычисление слева направо
Мультипликативные, аддитивные и поразрядные операции обладают свойством коммуникативности.
(а+в)+с=а+(в+с)
из этого следует, что компилятор может вычислять выражение в произвольном или оптимальном для компилятора кода порядке, вне зависимости от расположения операндов в выражении и в особом случае вне зависимости от скобок.
Если необходимо строго определить порядок выполнения выражения, то вводятся промежуточные переменные, которым присваивается значение части выражения.
Операции последовательного вычисления, логические, условные гарантируют определенный порядок вычисления операндов.
Пример, (а=3,а++,а=0), а=0.
Замечание.
Запятая в списке аргумента функции не является операндом операции последовательного вычисления, в связи с этим при вызове функции гарантируется только то, что к моменту входа все аргументы функции будут вычислены.
F(i=1,i++,i++) любые значения из множества 1,2,3, при этом 2 и 3 могут быть заменены любым значением из оперативной памяти, такого рода вызовы использовать нельзя.
Логические операции обеспечивают порядок вычислений, но при этом могут вычисляться только операнды, влияющие на конечный результат.a||b||c. При а!=0 выражение b||c рассматриваться не будет. Данный подход к вычислению логических выражений позволяет повысить эффективность вычислений за сет смещения операндов с наиболее вероятным результатом в начало выражения. Это позволяет включать в выражение проверку, останавливающую дальнейшее вычисление.
F(x)&&G(y)
F(x)+G(y) будут вызваны обе функции.
Замечание.
Все вышесказанное относится к языкам низкого уровня., поэтому использование вышеозначенных правил может быть допущено только в особых случаях, не рекомендуется формировать сложноступенчатые выражения при имеющихся резервах системы.
Побочные эффекты.
Выражаются в неявном изменении значений переменной в ходе вычисления выражения.
Вызывать операциями присваивания.
Вызов функции, которая изменяет значение внешней переменной, через ссылку или присваивание.
Порядок вычисления выражения зависит от реализации компилятора и гарантируется только в вышеозначенных функциях. – примеры побочных эффектов.
Для С-программы определены контрольные точки, по достижении которых все предшествующие вычисления гарантировано воспроизведены.
Контрольные точки:
- операции последовательного вычисления;
- условные
- логическое «и»
- логическое «или»
- вызов функции
- конец полного выражения , то есть выражение, которое не является частью другого
также конец инициализированного выражения для переменной класса памяти «авто». И конец выражения управления операторов if, switch,while,do,for.
add(i+1;i=j+2) – использовать нельзя
единица может быт прибавлена к i до или после операции присваивания.
i-целая переменная, а – вектор из 10
i=0, a[i++]=I использовать нельзя либо 1, либо 0
Операции преобразования типов выполняются либо неявно (по умолчанию), либо явно с помощью операций преобразования типа явного.
(int )x (х привести к типу целого).
Всегда фактические параметры функции преобразуются к типу формальному, что требует от программиста контроля совпадения типов. В Pascal транслятор контролирует совпадения.
Тип float всегда преобразуется в double, подтип целого в int. Символы хранятся в 2 байтах.
Константы.
I. Целые: десятичные, 8-ные, 16-ные
Десятичные(0-9) без лидирующего 0
8-ные (0-7)
Первая цифра 0:16≠016
16-ные (0-9, A-F)
Строчные прописные буквы не различаются, пробельные символы не допускаются. Все целые константы положительные.
Если требуются отрицательные, то записывают выражение унарный минус положительная константа.
Целая константа- тип, занимающий минимальный размер памяти необходимый для хранения данной величины.
Максимальная целая константа =
Если константа превосходит это значение, то она хранится как длинное целое.
Если необходимо сохранить целую константу как длинное целое, то дописывается суффикс L к константе.
0 – занимает 2 байта
0L - 4 байта
II. С плавающей точкой
Десятичное положительное число, включающее целую, дробную части и экспоненту. Дробная часть определяется точкой, е – экспонента.
Десятичная точка или знак е могут быть опущены.
Если оба символа опущены, то константа целая. Константа с плавающей точкой: положительное значение, тип double.
III. Символьные константы.
Буквы, цифры, специальные символы, заключенные в апостроф. Значение символьной константы равно коду представленного символа.
Тип хранения – целый.
Младший байт – код символа, старший – знаковое расширение младшего байта.
IV. Строковая константа.
Последовательность символов, заключенная в кавычки. Символьная строка – одномерный массив символов, ограниченный в конце символом конца строки (‘\0’)
В строке допускается наличие символов, не имеющих экранной интерпретации. Для них \ не рассматривается.
Для кодирования \ используется \\
V. Идентификаторы.
Относят имена переменных, функций, метод (используемый в программе) идентификатором является последовательность букв или цифр, начинающаяся с буквы. Символ подчеркивания ( __ )относят к буквам.
Строчные и прописные символы различны.
В большинстве реализаций компиляторов С идентификаторы считаются идентичными, если 1-ые n- символов совпадают.
Ключевые слова: являются лексические единицы, имеющие вид постоянных идентификаторов. Эти слова зарезервированы и не могут использоваться в качестве идентификаторов объектов.
Авто (auto)
Класс памяти auto по умолчанию.
Класс памяти определяет время жизни и область действия объекта. В принятой фон-неймановской архитектуре для хранения данных может использоваться стек данных, сегмент данных и динамически распределяемая память, называемая кучей.
Стек – структура данных, доступ к которой осуществляется с дисциплиной обслуживания LIFO. Использование стека для хранения переменных позволяет выделять память только во время выполнения модуля и освобождать её при выходе из него.
Сегмент данных – зарезервированная область памяти, в которой объекты хранятся в течение всего времени существования сегмента, который выделяется в программе при её загрузке на выполнение.
Динамическая память – вся доступная ОС, свободная в момент выполнения программы, оперативная память. Размещение в ней объектов происходит в программе по запросу вызовом функции ОС.
Переменная описанная как класс памяти auto , имеет локальную область действия с места объявления до конца блока, в котором она объявлена (время существования определяется временем жизни блока, в котором она объявлена). При выходе из блока стековая память, отведенная под неё, освобождается.
Break - оператор прерывания выполнения циклической постоянной последовательности и выхода из группы альтернатив оператора выбора. Управление передается на оператор следующий за концом передаваемого оператора.
Сase – часть оператора выбора. Означает начало значения условной переменой, анализируемой в операторе выбора.
Char – символьный тип данных.
Continue – оператор передачи управления из тела цикла на оператор определения условия продолжения цикла.
Default – часть оператора выбора. Определяет действие, выполняемое при отсутствии среди альтернативного значения условной переменной оператора выбора. Аналог :else из оператора if
Else – часть оператора условия. Наало альтернативной ветви.
Enum – перечислимый тип данных. Представляет собой подмножество целого типа. Позволяет определить последовательность целых значений, которые присваиваются идентификатором (перечисление красного(0), желтого(1), черного(2)). Переменная х этого типа должна принимать должна принимать значения либо 0, либо 1, либо 2. При записи можно использовать идентификаторы.
Extern – класс памяти. Переменная данного класса должна иметь описание на внешнем уровне. Объявляя внутри файла переменную данного класса, вы сообщаете компилятору, что её определения надо искать в другом файле.
Float – тип данных с плавающей точкой с плавающей точкой одинарной точности.
For – оператор цикла (паскаль – оператор с известным количеством повторений, Си – универсальный оператор).
Goto – оператор безусловного перехода. Передает управление на оператор, помеченный меткой, указанной в качестве операнда. Не рекомендуется использовать. Любой безусловный переход можно заменить с помощью структурных процедурных скобок.
Int – целый тип данных.
Long – префикс к основному типу, означающий увеличение точности в 2 раза.
If – начало оператора условия.
Register – класс памяти. Переменная данного класса по возможности размещается в регистре общего назначения для ускорения доступа к ней. Если свободных регистров нет, то используется класс памяти auto.
Return – оператор выхода из функции. Передает управление на оператор, следующий за вызовом функции. Если тип возвращаемого значения операнда оператора return.
Short – префикс уменьшения точности.
Signed – префикс к целому типу, означающий целое со знаком (хранится в дополнительном коде).
Дополнительный код используется для отрицательных чисел. Представляет собой дополнение числа до к- система счисления, n – число разрядов для представления числа.
-5=-251
Использование дополнительного кода позволяет заменить операцию вычитания операцией сложения. Для этого прямой код переводят в обратный и к младшему разряду+1.
510=101пр=11111010доп=25110
static – статический класс памяти. Переменная этого класса размещается в сегменте данных. Время жизни соответствует времени жизни программы. Область действия ограничивается блоком , в котором они описаны.
struct – тип данных, предназначенных для хранения в 1 объекте значений различного типа.
Switch – переключатель оператора выбора. В соответствии со значением условного выражения позволяет выбрать 1 из нескольких альтернатив.
Union – (объединение) тип данных предназначенных для хранения 2 и более объектов по 1 и тому же адресу. Если в структуре поля , элементы структуры занимают каждая свою область, то в объединении они размещаются в 1 области., и способ интерпретации значений определяется непосредственно при обращении. Объединение может быть использовано для доступа к отдельным байтам представления значения типа float.
Typedef – используется для назначения типу уникального имени. Необходим для повышения читабельности программы.
Unsigned – беззнаковый
Void – пусто. Используется для обозначения отсутствия возвращаемого значения функции.
While – оператор цикла с предусловием
Do While – с постусловием
Double – число с плавающей точкой двойной точности
Данные.
Понятие типа данных является основополагающим в концепции структурного программирования. Операции и функции языка структурного программирования могут использовать только те переменные, тип данных которых соответствует определенным при создании данных элементов языка С. Пользователю предоставляется возможность создания новых типов данных, с помощью которых проверка корректности, создаваемых пользователем. Функций на этапе трансляций программы. В С нет (язык среднего уровня).
Элементарные данные.
Типы данных, вводимые в язык программирования для описания основных математических данных (численные типы целые и вещественные), типы данных для хранении я символьной и логической информации, перечислимые типы.
Над всеми элементарными данными определены операции ввода\вывода.
Символьная информация тип char
Логическая – int (0-ложь,1-правда)
Целая – int
Вещественная – float, double
Области значений элементарных типов.
1. char – 1 байт (от 0 до 255 без знака, от -128 до 127 со знаком)
2. int – 2 байта (от 0 до без знака, от - до -1со знаком)
3. float – 4 байта , хранится в формате IEEE (institute of electrical and engineer electronic)
8 бит (1 бит занка+7 двоичная экспонента и 24-битовая мантисса) для хранения порядка числа (порядок хранится в смещенном виде), при этом отрицательный порядок , положительный порядок
Мантисса хранится в нормализованном виде, т.к. нормализация приводит к присутствию лидирующей 1 (старший байт), то её присутствие опускается , но подразумевается (лидирующий бит – скрытый бит). Мантисса – число в интервале от 1 до 2. Область значений от до
4. double – 8 байт
Порядок расположения байтов: как правило, младшие байты записываются под младшими адресом, т.е. байты следуют в обратном порядке. Формат аналогичен float, за исключением того, что экспонента 11 бит, мантисса 52 бита + неявный старший бит=1. Область значений от до .
5. long double – 80 бит. Формат аналогичен double. Мантисса длиннее на 16 бит. Диапазон от от до .
Агрегатные данные.
Типы данных, предназначенные для хранения однородной информации фиксированного размера. Для агрегатных данных определен прямой доступ к элементам, составляющим данные этого типа.
Массив – линейная структура данных, реализуемая методом последовательного хранения. Элемент массива идентифицируется 1 или несколькими индексами. Индекс – целое число, значение которого определяет позицию соответствующего элемента в массиве и используется для осуществления доступа к этому элементу.
Над отдельными элементами массива определены все операции, определенные для значений типа элемента массива. Над самим массивом операции не определены. Для массивов не существует операций добавления или удаления элементов, возможна только модификация значений элементов.
Описание элементов типа массив.
Синтаксис: тип данных, идентификатор в [ ] количество элементов массива по данному измерению.
float х[15] массив из 15 элементов типа float. В качестве элементов массива может использоваться массив.
int А[10][7];массив из 10 элементов типа массив, из элементов типа int
Таким образом, матрица – одномерный массив одномерных массивов (вектор векторов)
char C [2][3][4]// трехмерный массив (вектор вектора векторов и символов)
Размещение в памяти.
Элементарный массив размещается в памяти в порядке возрастания индекса, для многомерных – построчно.
Имя массива представляет собой ссылку на начальный элемент массива.
Для обращения к элементу массива используется операция индексации, в качестве индекса целое число от 0 до n-1, где n – количество элементов по данному измерению.
A[2]=2
При использовании операции индексации происходит вычисление значения смещения в зависимости от объявленных размерностей и значения индексов.
Например,
int А[10][7];
а [3][5]; 5-ый элемент 3-ей строки
* (а+3∙7+5) пропускаем 3 строки
Задача . char C [2][3][4]
Посчитать значение смещения в массиве от начала, элемента C [1][2][3]
Всего 24 элемента. Смещение 23.
Трехмерные массивы представляются по слоям, каждый слой построчно. Для смещения : № строки*число элементов строки, индекс в строке добавляем для определения смещения.
4-мерный массив:
смещение: 1-ая размерность не используется. При передаче в качестве параметра массива 1 из его размерностей может отсутствовать.