Оператор приведения на самом деле не меняет тип переменной, а временно генерирует значение нового типа.
Таблица приоритетов.
В таблице приоритетов операторы, перечисленные на одной строке, имеют одинаковый приоритет, строки упорядочены по убыванию приоритетов.
Операторы |
Выполняются |
|
|
() [] -> . |
слева направо |
|
|
! ~ ++ -- + - * & (тип) sizeof |
справа налево |
|
|
* / % |
слева направо |
|
|
+ - |
слева направо |
|
|
<< >> |
слева направо |
|
|
< <= > >= |
слева направо |
|
|
== != |
слева направо |
|
|
& |
слева направо |
|
|
^ |
слева направо |
|
|
| |
слева направо |
|
|
&& |
слева направо |
|
|
|| |
слева направо |
|
|
?: |
справа налево |
|
|
= += -= *= /= %= &= ^= |= <<= >>= |
справа налево |
|
|
, |
слева направо |
|
|
Темы 38-41. Массивы и указатели. Обработка текстов и файлов.
Основные свойства массивов.
Массив – это набор данных, элементы которого образуют упорядоченную последовательность, причем все эти элементы должны быть одного типа.
Как и обычные переменные, массивы в С описываются в начале функции или в начале блока, причем при описании массива, как правило, указывается количество ячеек, под которое будет выделяться память.
тип имя[константа 1][константа 2]..[константа n]
Количество размерностей массива стандартом не ограничивается. Если константное выражение в квадратных скобках присутствует, то оно должно быть натуральным числом. Если константное выражение отсутствует, то считается, что описание не завершено. Завершить описание можно двумя способами: либо при другом описании, либо при инициализации массива.
int a[]={5,6,7,8}.
Информатика 27.03.02 |
51 |
Память при таком описании выделяется по числу инициализаторов. Счет элементов в массивах начинается с 0. Инициализаторы могут присутствовать и при явно заданном размере массива. Если число инициализаторов меньше размерности массива, то оставшиеся элементы получают значение 0. Если число инициализаторов больше размерности, то выдается сообщение о синтаксической ошибке.
int a[50]={0}; - обнуление массива.
Вмногомерных массивах пустой может быть только первая размерность.
int a[3][3]={3,4,5,6};-массив заполняется по строкам int a[3][3]={{3,4},{5},{6}};
Вмногомерных массивах хранение организовано так, что самый правый индекс в паре или наборе индексов меняется чаще всего.
Хотя память под массив выделяется непрерывным куском, особенности статического распределения памяти приводят к тому, что элементы могут и не храниться связным участком.
Символьные массивы можно инициализировать и без использования фигурных скобок:
char mas[]=”Скоро зачет\n”;
Память будет выделена с учетом символа “\0”. При помощи функции printf символьный массив можно распечатать не используя операторы цикла:
printf(“%s”,mas);
Понятие об указателях.
Указатель – это некоторая переменная, значение которой является адресом другой переменной.
Указатели описываются специальным образом: тип *имя;
float *t; - t будет хранить адреса переменных типа float. Адрес сам по себе является целым числом, память под
указатель выделяется как под целое, но для нормальной работы с указателем необходимо знать тип переменной, адрес которой хранит указатель.
Для извлечения адресов служит унарная операция &, которая называется операцией получения адреса.
t=&b; - t хранит адрес b или указывает на b.
Унарная операция * позволяет извлечь содержимое ячейки, на которую указывает переменная, стоящая после символа *. Эта операция называется операцией доступа по указателю.
k=*t;
t=&b; k=*t; равносильно k=b;
Информатика 27.03.02 |
52 |
Связь указателей и массивов.
Любой доступ к элементу массива, осуществляемый с помощью операции индексирования, может быть осуществлён и при помощи указателя.
int a[10]; int *x=&a[0];
х указывает на нулевой элемент массива а, или, иначе говоря, x содержит адрес элемента a[0]. В этом случае адрес любого i-ого элемента массива можно представить как x+i, а его значение – как *(x+i).
Подобные операции верны для любого типа и размера массивов, так как при прибавлении к указателю целого числа i указатель «сдвигается» не на i байтов, а на i элементов этого типа.
x=&a[0]; равносильно |
x=a; |
Если где-либо на |
протяжении программы используется |
идентификатор массива без указания индекса, то эта переменная имеет значение, равное адресу нулевого элемента массива.
Существуют и другие способы записи элементов массива и их адресов. Так a[i] можно записать как *(a+i), а запись &a[i]
эквивалентна записи a+i. С другой стороны, |
если x – указатель, |
то в выражениях его можно использовать с |
индексом, то есть |
запись x[i] эквивалентна записи *(x+i). |
|
Между указателем, которому присвоен адрес нулевого элемента массива, и именем массива существует важное различие. Указатель является переменной, поэтому его значение по ходу программы можно менять (x=a; x++;). Имя массива без указания индекса не может находить в левой части оператора присваивания (записи a++; или a=x; - недопустимы). Это связано с тем, что участок памяти, выделенный под массив, не изменяется на протяжении работы программы.
Над указателями допустимо выполнение следующих операций:
- присвоение указателю в качестве начального значения адреса объекта данных или нуля;
-прибавление к указателю или вычитание из указателя целого числа;
-сравнение двух указателей;
-вычитания одного указателя из другого, если оба указателя указывают на объекты одного типа.
Следующий фрагмент программы можно записать разными способами:
1.int a[5]={3,7,11,8,2}, i, max; max=a[0];
for(i=1;i<=4;i++)
if(a[i]>=max)
max=a[i];
Информатика 27.03.02 |
53 |
2.int a[]={3,7,11,8,2}, i, max; max=*a;
for(i=1;i<=4;i++)
if(*(a+i)>=max)
max=*(a+i);
3.int a[]={3,7,11,8,2}, i, *t; int max=*(t=a); for(i=1;i<=4;i++)
if(*(t+i)>=max)
max=*(t+i);
4.int a[]={3,7,11,8,2}, *t; int max=*a; for(t=a;t<=a+4;t++)
if(*t>=max)
max=*t;
При работе с символьными массивами с использованием указателей можно вообще явным образом не выделять память под массив:
char a1,a2;
a1=”Кругом одни враги”; a2=a1+17;
while (--a2>=a1) printf(“%c”,*a2);
printf(“\n”);
Темы 42-43. Классы памяти. Функции. Способы организации взаимодействия между функциями.
Аргументы и возвращаемые значения функций.
В программе на C может быть любое количество функций, среди
них |
нет |
иерархии. Но |
первой будет выполняться функция main(), |
||
где |
бы она ни стояла. Любая функция в процессе |
своей |
работы |
||
может |
вызвать любую |
другую функцию или даже |
саму |
себя |
|
(рекурсия). |
|
|
|
||
|
Чтобы вызвать функцию необходимо обратиться к |
ней по |
имени |
||
в качестве оператора или операнда, указав после имени в круглых скобках список аргументов, которые необходимо передать. Имена переменных в этом списке пишутся через запятую без указания типа. Такие аргументы называются фактическими параметрами.
В результате вызова управление будет передано в вызванную функцию, а затем вернётся к вызывающей функции, когда вызванная функция выполнит все свои инструкции или когда встретится
ключевое слово return. |
|
main() |
r() |
{ r();) |
{putchar(‘r’); |
Информатика 27.03.02 |
54 |
a() |
a(); |
{putchar(‘a’); |
putchar(‘r’); |
d(); |
} |
putchar(‘a’); |
|
} |
|
d() |
|
{putchar(‘d’);} |
|
Заголовок любой функции имеет вид: |
|
тип возвращаемого значения ИМЯ (список параметров)
Список параметров представляет собой перечень переменных, в которые будут попадать значения, передаваемые из вызывающей функции. Имена в этом списке пишутся через запятую, для каждой переменной указывается тип. Параметры, задаваемые в заголовке функции, называются формальными.
Если функция возвращает значение, то её можно вызывать и в качестве оператора, и в качестве операнда. Но, если вызвать её в качестве оператора, то возвращаемое значение будет пропадать
Если функция ничего не возвращает, то её можно вызвать только в качестве оператора. У таких функций в заголовке в качестве типа возвращаемого значения указывается ключевое слово void.
При передаче аргументов между функциями типы, количество и порядок следования фактических аргументов в вызывающей функции должны соответствовать типам, количеству и порядку следования
формальных параметров в вызываемой функции. |
|
|
|||
void main() |
|
|
|
|
|
{int a,b,t; |
|
|
|
|
|
. . . |
|
|
|
|
|
t=power(a,b); |
|
|
|
|
|
. . . |
|
|
|
|
|
} |
|
|
|
|
|
int power(int base, int n) |
|
|
|
||
{int a; |
|
|
|
|
|
for(a=1;n>0;--n) |
|
|
|
|
|
|
a=a*base; |
|
|
|
|
return a; } |
|
|
|
|
|
Никакие |
действия, |
которые |
происходят |
с |
формальными |
параметрами в вызываемой функции, не могут привести к изменению значений фактических параметров. Это связано с тем, что сами переменные не передаются в вызываемую функцию. Компилятор перед передачей управления делает копии фактических параметров, и именно эти копии попадают в вызываемую функцию. Такой способ передачи аргументов называется передачей по значению. При
передаче по значению обратно в |
вызывающую функцию может |
Информатика 27.03.02 |
55 |