Элементы языка Си. Символы, лексемы, знаки операций.
Элементы языка Си. Символы, лексемы, знаки операций.
Символы языка
а)прописные и строчные рус и лат буквы, арабские цифры.
б)спец символы и знаки пунктуации
. , : ; ? ‘ !
/ | \ ~ * + ( ) { } < > [ ]
# % & ^ - = “
в)пробельные символы
Эскейп-последовательности состоят из-за которой следуют буквы или цифры и используются для представления неграфических и пробельных символов, символьных и строковых констант.
\n-новая строка
\r-возврат каретки
\t-табуляция
\f-новая страница
\b-забой
\”-“
\\- \
Лексемы
Лексема-это единица текста программы, которая не может быть разбита в дальнейшем и имеет определенный смысл для компилятора: знаки пунктуации, знаки операций, константы , идентификаторы, ключевые слова. Лексемы отделяются друг от друга пробельными символами и другими лексемами. Если лексемы не отделены пробелами, то компилятор выделяя отдельную лексему , объединяет столько символов, сколько возможно ,прежде чем перейти к следующей лексеме.
Элементы языка Си. Константы, идентификаторы, ключевые слова, комментарии.
В Си различают 4-е типа констант: целые, с плавающей точкой, символьные, строковые.
Целые: формат 10-чной константы—цифры от 0 до 9, формат 8-чной константы—от 0 до 7, формат 16-чной—от 0 до 9 и от А до F.
Целой константе присваивается тип, который зависит от ее значения .
С плавающей точкой: Десятичное число представляется в виде действительной величины с десятичной точкой или экспонентой.
[цифры] [цифры] [Е\е(+\-)цифры]
Символьные: Это символы заключенные в ‘ ‘. Значением символьной константы является числовой код символа. Т.к. эскейп-последовательность рассматривается как одиночный символ, ее тоже можно использовать в символьной константе.
Строковые: это последовательность символов , заключенная в “ “. Компилятор добавляет в конец строковой константы символ ‘\0’. Фактически стринг - это массив символов, число элементов которого = числу символов стринга + 1.
Идентификатор.
Идентификаторы состоят из букв, цифр, первой из которых явл. буква. Длина идентификатора создается при его объявлении в программе.
Ключевые слова- предопределенные идентификаторы , которые имеют спец назначения для компьютера. Их нельзя использовать в качестве идентификатора.
Комментарий - последовательность символов, рассматриваемая компилятором как отдельный пробельный символ и игнорируется.
Типы данных.
Типы данных бывают скалярные и составные. Скалярные типы делятся на указатели и арифметические, к-рые в свою очередь можно разделить на целые и плавающие
Целые тип
Тип | Размер памяти | Диапазон значений |
Char | -128 – 127 | |
Int | Зависит от реализ | --- |
Short | -32768—32767 | |
Long | -2147483648—2147483647 | |
Unsigned char | 0 – 255 | |
Unsigned int | -- | -- |
Unsigned short | 0 – 65535 | |
Unsigned long | 0 -- 4294967295 |
Тип char используется для представления символов из множества представляемых символов и по умолчанию интерпретируется как однобайтовая целая величина. Значение объекта типа char явл код символов из набора кода ПЭВМ. Коды 0 – 127 имеют символьный эквивалент. Если значением объекта типа char должны быть русские буквы, то необходимо объявлять переменную как unsigned char .
Переменные типа int и unsigned int не имеют жестко закрепленных размеров и зависят от реализации. Обычно они совпадают или с типом short или с long.
Ключевое слово unsigned указывает на то , что нулевой тип рассматривается как часть числа, а signed , что нулевой бит указывает на знак. Слова unsigned и signed могут использоваться самостоятельно и эквивалентны типу unsigned int.
Плавающие типы:
Float—4 байта (1 бит- знак, 8- экспонента, 23- мантиса)
Double —8 байта (1 бит- знак, 11- экспонента, 52- мантиса)
Long double
Тип long double используется для обозначения чисел повышенной точности. Размер памяти зависит от реализации.
Операции и выражения. Арифметические операции
сначала будет увеличено(уменьшено), а потом использовано, а во втором – наоборот,сначало использовано, а потом увеличено или уменьшено.
Побитовые операции: поразрядные логические операции и операции сдвигов.
В Си имеется 6 операций для манипуляции с битами. Их можно применять только к целочисленным операндам (int, char, short, long).
Они делятся на две группы:
Поразрядные логические операции
&-побитовая и
| - побитовая или
^ - побитовая исключающая или
~ - порозрядная инверсия
Операции сдвигов
>> - сдвиг вправо
<< - сдвиг влево
Операция & часто используется для обнуления нек-рой группы разрядов n=n&077 – обнуляет в n все разряды ,кроме младших семи Операция | часто используется для установки разрядов.
x=x|SET_ON- устанавливает 1 в тех разрядах х, в к-рых она есть в SET_ON Операция ^ дает 0, если операнды совпадают, и 1- если они различны
Операция ~- унарная. Инвертирует биты.
Операторы << >> выполняют сдвиг влево или вправо левого операнда на число разрядов, задаваемых правым операндом, к-рый должен быть целым. Выдвигаемые биты теряются, а вдвигаемые нулевые биты. Сдвиг влево на 1,2,3…разрядов явл наиболее быстрым способом умножения на 2,4,8,.., сдвиг вправо- наиболее быстрым способом деления.
Выр1?(выр2):(выр3)
Если выр1 истинно, то вычисляется выр2 и становится результатом всего выражения, если оно ложно, то вычисляется выр3.
Если типы операндов, принимающих участие в операции условия различны, то тип результата определяется правилами приведения типов не зависимо от значения результатов.
Операция Sizeof
Результатом Sizeofявл размер в байтах типа или переменных. Применение этой операции в массивах возвращает число байтов, необходимое для размещения всех элементов в массиве.
Int I,r;
Char c;
r = sizeof(int) ; [2]
r = sizeof(char); [1]
r = sizeof I; [2]
Переключатель
Инструкцией в языке Си наз любое выражение ,заканчивающееся ;Инструкции могут быть простыми и составными. Составная инструкция или блок- это любая совокупность простых инструкций, заключенных в {}
{[объявление]
инструкция
[инструкция]…
}
Инструкция ветвления
Выбирает из группы альтернатив возможное выполнение продолжения вычислительного процесса.
В Си эти инструкции организованы как :
If- else, switch
Переключатель switch
предназначена для выбора одного из различных вариантов
switch (выр){[объявления]
case конст_выр : [инструкции]
[case конст_выр : [инструкции]]
[default : [инструкции]]}
Выражение следующее за switch может быть любым целым выражением. Значение этого выражения явл критерием для выбора одного из нескольких вариантов. Тело оператора switch состоит из нескольких операторов, помеченых словом case. Обычно в качестве конст_выр используются целые или символьные константы.
В операторе switch может быть только одна ветвь, помеченная default. Она не обязательно должна стоять последней.
Схема выполнения оператора switch
1)вычисляется выр в скобках
2)вычисленное значение последовательно сравнивается с конст_выр
3)если сравнение найдено, то выполняются соответствующие инструкции
4)если сравнение не найдено и есть ветвь default, то выполняется ее инструкция
5)если сравнение не найдено и ветви default нет, то выполняется следующий за switch оператор.
Т.к. выбор ветви case реализован как переход на метку, то после выполнения одной ветви case будут выполняться другие инструкции ветвей case до конца операции. Немедленный выход из переключателя осуществляется с помощью инструкции break;
Char sign;
Int x,y,z;
Switch(sign){
Case’+’: z=x+y;break;
Case’-’: z=x-y;break;
Case’*’: z=x*y;break;
Case’/’: z=x/y;break;
Default: prinf(“ошибочный знак операции\n”)}
Для того чтобы выполнить одни и те же действия для различных значений выражения, можно пометить один и тот же оператор разными case.Допускается использование вложенных операторов switch. В этом случае в ветвях case внешнего и внутреннего операторов допускаются одинаковые конст_выр.
Операторы цикла.
While(выр)
Инструкция
Вначале вычисляется выр в скобках, если оно истино, то выполняется инструкция.
for(выр1;выр2;выр3)
инструкция
выр1(выр. инициализации)- используется для установления начальных значений переменных, управляющих циклом
выр2(выр.условия)- определяет условие при к-ром цикл выполняется
выр3(выр.интеграции)- объявляет изменение переменной, управляющей циклом
Схема выполнения:
1) вычисляется выр1
2) вычисляется выр2,если оно истино,то выполняется инструкция
3) вычисляется выр3
4) снова вычисляется выр2
- - - - - пока условие не станет ложным.
Любое из трех выражений может отсутствовать. При отсутствии выр1 или 3 считается, что их просто нет, а при отсутствии выр2 считается, что оно истино.
Для управления циклом возможно использование не6скольких переменных. При этом используется оператор последовательного вычисления, к-рый наз «запятая». Типом и значением результата явл тип и значение правого выражения, что позволяет в цикле for в любом из трех компонентов иметь по несколько выражений, например, ввести два индекса одновременно.Пара выражений, разделенных запятой, вычисляется слева направо.
Инструкция в цикле for может быть и пустой
Do-while
Используется в тех случаях, когда тело цикла должно быть выполнено хотя бы один раз.
do
инструкция
while(выр)
Схема выполнения:
1) сначало выполняется инструкция
вычисляется выражение. Если оно истино, то инструкция выполняется снова, и так до тех пор, пока выражение не станет ложным.
Continue
Прерывает тело цикла, но передает управление на следующую операцию. Для while, do-while это означает немедленный переход к проверке условия ввода, а для for к прекращению шага. Его можно применять только в циклах. Если цикл вложенный, то прерывается самый внутренний.
Goto
Область действия ограничена ф-цией, в к-рой она определена. Следовательно, каждая метка уникальна. Нельзя передать управление goto в другую ф-цию. Если оператор с данной меткой отсутствует или существует
Пустой оператор
состоит из ; При выполнении его ничего не происходит. Используется в операторах do, for, while, if в случаях, когда тело оператора не требуется, но оно должно быть.
For(…){
For(…){
while(…){
if(…) go t end;
}}}
end:; }
Классы памяти.
Класс памяти выделяется для переменных определенным спецификатором класса памяти, определяемых под переменные. Класс памяти определяет время жизни и область действия объекта, связанные с понятием блока программы. Существует два типа блока: составной оператор и определители ф-ции, состоящие из составного оператора, включающего тело ф-ции + заголовок ф-ции. Блоки могут включать в себя составные операторы, но не могут включать определение ф-ции , внутренние блоки наз вложенными, а внешние- объемлющими.
Время жизни – это интервал времени, в течение к-рого програмный объект существует. Время жизни может быть глобальным или локальным. Объект с глобальным временем жизни существует и имеет определенное значение в течение всего времени выполнения программы. Переменной с локальным временем жизни каждый раз выделяется новая ячейка памяти, когда управление передается блоку, к-рым она определяется. Когда управление возвращается из блока, переменная теряет свое значение.
Переменная с классом auto явл локальной для каждого вызова блока и теряет свое значение при выходе из блока. Она должна явно инициализироваться, иначе ее содержимое имеет неопределенное значение.
Класс памяти static указывает на то, что переменная явл локализованой в блоке, но сохраняет свое значение при повторном входе в блок.
Класс памяти extern означает, что переменная сохраняет свое значение в течение всего времени выполнения программы.
Переменная класса памяти register хранится, если это возможно , в регистре, для повышения скорости выполнения программы. Время жизни для переменной этого класса такое же как для auto. Регистровая память может быть назначена только для типов int и указателей ,имеющих тот же размер, что и int. Если переменная объявлена с классом register , а свободных не оказалось, то ей назначают класс auto.Объкты класса auto и register имеют локальное время жизни, а объекты классов static и extern – гловальное, но точный смысл
Классы памяти.
каждого из идентефикаторов зависит от того, а каком уровне, внутреннем или внешнем, объявлена переменная и от того, явл объект ф-цией или переменной.
Функции. Определение ф-ций.
Любая программа состоит только из ф-ций. Ф-ция – это независимая совокупность объявлений и инструкций, приводящая к решению определенной задачи. Каждая ф-ция имеет имя, для вызова ф-ции. В каждой программе есть только одна ф-ция именем main, с к-рой начинается выполнение программы. При вызове ф-ции ей могут быть переданы параметры посредством переменных. Ф-ция может возвращать значение, это значение- оновной результат ф-ции.
С использованием ф-ции в Си связаны:
1) определение ф-ции
2) объявление ф-ции
3) вызов ф-ции
Определение ф-ции
Определение ф-ции задает имя, кол-во и тип формальных параметров и тело ф-ции. Оно может определять тип возвращаемого значения и класс памяти ф-ции.
[спецификатор_класса_памяти][спецификатор_типа]
имя([спецификатор_формальных_параметров])
тело ф-ции
Класс памяти ф-ции может быть static или extern. По умолчанию считается extern.Спецификатор типа задает тип возвращаемого ф-цией значения и может быть любого основного типа, типа структуры или объединения. Если спецификатор типа не задан, то считается, что ф-ция возвращает значение типа int. Имя ф-ции может быть задано со *, это означает, что ф-ция возвращает указатель. ф-ция не может возвращать массив или ф-цию. Тип возвращаемого значения в определении ф-ции должен соответствовать типу в объявлении ф-ции. Ф-ция возвращает значение, если ее выполнение заканчивается return[выражение]. Если оператор return не задан или не содержит выражение, то ф-ция не возвращает никакого значения, в этом случае спецификатор типа указывается с помощью слова void. Если ф-ция объявлена со спецификатором типа, а значение не возвращается, то результат не определен. Список формальных параметров- это последовательность объявлений формальных параметров, разделенных запятыми.
[register]спец_типа [имя] Список формальных параметров может быть пустым. В списке формальных параметров указывается слово void. Порядок, типы и число формальных параметров в определении ф-ции должны совпадать с порядками, типами и числом параметров в объявлении и всех вызовах ф-ции. Язык Си позволяет задавать переменное число аргументов. Список формальных параметров заканчивается (,…) Однако предполагается, что ф-ция имеет по крайней мере столько аргументов, сколько задано перед последней запятой. Ф-ции может быть передано большее число аргументов, указанных до(,…), над такими аргументами не производится контроль типов. Тело ф-ции – это составной оператор, соединяющий объявления и инструкции. Запрещается внутри тела ф-ции помещать другие ф-ции. Все переменные, объявленые в теле ф-ции, имеют класс памяти auto. Под
Функции. Определение ф-ций.
каждую из переменных при вызове ф-ции отводится память в стеке и производится инициализация., после чего управление передается первому оператору ф-ции. Параметры передаются в ф-цию посредством копирования аргументов, потому в теле ф-ции нельзя изменять значения аргументов.
Вызов
Любая программа состоит только из ф-ций. Ф-ция – это независимая совокупность объявлений и инструкций, приводящая к решению определенной задачи. Каждая ф-ция имеет имя, для вызова ф-ции. В каждой программе есть только одна ф-ция именем main, с к-рой начинается выполнение программы. При вызове ф-ции ей могут быть переданы параметры посредством переменных. Ф-ция может возвращать значение, это значение- оновной результат ф-ции.
С использованием ф-ции в Си связаны:
4) определение ф-ции
5) объявление ф-ции
6) вызов ф-ции
Вызов ф-ции имеет формат
выр ([список_выр])
Выражение вычисляется как адрес ф-ции. Список_выражений представляет собой список фактических аргументов, к-рый может быть пустым.
Выполнение вызова ф-ции происходит следующим образом:
1.Вычисляется выражение в списке выражений и производится необходимое преобразование
Call – by – value
(c передачей значений параметров ф-ции)
Используетя когда оьъем передаваемых данных ф-ции не велик и ф-ция не возвращает большой объем данных.
Call - by – reference
(с передачей адресов переменной)
В качестве параметров ф-ции передаются копии адресов переменных, благодоря чему ф-ция получает доступ к адресам переменных, вызывающихся в программе. Это позволяет внутри ф-ции изменять значения переменных. Этот способ позволяет разрабатывать ф-ции,имеющие доступ к массивам и др. протяженным объектам данных. Если в качестве параметра ф-ции используется имя массива, то в ф-цию передается не сам массив, а адрес начала его расположения в памяти.
Рекурисвные ф-ции.
Любая ф-ция в Си может быть вызвана рекурсивно. При каждом вызове для формальных параметров и переменных с классом памяти auto, register выделяется новая память. Переменные с классом памяти static не требуют новой памяти при каждом рекурсивном вызове. Параметры предыдущих незавершенных вызовов не затираются, но при этом они не доступны. Допустимо любое число рекурсивных ф-ций.
Пр: n!= 1 n=0
n(n-1)! n>0
long fact(int n )
{ return (n < = 1)? 1 : n*fact(n-1);
}
Include
# include “спецификатор_маршрута”
# include <спецификатор_маршрута>
Эта директива добавляет содержимое заданного файла включения к другому файлу так, как если бы этоот файл появился в точке, где записана директива. Данные форматы отличаются способом поиска препроцессора включаемого файла. Если спецификатор_маршрута не полный и заключен в “ ”, то препроцессор начинает поиск в текущем рабочем каталоге. Если в этом каталоге файл не найден или <спецификатор_маршрута>, то поиск файла включения осуществляется в стандартных системных каталогах.
Include
Включаемые файлытакже могут содержать директива препроцессора. Допускается до 10 уровней вложенности включаемых файлов. Файлы включения полезны для объявления внешних переменных, составных типов данных, определенных констант и макроопределений.
Препроцессорные операции
Если в программе имеется макроопределение с параметрами, то они наз формальными параметрами и в тексте подстановки могут быть произведены перпроцессорные операции: 1)образование строки #;
2)операция объединения лексем #
1.если предшествует формальному параметру в тексте подстановки, то соответствующий фактический аргумент, передаваемый макрокомандой, будет заключаться в “” и считаться строковым литератором. Такую конструкцию можно использовать для конкотенации с другими строковыми литераторами.
2.операция объединения лексем понимается препроцессором как операция конкотенации аргументов (обязательно два аргумента)
25.1, Указатели.Операции &,*.
В языке Си реализованы два альтернативных способа доступа к переменным:
1)по имени
2)механизм указателя
Указатель – это переменная, содержащая адрес другой переменной. Использование указателей позволяет создавать более быстрые и компактные программы и необходимо в следующих случаях :
1)при динамическом распределении памяти
2)передача указателя в качестве аргумента ф-ции позволяет в вызываемой ф-ции изменить значение вызывающей программы
3)использование указателя явл альтернативным по отношению к использованию индексов способом доступа к элементам массива.
4)можно определить указатель на ф-цию, что позволяе использовать его для вызова разных ф-ций.
5) при работе с файлами
Объявить указатель можно по следующему формату:
Спецификатор_типа * идентефикатор;
Так запись char*cptr означает,что объявлена переменная cptr, к-рая явл указателем на объект типа char.
После объявления указателя под него выделяется память, но пока он ни на что не указывает. До тех пор пока указателю не будет присвоено конкретное значение, его нельзя использовать в программе. Размер указателя = 2-4 байта
25.2, Указатели.Операции &,*.
В языке Си определены две операции для работы с указателями :
&(адрес) – унарная
*(разадресация или раскрытие ссылки)- унарная
Операция & используется для получения адреса какого-либо объекта
Следует различать два понятия : указатель переменная и указатель константа.
указатель переменная – это переменная для хранения адреса объекта
указатель константа - это значение адреса оперативной памяти
Пр: char *cptr,c;
Int *iptr, I;
cptr= &c;
iptr = &I;
В этом примере iptr -указатель переменная , а &I - указатель констант.
Операция & применяется только к объектам, расположенным в памяти : переменные, массивы и т.д. Ее операндом не могут быть выражения, константы, регистровые переменные.
Доступ к объекту через указатель осуществляется с помощью операции *, к-рая рассматривает свой операнд как адрес некоторого объекта и использует этот адрес для выборки содержимого. Типом результата операции * явл тип объекта, адресуемого указателем. Указатель всегда должен указывать на объект того же типа с к-рым он объявлен.
Присваивание указателей
Можно присвоить один указатель другому. Эта операция имеет смысл только в том случае, если они адресуют объекты одного и того же типа.
#include <stdio.h>
main()
{int I , *ip1, *ip2;
I= 125
Ip1=&I;
Ip2=&ip1;
Printf(“%d\t%d\n”,*ip1,*ip2);
}
результат : 125 125
Сравнение указателей
Сравнение двух указателей используется чаще всего в том случае, если оба указателя адресуют объект общий для них
#include <stdio.h>
main()
{int a,b, *ip1, *ip2;
Ip1=&a;
Ip2=&b;
If (ip1!=ip2) printf(“указатели не равны”)
Else printf(“эта строка не напечатается”);
}
Массивы и указатели.
Доступ к массиву можно осуществить двумя способами:
1)с помощью индексного выражения
2)в виде указателя со смещением
Элемент массива можно изобразить в виде указателя со смещением и в виде имени массива с указанием элемента. Эти две записи можно и сочетать. В общем случае индексное выражение имеет вид : выр1[выр2], где выр1 – это указатель, выр2 – целое число.
n-ый элемент массива может быть записан как : a[n], n[a], *(a+n), *(n+a), pa[n], n[pa], *(pa+n), *(n+pa)
Указатели на функции.
Имя функции - это указатель-константа на функцию, равный адресу точки входа, т.к. сама функция не является переменной. Но можно определить указатель на функцию и работать с ним как с обычной переменной: присваивать, размещать в масиве, передавать в качестве аргумента, возвращать как результат. Формат определения указателя на функцию: type(*name)(arg_list) где type – тип возвращаюемого функцией значения. name – имя переменной-указателя на функцию, arg_list – необязательный список аргументов.
Указатели на функции используются в следующих случаях:
1) многие библиотечные функции используют в качестве аргумента указатель на функцию.
2) Можно разрабатывать универсальные программы
3) указатели на функцию могут использоваться для косвенного вызова резидентных программ.
Как и переменные, указатели на функцию могут объединяться в массивы.
Типичным применением указателя на функцию являются так называемые системы управления меню. При выборе позиции меню ( от 1 до5 ) вызывается соответствующая функция. Указатели на каждую функцию хранятся в массиве указателей на функцию, выбор пользователя используется как индекс массива, а указатель используется для вызова функции.
#include<stdioh.h>
int difference(int,int);
int sum(int,int);
main()
{ int (*funcptr)(int,int);
int v1=20,v2=5,res;
funcptr=difference;
res = (*puncptr)(v1,v2);
printf(“%d\n”,res);
funcptr = sum;
res = (*puncptr)(v1,v2);
printf(“%d\n”,res);
}
int difference(int a,int b)
{return a-b;}
int sum(int a,int b)
{return a+b;}
В результате будет выведена сначало разность чисел 15, а потом их сумма 25
Функции malloc и free
malloc()
СТЭК |
свободная память |
раздел глоб. Перем и конст |
Код програмы |
void *malloc(size_t size);
void *free( void *p);
Ф-ция malloc выделяет обл памяти размером size -байт. Эта ф-ция содержится в файле stdlib.h, или alloc.h. Ф-ция malloc возвращает укзатель на начало выделяемого участка памяти. Участок выделяемой памяти <=64 кбайт. Свободная память хранится в виде списка блоков. Каждый блок содержит указатель на следующий блок, размер и само свободное пространство.
Все блоки в списке хранятся в порядке возрастания адресов в памяти, при этом послед. блок содержит указатель на первый. При запросе на память просматривать список свободных блоков, пока не обнар достаточно большой. Если размер точно такой же как нужно выделить, то он отделяется и отдаётся для пользования, если он больше то он отрезается, а оставшаяся часть остаётся в списке. Если в памяти свободного места нет то ф-ция возвращает 0.
Функции malloc и free
void free(void p)
Ф-ция free освобождает блок памяти, на начало которого указывает р. После этого память может быль использована в malloc.
Библиотека stdlib.h содержит ещё 2 функции для динам выделения памяти: calloc, realloc.
calloc – динимически выделяет память под массив
void *calloc(size_h memb, size_t size)
memb – число элементов массива
size – размер отдельного элемента
Возвращает либо NULL, либо указатель на начало выделеного участка памяти.
realloc – изменяет размер объекта память под который была выделена ранее. Содержимое объекта не изменяется, если объём памяти больше чем предыдущий размер объекта и наоборот.
void *realloc(void *ptr, size_t size)
size – новый размер
ПР: #include<stdio.h>
#include<stdlib.h>
main()
{ int *p,t;
p = (int )malloc(40*sizeof(int));
if(!p){printf(“Нехватает памяти\n”);
exit(1);}
for(t=0;t<40;t++) *(p+t)=t;
- - -
for(t=0;t<40;t++);
printf(“%d\n”,*(p+t));
free(p);
}
Операции над структурами
Возможны следующие операции над структурами:
1.Копирование
2.Присваивание (передача структур в функции и возврат их в качестве результата также относится к операции присваивания)
3.Взятие адреса
4.Осущ доступа к переменной
Поля битов.
Язык С допускает использование в структурах полей особого типа – битовых полей (или полей битов). Их использование делает возможным доступ к отдельным битам более крупных объектов. Это позволяет экономнее использовать память. Например : если переменная принимает значения “0” или “1” (флаг), то для ее представления можно использовать 1 бит. Использование групп однобитовых флагов позволяет запаковать несколько объектов в одном машинном слове.
Поле битов – некоторое множество битов, лежащих рядом внутри одной, зависящей от реализации единицы памяти.
Описание поля битов : тип [имя] : ширина;
Тип может быть int, signed, unsigned.
Не допускаются массивы полей битов, указатели на поля битов и функции, возвращающие поля битов.
Каждому битовому полю выделяеться ровно столько бит, сколько указано в поле “ширина”(от 0 до размера длины слова).
Ссылка на битовое поле выполняется по имени, указанном в поле “имя”. Поля могут не иметь имени. В этом случае организуеться пропуск заданного числа бит. Т.е. биты выделяются, но доступ к ним не возможен. Особая ширина безымянного поля, равная 0, используется когда надо выйти на границу следующего слова. Битовое поле может существовать только как элемент структуры и определяет из скольки бит состоит каждый её элемент.
struct имя_типа_структуры {
тип имя1:ширина1;
тип имя2:ширина2;
……….
тип имяN:ширинаN;};
Длина структуры всегда кратна 8;
struct flag{
unsigned one_bit:1;
unsigned two_bit:1;
unsigned three_bit:1;} obj;
Поэтому под переменную obj будет отведено 8 бит, но использоваться будут только первые 3.
В структуре могут быть смешаны обычные переменные и битовые поля. Ссылка к битовым полям obj. one_bit – доступ к полю.
Над битовыми полями возможны следующие операции:
obj.one_bit= obj.two_bit=1;
Объединения
Объединение – это переменная, которая может содержать в разные моменты времени объекты различных типов и размеров. Фактически объединение – это структура, у которой все её элементы имеют нулевое смещение относительно базового адреса. Размер структуры достаточно велик, чтобы вместить самый большой её элемент, а выравнивание удовлетворяет всем типам объединения. Объединения не могут содержать поля битов. Объявление объединения аналогично объявлению структуры, только вместо слова struct используется union.
union u {
int i;
char c;
long int l;};
union u a,b;
Можно объявить переменные в шаблоне. Переменной типа union выделяется место в памяти (в байтах) ровно столько, сколько нужно для самого большого элемента. Т.е. она будет достаточно большой, чтобы в ней разместились переменные других типов.
В каждый момент времени в переменной типа union хранится только одно значение. И оно может быть использовано в выражении. Если используется меньший элемент объединения, то переменная типа union может содержать неиспользованную память.
Помнить о том, какой элемент хранится в объединении, должен программист.
Объединения могут входить в структуры и массивы и наоборот.
struct {
char *name;
int iv;
union {
int i;
float f;
char *s} u;
} sym [nsym];
sym[k].u.i – доступ к полю i объединения u k-того элемента массива структур sym
*sym[k].u.s равносильно sym[k].u.s[o]
Объединения
Инициализировать объединение можно только значением, имеющим тип его первого элемента.
union u {
int i;
char c;
long int l;
} a,b;
a.i=100;
Часто объединения применяются в случаях, когда надо выделить часть целого и переменной или загрузить объединение в структуру, описанную с полями битов.
Ввод, вывод потока.
При вводе/выводе потока все данные рассматриваются как поток отдельных байтов, независимо от того, какое используется устройство ввода/вывода, т.е. поддерживается некоторая абстракция между программой и физическим устройством. Эта абстракция и называется потоком, т.е. поток - это источник или получатель данных.
Так как потоки не зависят от физических устройств, одна и та же функция может выводить информацию на екран и на диск одновременно. Существует 2 типа потока:
1)текстовый поток – последовательность строк, каждая строка имеет 0 или n литер и заканчивается \0 , но операционная среда может потребовать коррекцию текстового потока. Например, пара символов: возврат каретки и перевод строки трактуются как один символ перевода строки при вводе.
2)бинарный поток – последовательность непреобразуемых байтов, которые взаимнооднозначно соответствуют тому, что находится на внешнем устройстве.
Чтобы связать поток с файлом или устройством, его необходимо открыть. Эта связь разрывается посредством закрытия потока.Открытие файла возвращает указатель на обьект типа FILE.
С началом работы автоматически открываются 5 потоков:
stdin – стандартный ввод;
stdout – стандартный вывод;
stderr – стандартный вывод сообщения об ошибках;
stdaux – стандартный дополнительный поток;
stdprn – стандартная печать.
По умолчанию 1-3 относятся к консоли и открываются в текстовом режиме, 4-5 открываются в двоичном режиме.Режим доступа к файлу устанавливается во время его открытия как параметр функции открытия или с помощью спец. переменной _fmode, которая находится в <fctl.h> или <stdlib.h>. fmode может принимать 2 значения: O_BINARY – открывается в двоичном режиме, O_TEXT – в текстовом режиме. По умолчанию устанавливается текстовый режим.
Связующим звеном между файлом и потоком является указатель на файл. Указатель на файл – это указатель на структуру типа FILE, ее шаблон определен в stdio.h. Этот указатель используется для последующей ссылки на поток.
Доступ к файлам через поток ввода/вывода.Открытие потока.Закрытие потока.
Связующим звеном между файлом и потоком является указатель на файл-это указатель на информацию , которое определяет различные характеристики файла(имя, режим доступа, текущая позиция указателя).
Указатель на файл - это указатель на структуру типа FILE, шаблон которой содержится в < stdio.h>. Этот указатель используется для последующих ссылок на потоки
FILE* fp-объявление.
Открытие потока.
Функция fopen открывает поток и связывает с ним файл с заданым именем , она возвращает указатель связанный с этим файлом или NULL если попытка открытия неудачна.
Прототип этой функции FILE*fopen(char *filename,char *mode);
char *filename-указатель на строку-имя файла.
char *mode-задает режим открытия файла.
char *mode может принимать следующие значения :
«r»-открыть только для чтения
«w»-создать для записи .
«a»-открыть файл для добавления в конец файла.
«r+»-открыть для исправления (для чтения и записи)
«w+»-создать для исправления (старое содержимое теряется)
«a+»-открыть файл для исправления уже существующей информации и добавления ее в конец.
Если любой из режимов дополнить буквой b, это означает что файл открывается в двоичном режиме.
ПР: открытие файла “good”
FILE *fp;
If ((fp = fopen(“good”,”r”))==NULL)
printf(“Can not open file\n”); exit(1);}
При открытии файла для чтения требуется, чтобы он существовал. В случае открытия для чтения и записи, существующий файл не уничтожается, если он есть, создается если его нет.
Функция freopen переназначает указатель потока на другой поток. Прототип этой функции: FILE *freopen (char *filename, char *mode, FILE *stream);
Функция открывает файл в режиме mode и свзывает его с потоком stream. Обычно используют для замены файлов, связанных с <stdin>, <stout>…
Закрытие потока.
Функция fclose закрывает отдельный поток, а fcloseall закрывает все открытые потоки, за исключением стандартных.
int fclose (FILE*fp),
возвращает NULL, в случае успешного закрытия файла и EOF в случае ошибки, при этом все данные из буфера считываются в файл. Если поток не закрыт, то он закрывается автоматически по окончании программы. Одновременно можно иметь до 20 открытых потоков.
Функция remove уничтожает заданный файл int remove (char *filename)
возвращает NULL при успешной операции.
Элементы языка Си. Символы, лексемы, знаки операций.
Символы языка
а)прописные и строчные рус и лат буквы, арабские цифры.
б)спец символы и знаки пунктуации
. , : ; ? ‘ !
/ | \ ~ * + ( ) { } < > [ ]
# % & ^ - = “
в)пробельные символы
Эскейп-последовательности состоят из-за которой следуют буквы или цифры и используются для представления неграфических и пробельных символов, символьных и строковых констант.
\n-новая строка
\r-возврат каретки
\t-табуляция
\f-новая страница
\b-забой
\”-“
\\- \
Лексемы
Лексема-это