Имена переменных могут состоять из букв (только из латинского алфавита), цифр и символа подчеркивания, приравненного к букве. Начинаться имя должно с буквы.
- a, c1, x12_45g но не 1а, 12-78
- “_”используется для образования для длинных имен
begin_of_1 но не _of_1
- в именах различаются маленькие и большие буквы (с большой буквы обычно пишут именованные константы, с малой – имена переменных);
- различают имена переменных;
- имена внутренних - до 31 знака;
- имена внешних - до 6 символов.
- ключевые слова языка Си зарезервированы (не могут быть использованы как имена !!!)
int, if, for, char…
Эти слова пишутся только маленькими буквами
Пример 6.3:
#include <stdio.h>
#define KOL 12
main()
{ int i, main[KOL], first_day_of_year;
}
Типы и размеры данных
6.4.2.1 Базовые типы Си
char единичный байт, содержащий одну литеру из допустимого набора (ASCII);
int целое, отображаемое на естественное представление целых4
float вещественное одинарной точности;
double вещественное удвоенной точности.
6.4.2.2 Квалификаторы
Различают два вида квалификаторов в языке Си:
1) длины (применимы к целым, int можно опускать)
- short
- long (можно применить к типу double)
2) знака (применимы к символьному и любому целому типу)
- signed
- unsigned
Примеры записи:
long int = long
short int = short
short<int<long
limits.h - в этом файле устанавливаются размеры типов
float.h - в этом файле устанавливаются константы с плавающей точкой
Реализация типов в языке Turbo C
ТИП Размер, бит Диапазон
Unsigned char 8 0..255
Char 8 -128..127
Unsigned short 16 0..65535
Short 16 -32768..32767
Unsigned int 16 0..65535
Int 16 -32768..32767
Unsigned long 32 0..4294967245
Long 32 -2147483648..2147483647
Float 32 3.4e-38..3.4e+38
Double 64 1.7e-308..1.7e+308
Long double 64 1.7e-308..1.7e+308
Отсутствует базовый тип логический, который моделируется целым типом:
– ложь = 0, истина = не 0.
Присутствует тип указатель.
Введен тип пустой (void) – отсутствие какого-либо значения.
Константы
6.4.3.1 Целочисленные константы
Типы int и long.
Системы исчисления
В 10 с/с цифры от 0 до 9 не начинающиеся с 0
В 8 с/с цифры от 0 до 7, обязательно начинаются с 0
В 16 с/с цифры от 0 до 9, буквы A..F (a..f) начинаются с 0х или 0Х
Пример 6.4:
170 /*десятичная*/
0252 /*восьмиричная*/
0хАА /*шестнадцатиричная*/
170L /*десятичная длинная*/
0252L /*восьмиричная длинная*/
0ХAАL /*шестнадцатиричная длинная*/
Во внутреннем представлении, если целая константа превысила 16 разрядов – автоматически представляется как 32 разряда (10 с/с). Если значение 8-ой или
16-ой константы превысило наибольшее целое без знака, то оно также будет представлено, как длинное беззнаковое.
6.4.3.2 С плавающей точкой
У констант с плавающей точкой float обязательно должны быть либо десятичная точка, либо е (экспоненциальная часть):
314.15 e-2 = 3.1415 = 314*10-2
6.4.3.3 Символьная
Внутримашинное представление информации записывается для каждого символа, причем изображение символьной константы берется в ‘ ‘.
1) для представления “читаемых” (“печатных”) символов используются внутримашинные коды – ASCII, КОИ-8, ДКОИ.
2) Специальные символьные константы (ESС-последовательности):
- Апостроф \’
- Кавычки \”
- Пусто (нулевой символ) \0
- Новая строка \n
- Обратная косая \\
3) Последовательности трех восьмеричных символов: \ddd (код символа).
Пример 6.5:
‘M’ ‘m’ ‘П’ ‘п’
‘\n’ ‘\\’
‘\016’ = ‘f’
Символьная константа имеет тип int (т.к. есть расширенные коды в ASCII, размером в 2 байта).
6.4.3.4.Строковая константа
Последовательность символов кодов внутримашинного представления, заключенная в парные кавычки (“ ”).
Пример 6.6:
“MM” “”ПМ” “Informatique” “m” “o”
Строковая константа представляет собой массив символов, в конце которого вставлен код признака конца строки - \0.
“ПМ”
П | М | \0 |
6.4.3.5 Константное выражение
Оперирует только с константами.
Кроме арифметических констант могут быть использованы именованные константы.
#define <имя> <текст>
<имя> - символьное имя
<текст> - последовательность литер
Семантика:
Далее по тексту программы производиться замена <имя> на <текст>, кроме как:
- внутри строковых констант;
- если цепочка, составляющая имя, является частью определения другого имени.
Особенности синтаксиса:
- имя может содержать только из заглавные буквы;
- не нужно писать декларации;
- ее нужна ; после #define.
Пример 6.7:
#define MAX 100
#define V_YEAR 1
После своего определения именованные константы могут использоваться в константных выражениях.
Пример 6.8:
#define MAX 100
…
float a[MAX]…
Пример 6.9:
#define V_YEAR 1
…
int days_of_year [31+28+V_YEAR+31+30+31+30+31+31+30+31+30+31];
7 ДЕКЛАРАЦИИ В СИ
7.1 Декларации – назначение и синтаксис
В Си переменные надо объявлять до первого использования.
Декларация:
1) специфицирует тип;
2) содержит список переменных этого типа;
3) возможна начальная инициализация;
4) возможен квалификатор константы (const).
Пример 7.1:
int up, down, step;
char c, str[101];
или
int up;
int down;
int step;
char c;
char str[101];
7.2 Инициализация
Инициализация (от англ. Initial – начальное) – это процесс придания переменным начальных значений при их объявлении. Записывается в Си в виде выражения после символа равно при декларации переменной:
char newline=’\n’;
Если обычная декларация только выделяет память для переменной, то декларация с инициализацией, записывает в память и соответствующую информацию.
Пример 7.2
int i =0;
int board=MAX+1;
float eps=1.0e-3;
char error[]=”Ошибка: ”;
О | ш | и | б | к | а | : | \0 |
int kdm[12]={31,28,31,30,31,30,31,30,31,31,30,31,30,31};
7.3 Квалификатор константы const
Квалификатор const записывается перед декларацией. Его используют для того, чтобы запретить возможность изменения значения этой переменной в программе.
Пример 7.3:
const float pi=3.1415;
const int kdm[12]={31,28,31,30,31,30,31,30,31,31,30,31,30,31};
……
pi=3.14; /*нельзя*/
kdm[i]=kdm[i]+1; /*нельзя*/
8 ОПЕРАТОРЫ В ЯЗЫКЕ СИ
8.1Арифметические операторы
В языке Си привычные знаки операций называют операторами, а конструкции языка (ветвления, циклы) называют инструкциями.
Свойства операторов:
- арность (количество операндов);
- позиция (место по отношению к операндам);
- приоритет (важность, старшинство);
- ассоциативность (порядок выполнения операторов с олинаковым приоритетом).
1.Операторы +, -, / , * , % бинарные.( % - остаток от деления)
Оператор | Целые | Вещественные |
+ | Сложение | Сложение |
- | Вычитание | Вычитание |
* | Умножение | Умножение |
/ | Деление нацело | Деление нацело |
% | Остаток от Деления | -------------------- |
Пример 8.1:
year%4
Приоритет:
prio(+) = prio(-)
prio(*) = prio (/) = prio(%)
prio(*, /, %) > prio(+, -)
Для унарных +, - :
prio(унарных)>prio(*, /, %)
Ассоциативность
Ассоциативность определяет порядок выполнения операторов с одинаковым приоритетом. Все арифметические операторы левоассоциативные.
Пример 8.2:
8/2/2 è 4/2=2
8.2 Операторы отношения и сравнения на равенство
Бинарные операторы:
1) отношения:>,>=,<,<= (одинаковый приоритет);
2) сравнения на равенство:
==(равно) !=(неравно)
Приоритет одинаковый внутри группы.
prio(отношения)>prio(сравнения на равенство)
prio(отношения)<prio(арифметических)
Пример 8.3:
K+1<l+2 (k+1)<(l+2)
Year%4==0 (Равен ли остаток от деления year на 4 0 ?)
Все операторы сравнения и отношения вырабатывают значение истина и ложь. В языке Си:
- ложь – 0
- истина - ≠ 0
- 8.3Логические операторы
8.3.1 Бинарные операторы:
&&- логическое ‘и’
|| - логическое ‘или’
Вычисление результата логического выражения выполняется до тех пор, пока не вычислится истинность выражения (слева на право).
Результат && есть “ложь”, как только первый попавшийся операнд есть “ложь”. Результат || есть “истина”, как только первый попавшийся операнд -“истина”.
Дальше вычисление не производится.
Свойства:
&& и || -левоассоциативные
prio(&&) = prio(||)
prio(&&) <prio (отношения, сравнения на равенство)
X&&Y
X Y | И | Л |
И | И | Л |
Л | Л | Л |
X||Y
X Y | И | Л |
И | И | И |
Л | И | Л |
Пример 8.4:
4 3 2 6 5 1 8 7 (приоритет)
Year%4==0&&year%100!=0||year%400==0
8.3.2 Унарный оператор
Логическое отрицание
не - !
0,если х ≠0
!х=
1,если х=0
prio(!)>prio(&&,||)
Пример 8.5:
Эквивалентны:
res==0 и !res
8.4 Побитовые операторы
Применяется к целочисленным операндам (char, short, int, long) знаковым и без знаковым.
8.4.1 Бинарные
8.4.1.1 Побитовое И
& : используют для обнуления разрядов или бита внутри байта
X&Y
X Y | ||
Пример 8.6:
Значение выражения содержит 1 Maska1=017;
во всех разрядах, в которых ie1 и ie2 P=p&maska1;
содержит 1 и 0 во всех остальных разрядах
8.4.1.2 Побитовое ИЛИ
| : для установки разрядов в 1
X||Y
X Y | ||
Пример 8.7:
Значение выражения содержит 1 Maska2=03;
во всех разрядах, в которых ie1 или ie2 m=m&maska2;
содержит 1 и 0 во всех остальных разрядах
Следует отличать логические и побитовые операторы !!!
Пример 8.8:
X=1; y=2;
x&&y /*=1*/
x&y /*=0*/
8.4.1.3 Побитовое исключающее ИЛИ
^ : 1- разные значения
0- остальные разряды
X ^ Y
X \ Y | ||
Пример 8.9:
x=0177;
y=01;
x^y /*0176*/;
8.4.1.4 Сдвиг влево
<< - правый операнд должен быть >0
Это целое положительное число, указывающее на сколько битов необходимо сдвинуть левый операнд влево.
Пример 8.10
x=02; /*0102*/
y=x<<1; /*01002=4*/
Сдвиг влево соответствует умножению левого операнда на степень двойки, показатель степени задается правым операндом оператора сдвига
8.4.1.5 Сдвиг вправо
>> - правый операнд должен быть >0
Это целое положительное число, указывающее на сколько битов необходимо сдвинуть левый операнд вправо.
Пример 8.11
x=06; /*1102*/
y=x>>1; /*112=3*/
z=x>>2; /*12*/
Сдвиг вправо соответствует делению нацело на степень двойки.
8.4.2 Унарные
Унарный оператор побитового отрицания ~
x | ~x |
Пример 8.12
c=c&~03;
Значение выражения :
C_1 ……………………………………С_14 С_15 С_16
8.5 Операторы присваивания
Операторы присваивания имеют следующий вид
<e1><op>=<e2> - выражение
<op> - бинарный оператор
+ % << |
- >> ^
* &
/
Выполнение
<e1>=<e1><op><e2>
значки операторов присваивания
+= /= <<= &= ^=
-= %= >>= |=
Пример 8.14
x=15; x8=015;
y=8; y8=07;
z=5; z8=05;
x+=2; /*x=17*/
y-=7; /*y=1*/
z*=4; /*z=20*/
z/=2; /*z=10*/
z%=3; /*z=1*/
x8<<=2; /*x8=064*/
y8>>=1; /*y8=3*/
x8|=03; /*x8=067*/
x8^=07; /*x8=060*/
!!! Внимание !!!
x*=a+b ( x=x*(a+b)
( x=x*a+b;
Все операторы правоассоциативные.
8.6 Инкрементные и декрементные операторы
Унарные
инкрементный ++ : добавляет 1 к операнду;
декрементный -- : вычитает 1 из оператора
необычность
префиксный ++(--) увеличивает (уменьшает) операнд до его использования
постфиксный ++(--) увеличивает (уменьшает) операнд после его использования
Пример 8.15:
x=2;
y=x++; /*y=x; x+=1;
y=2; x=3*/
x=2;
z=++x; /*x+=1; z=x;
x=3; z=3*/
Эти операторы можно применять только к переменным, но не к выражениям.
8.7 Преобразование типов
Преобразование (приведение) типов: приведение операндов разных типов к некоторому общему.
Существуют правила, согласно которым операнды приводятся к общему типу.
1) Для бинарных операторов:
а) если 1 из операндов имеет тип long double, то операнды приводятся к типу long double;
б) если 1 из операндов имеет тип double, то общий тип – double;
в) если 1 из операндов имеет тип float, то общий тип - float;
г) если 1 из операндов имеет тип short или int, то общий тип – int; (для целочисленных операндов);
д) если 1 из операндов имеет тип long, то общий тип – long, то общий тип- long (для целочисленных операндов).
2) При присваивании:
значение правой части приводится к типу левой части, это и будет типом результата.
а) char -> int (размножение знака)
б) int -> short
int -> char
long -> int
long -> char
(отбрасывание старших разрядов)
в) float -> int
int -> float
(преобразование типа с ПТ <-> целое)
г) double -> float (округление/отбрасывание)
3) При вызове функций (будет рассмотрено в соответствующей теме)
4) Явное задание приведения типов
Когда ни одно из вышеуказанных правил не выполняется, то используется оператор <тип>, который задаёт явное преобразование к явному типу данных.
- унарный;
- префиксный;
- правоассоциативный
Синтаксис:
(<имя_типа>) е,
где е – выражение
Семантика:
<е> приводится к заданному <типу>
Пример 8.19:
int x=16;
…
y=sqrt((double)x);
9 УПРАВЛЕНИЕ В СИ
Управление – определенный порядок выполнения вычислений в программе.
9.1 Инструкции и блоки
Если в конце выражения поставить ‘ ; ’, то выражение становится инструкцией.
<инструкция>::=<выражение>;
Пример 9.1:
x=0 j++ /* выражения */
x=0; j++; /* инструкции */
Составная инструкция ( блок ).
<блок>::={ [<декларация>]
<инструкция1>;
………………….
<инструкция n> ;
}
Внутри блока разрешены как операторы декларации так и исполнимые операторы.
9.2 Инструкция if – else
Синтаксис
if(<выражение>) либо if (<выражение>)
<инструкция1> <инструкция1>
else <инструкция2>
Семантика
Вычисляется значение выражения, если значение выражения истинно, то выполняется <инструкция1>, если ложно то <инструкция2>
Пример 9.2:
int a,b,c; /* исходные данные */
int x; /* результат */
……..
if(a>b) /* вариант 1 */
if(a>c) x=a;
else x=c;
else if(b>c) x=b;
else x=c;
/* вариант 2 */
………………………..
x=a;
if (b>x) x=b;
if(c>x) x=c;
9.3Переключатель switch
Используется для разветвления алгоритма более чем на 2 направления.
Синтаксис
Switch(<выражение>)
{ case <константное выражение1>:<инструкции 1>
case< константное выражение n>:< инструкции n>
default:<инструкции>
}
Семантика
Каждая ветвь case помечена одной или несколькими целочисленными константами или константными выражениями.
Исполнение всей конструкции switch начинается с той ветви case, в которой константное выражение совпадает со значением выражения записанного после слова switch. Если не одна из констант не подходит, то выполняется ветвь помеченная default.Ветвь default необязательна, и если ее нет, то ничего не вычисляется. Ветви case и default можно размещать в любом порядке. Поскольку выбор любой из ветвей case выполняется как переход на метку, то после выполнения одной ветви case, программа переходит к выполнению следующей ветви. Если этот переход не устраивает, то ветвь case нужно завершить оператором break.
Пример 9.3:
/* kd – количество дней месяца */
if (j==1|| j==3|| j==5|| j==7|| j==8|| j==10|| j==12) kd=31;
else if(j==2) kd=28;
else kd=30;
Пример 9.4:
………………………………..
switch (j)
{
case 1: kd=31; break;
case 2: kd=28;break;
case 3: kd=31;break;
…………………………….
case 12: kd=31;break;
default:printf(”Ошибка”);break;}
Пример 9.5:
switch (j)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12: kd=31; break;
case 4 :case 6: case 9: case 11: kd=30;break;
default: if (j==2) kd=28;
else printf(”Ошибка”);break; }
9.6 Цикл while
Синтаксис:
While (<выражение>)
<инструкция>
Аналог ”пока” языка алгоритмов. Это цикл с неизвестным количеством повторений, с предусловием.
Семантика:
Вычисляется выражение, если оно отлично от 0 (истинно),
то выполняется инструкция и снова переход на проверку выражения.
Как только выражение станет равным 0 цикл while завершается. Если необходимо в теле цикла выполнить больше чем 1 инструкцию, то надо взять в { }
Пример 9.6:
/* е в степени х (с точностью eps ) */
float y,s,,eps,x;
int i,n;
………………………………………… /* Ввод х */
y=1; n=1; i=1; S=x;
while (s/n>eps)
{
y+=s/n;
i++;
n*=i;
s*=x;
}
9.7 Цикл for
Синтаксис
For (<выражение 1>;<выражение 2>;<выражение 3>)
<инструкция>
Это цикл с известным числом повторений.
Семантика
< выражение 1>
while(<выражение 2>)
{< инструкция >;
< выражение 3>;
}
<выражение 1> - инициализация
<выражение 2> - условие завершения цикла
<выражение 3> - изменение
Любое из этих 3 выражений может отсутствовать, но ‘;’ обязательно!!!
Пример 9.7:
/* бесконечный цикл */
for( ; ;)
{……...}
Если опущены <выражение1> и <выражение3> - они не используются.
<выражение1> берется до цикла.
<выражение3> изменяется внутри цикла
Пример 9.8-9.9
#define N 10
float X[N]
int i;
float s;
………………………………..
s=0;
for(i=0;i<N;i++)
s+=X[i];
Либо:
for(s=0,i=0;i<N;i++)
s+=X[i];
Особенности цикла for в языке С:
Переменная цикла и ее предельное значение могут изменятся внутри цикла. По завершению цикла переменная цикла определена. В выражениях 1, 2 и 3 может быть использовано более одного выражения, разделенных оператором ‘,’
‘,’- бинарный, инфиксный, левоассоциативный оператор.
Приммер 9.10 Реверсировать массив.
0 1 2 3 4
1 |
#define N 10
…………….
float x[N];
int i, j;
float r;
…………….
For( i=0 , j=N-1; i<j ;i++ , j--)
{
r=x[i];
x[i]=x[j];
x[j]=r;
}
9.6 Цикл do while
Синтаксис: do <инструкция> while (<выражение>)
- цикл с неизвестным числом повторений.
Семантика: 1.выполняется <инструкция>
2.вычисляется значение <выражения>
3.если <выражение> истинно(не равно 0), то снова переходим на пункт 1. Если <выражение> равно 0 (ложно) – конец цикла.
9.7 Инструкция break и continue
Break используется в циклах while, for, do while и в конструкции zwitch. В циклах использование break приводит к немедленному их завершению (до достижения предельного значения переменной цикла for или до достижения условия завершения цикла в while или do while).
Пример 9.11 Определить, является ли матрица А положительно определенной (все элементы больше 0).
Aij>0 , i принадлежит [1,m], j принадлежит [1,n]
#define N 10
#define M 15
float a[M][N];
int i,j;
int pr=1;
…
for (i=0; i<=M-1;i++)
for(j=0; j<N; j++)
if (a[i][j]<=0 )
{ pr=0; break; }
if (pr) printf(“A - положительно определенная ”);
else printf(“A – не положительно определенная ”);
! Break завершает немедленно ближайший , охватывающий его цикл.
Continue вызывает переход к следующей итерации цикла : в for изменяет переменную цикла согласно закона , указанного в шапке цикла, в while , do while приводит к вычислению выражения , которое является условием продолжения цикла.
Пример 9.12 . Найти сумму S отрицательных элементов массива x[N]
#define N 5
float x[N] ;
int i;
float s=0;
…
for(i=0;i<=N-1;i++) или for(i=0;i<N;i++)
if (x[i]<0) s+=x[i]; {if (x[i]>=0 )continue;
s+=x[i];}
10 УКАЗАТЕЛИ И МАССИВЫ
10.1 Указатели
int x;
int *px; /* объявляется указатель на данное целого типа */
px=&x; /* указателю px присвоили адрес переменной x */
ПАМЯТЬ-массив последовательно проадресованных ячеек, с кото- рыми можно работать по одному и группами.
Указатель-группа ячеек памяти (2 или 4 байта) , значениями которых является адрес.
Оператор & (унарный) выдаёт адрес объекта.
Пример 10.1:
p=&c;(р ссылается на переменную с)
pi=&i; (pi ссылается на переменную i)
Применяется только к операндам которые находятся в памятии (переменные и элементы массива)
Не могут быть применины к константам и выражениям
Унарный оператор * -оператор раскрытия ссылки,
применяется только к указателям. Результат - объект, на который ссылается указатель
Пример 10.2:
int a=1,b=2,z[5];
int *ip; /* объявляем указатель на переменную целого
типа */
ip=&a; /* указатель ip ссылается на переменную a */
b=*ip; /* b=1 */
*ip=0; /* a=0 */
ip=&z[2] /* ip указывает на z[2] */
Указатель ссылается только на объекты заданного типа (кроме void)
При объявлении указателя можно написать указатель на тип void:
void *p;
но потом применять оператор разоименования (*) нельзя
Пусть
int a=1;
int *ip; => Используем *ip везде, где допустимо использовать a:
ip=&a;
- *ip=*ip+10; /* a+=10 */
- y=*ip+1; /* y=11+1 */
- *ip+=1; /* 11+1=12 */
- +*ip; /* 12+1=13 */
- (*ip)++; /* 13+1=14 */
- ! *ip++; /* изменяется сам указатель, а не то
значение на которое он ссылается */
В этом примере увелечение самого указателя на 1 приводит к тому,что ссылается на следующий элемент того типа, какой был
заявлен в деклорации.
Указатель есть переменная, а поэтому он может встречатся в программе и без оператора *
Пример10.3:
int a;
int *ip,*ir;
ir=&a;
ir=ip;
10.2 Связь между указателями и массивом
В языке C связь между указателями и массивом очень тесная, так как любая операция взятия элемента массива может быть выполнена с помощью оператора *(!!! более того * выполняется быстрее)
[ ] º *
int a[5];
i-й элемент:a[i]
С указателем:
int *pa
pa=&a[0];
x=*pa =>x=a[0];
Адресная арифметика:
Если указатель pa указывает на некоторый элемент массива, то выражение pa+1 указывает на следующий элемент массива, pa+i – на i-й после pa, pa-1 – на предыдущий (перед pa).
Если pa=&a[0], то *(pa+1)~a[1]
pa+i~ адрес a[i]
*(pa+i)~a[i]
Пример 10.4:
int *pa;
int a[5]= -1,-10,-100,-1000,-10000 ;
int a1,a2;
pa=&a[0];
a1=*(pa+1); /* a1=-10 */
a2=*(pa+2); /* a2=-100 */
Связь между адресной арифметикой и индексированием массива
Значение переменой или выражения типа массива есть адрес нулевого элемента этого массива.
ПРИМЕР 10-5
int a[5], *pa, *pm
pa=&a[0]:pm=a;
Эквивалентны
a[i] | *(a+1)
&a[i] | a+i
pa[i] *(pa+i)
Указатели группируються обычные элементы.Указатели также можно индексировать.Тогда *(pa+i) pa[i].Различия между именем.
I 10-4 Различия между именем масства и указателем(в роли имени массива)
Указатель=переменная
-допустимо
int*pa; int a[5]
pa=a;
pa++;
-недопустимо
int*pa;
int a[5];
a=pa;
a++;
Литерные указатели
Строковая константа, записаная в СИ в виде изображение есть массив литер или символов.
Количество байтов=количество литер+1 (для символа ’\ Ф ’)
ПРИМЕР 10-6
Char * pstr
Pstr=’ С указатели ’
Строка не копируется , а только указатели на массив .
ПРИМЕР 10-7
Char s _str[] =” как массив ”
Char *p_str=” с указателем”
s_str ---Элементы этого массива могут изменяться, но ссылается в оперативную память
p_str --- Это указатель инициализированный
В Си нет операторов для работы с массивом в целом ->недопустимо
10.5 Литерные указатели.
Строковая константа есть массив литер (символов). Количество байтов равно количеству литер +1 (для символа окончания строки \0).
Пример 10.6
char *pstr;
pstr=”с указателем”:
! Различие между декларациями строк как массива и с помощью указателя:
Пример 10.7
char s_str[]=”как массив”; /*11dyte*/
char p_str=”с указателем”; /*13byte*/
с | у | к | а | з | а | т | е | л | е | м | \0 |
p_str
к | а | к | м | а | с | с | и | в | \0 |
s_str
Замечание
s_str:
- элементы s_str могут изменяться.
- s_str всегда ссылается на одно и то же место в памяти.
p_str:
- при изменении указателя он будет ссылаться на что либо другое.
!!! В Си нет оператора для работы с массивом в целом (=> недопустимо s_str изменить).
10.6 Массивы указателей.
|
|
|
|
|
|
Удобно в Си текст, представлять массивом указателей.
Пример 10.9
#define KL 100
int n1,n2;
char *v[KL];
char *temp;
int k;
…
temp=v[n1];
v[n1]=v[n2];
v[n2]=temp;
k=KL;
while (k-->0)
printf(“%s\n”,*v++);
10.7 Инициализация массива указателей
Пример 10.10:
Char*m_name[]= { ”ошибка”,”январь”,”февраль”,”март”,”апрель”,
”июнь”,”июль”,”август”,”сентябрь”,”октябрь”,”ноябрь”,”декабрь” } ;
/* обращаемся по номеру месяца */
(n<1 || n>12)? m_name[0]:m_name[n];
10.8 Многомерные массивы
Пример 10.11:
/* представляется как массив массивов */
int mpr[2][9]=
{
/* даты */ {1,7,8,1,2,9,24,7,8},
/* месяцы */ {1,1,3,5,5,5,8,11,11}
}
Это даты праздничных дней Украины не привязанных к Церковному
календарю.
Обращение к элементам двумерного массива.
……………………………………………………………………………
d_may1=mpr[0][3];
m_may1=mpr[1][3];
10.9 Указатели вместо многомерных массивов
Пример 10.12:
int a[3][4] /* массив массивов */
0 1 2 3
Int*b[3]
0)
1)
2)
Массив а занимает 24 байта (2 байта * количество элементов)
Массив b занимает первые 6 байт. У массива b не выделена пока память под собственно элементы. Это выделение может быть выполнено 2 способами:
1) при инициализации;
2) либо явно динамическим захватом памяти (см. 2 семестр);
Преимущество 2-го способа состоит в том , что строки в массиве b
могут быть различной длины. Это преимущество используется в литерных массивах.
Пример 10.13:
Берем из примера 10.10 первые 3 Элемента массива и выделяем под них память 2 способами.
1)
/* объявление массива строк как массива массивов char
m_name1[][10]={”ошибка”,”янв.”,”февр.”};
посчитает
компилятор обязательно задается
о | ш | и | б | к | а | \0 | я | н | в | . | \0 | ф | е | в | . | \0 |
10 20 30
Количество не использованных байтов:12 (40%)
2)
char*m_name2[]={”ошибка”,”янв.”,”фев.”};
0) ошибка\0
1) янв.\0
2) фев.\0
Библиотека для работы со строками string.h
1 strlen(s), где s – строка
Определяет длину строки (информационной части, без \0)
int l;
l=strlen(“пример”); /* l=6 */
2 strcat(s1,s2) /* s1+=s2 */
s2 конкатенируется к s1(s1 – меняется, s2 – не меняется)
char a[]=”Белеет ”, /* a~Белеет */
b[]=”парус ”; /* b~парус */
strcat(a,b); /* a~Белеет парус */
3 strcpy(s1,s2)
Копирование строки s2 в s1 (s1 – меняется, s2 – не меняется)
char a[]=”Белеет ”,
b[]=”парус ”;
char *c;
strcpy(c,a); /* c~”Белеет ” */
strcat(c,b); /* c~”Белеет парус ” */
4 strcmp(s1,s2)
Сравнение строк (в лексико-графическом порядке)
/* Происходит посимвольное вычитание ASCII кодов */
0, если s1=s2
=0, иначе ( разница в коде ):
strcmp=
<0, s1<s2
>0, s1>s2
Пример:
int r1,r2,r3;
char a[]=”ПО96а”,
b[]=”ПО96б”ж
char *c;
strcpy(c,a); /* c~”ПО96а” */
r1=strcmp(a,c); /* r1=0 */
r2=strcmp(a,b); /* r2<0 */
r3=strcmp(b,c); /* r3>0 */
Библиотека проверки символов ctype.h
Тип всех функций - int . Все функции отвечают на вопрос в соответствии с названием функции:
”Являются ли аргумент этой функции тем, что сформулировано в названии?”
Результат : 1 или 0.
Тип аргумента – int !!! Хотя все функции анализируют символы, но символьная константа имеет тип int .(т.к. в константе могут быть символы, которые в ASCII кодируются 2 байтами, а char только
1 байт.
isdigit( c ) – цифра (0..9) (если цифра, то вернет 1, иначе 0)
isalpha( c ) – буква (латынь)
isalnum( c ) – буква (латынь) или цифра
isupper ( c ) – прописная буква
islower ( c ) – строчная буква
Пример:
int c1=’9’,c2=’s’,c3=’G’,c4=’y’,c5=’=’;
int r1,r2,r3,r4,r5;
r1=isdigit(c1); r1=1
r2=isalpha(c2); r2=1
r3=isalnum(c1); r3=1
r3=isalnum(c5); r3=0
r4=isupper(c3); r4= 1
r5=islower(c4); r5=1
Преобразование символов.
1) atoi(s) - выполняет преобразование строки в int
2) atol(s) - выполняет преобразование строки в длинный int
Строка s – это аргумент содержащий изображение этого числа.
Результатом является целое или длинное целое число.
Пример:
int i;
long l;
i=atoi (”1996”); i=1996
l=atol(”1999000”); l=1999000
11 СТРУКТУРЫ В ЯЗЫКЕ СИ
Структура языка Си- это эквивалент записи.
Структура - одна или несколько переменных возможно различных типов, которые сгрупированы под одним именем.
ПР.11.1
/* строка таблицы */
Ф.И.О МАТЕМ ФИЗ Р.ЯЗ
Элементы разных типов
ПР.11.2
Представление
/* точка А в пространстве */ можно выполнить с помощью структуры:
xa ya za
Элементы массива безликие.
Элементы структуры имеют имена.
ПР.11.3
/* окружность на плоскости */
x0 y0 R
11.1 Объявление структурного типа в языке СИ
синтаксис:
struct [<имя = тег>]
{<декларация..члена1>;
...
<декларация члена N>;
};
- Декларация структуры
= тип
- Если после слова struct указать имя (tag), то это есть имя типа, кот. можно далее пользоваться как именем любого другого базового типа (как float, int).
- Имена тегов и членов могут совпадать с именами других переменных.
- Объявление структурного типа – это образец, а не декларация данных ( память не выделяется).
- ПР.11.4 /* для 11.2 */
Struct без тега struct point c тегом
{ int xa; { int xa;
int ya; int ya;
int za; int za;
}; };
ПР.11.5 /* для 11.3 */
Struct Struct circle
{ float x0; { float x0;
float y0; float y0;
float r; float r;
}; };
11.2. Декларация переменных структурного типа.
I сп < декларация типа структ. >
<список переменных>; 1 оператор
II сп struct < тег><список переменных>; 2 оператора
ПР.11.6 /* прямая : через точки А и В */
Struct struct point a,b;
{ int xa; см.11.4
int ya;
int za;
} a,b;
Инициализация:
Переменные структурного типа можно инициализировать как и все другие.
ПР.11.7 /* окружность с центром (2;3) и радиусом 5.5 */
Без тега
Struct
{ float x0;
float y0;
float r;
} pr = {2.0, 3.0, 5.5};
c тегом
struct circle pr = {2.0, 3.0, 5.5}
Доступ к элементам структуры
<имя структуры>.<имя члена>
Пример 11.8
/*расстояние от начала координат до точки pt*/
struct
{float x;
float y;} pt={20.0,15.0};
double dist;
dist=sqrt((double)pt.x*pt.x+(double)pt.y*py.y);
printf(“От начала координат”);
printf(“до точки (%f, %f)”,pt.x, pt.y);
printf(“расстояние %f”,dist);
Дата добавления: 2015-12-29; просмотров: 2986;