Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Text_lektsy_Si-dlya_studentov.pdf
Скачиваний:
6
Добавлен:
08.05.2015
Размер:
1.22 Mб
Скачать

В Си нет.Замена – целые. 0 false,

(НЕ)0 true

2.3 Указатели

Указатели (ссылки) – это переменные, показывающие место или адрес памяти, где расположены другие объекты (переменные, функции и т.п.). Т.к. указатель содержит адрес некоторого объекта, то через него можно обращаться к этому объекту.

У такого выражения есть АДРЕС, ТИП и, разумеется, ЗНАЧЕНИЕ. Но у него нет ИМЕНИ И нет ОБЛАСТИ ВИДИМОСТИ.

 

E – имя

 

Программный уровень

 

переменная

 

 

 

Значение

 

 

 

 

 

 

 

 

 

участок памяти

Содержание

 

 

Машинный уровень

Формат: описания

переменной указателя

 

&E – адрес

<тип> *<имя>

 

[,*<имя>]...;

Объекты, состоящие из знака* и адреса необходимо объявлять!

Объявление вида: char *d; говорит о том, что значение, записанное по адресу d, имеет тип char.

Пример:

int *kol, *num; Признаком указателя служит *. double *lenght;

Операции над указателями: над указателями определены две унарные операции:& *

Унарная операция & возвращает адрес объекта в явном виде, поэтому опера-

тор:

y = &x;

присваивает адрес x переменной y. Операцию & нельзя применять к константам и выражениям. Операция применима только к объектам, имеющим имя и размещенным в памяти.

Унарная операция * воспринимает свой операнд как адрес некоторого объекта и использует этот адрес для выборки содержимого. Поэтому, оператор:

z = *y;

присваивает z значение переменной, записанной по адресу y.

int Объявляет переменную a типа «указатель на int», то есть со-

*a; держащую адрес некоторого целого значения.

11

&x

Возвращает адрес переменной a

 

 

 

 

*p

Возвращает "переменную" по адресу, находящемуся в перемен-

 

ной p.

 

 

 

 

 

 

Пример: int x, y, *px;

 

 

px=&x;

 

 

 

y=*px;

 

 

 

Это эквивалентно

y = x;

 

Указатели могут встречаться в выражениях. Если y – указатель на целое ( int

*y;

), то *y может появляться там же, где и любая другая переменная, не являющаяся указателем.

Пример:

*y = 7; //заносим 7 в ячейку памяти по адресу y *x = *x*5; //увеличиваем значение по адресу x в 5 раз

(*z)++; //добавляем 1 к содержимому ячейки памяти с адресом z, круглые скобки обязательны

12

Глава 3 МАССИВЫ И СТРУКТУРЫ

К совокупностям данным относятся массивы, структуры и файлы

3.1Массивы

МАССИВ – это множество переменных одного типа, характеризующихся одним именем. Как следует из их определения, массивы очень удобны, если приходится иметь дело с большими наборами однотипных данных.

описание массива Формат: Синтаксис описания массива

<тип> <имя_переменной> [количество_элементов_массива]

[[количество_элементов_массива][количество_элементов_массива]]

Обращение (ссылка) к элементу массива

Отдельные элементы массива собственного имени не имеют. Доступ к ним можно

получить, используя оператор [ ].

 

Формат:

 

<имя_массива> [<индекс_элемента>][[<индекс_элемента>]]

Данный оператор возвращает элемент массива, соответствующий индексу. Обратите внимание: индексация в Си начинается с 0, то есть правильными значениями индекса будут все значения в интервале

от 0 до <количество_элементов_массива>–1.

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

Пример: page[5] line[i] screen[j][k] matr[i–1][j+i–1]

Массивы можно, как и остальные переменные, инициализировать сразу при их объявлении. При этом элементы массива перечисляются через запятую, и все вместе заклю-

чаются в фигурные скобки. Пример: int a[ 6 ] = { 1, 2, 3, 4, 5, 6 };

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

int a[ ] = { 1, 2, 3}).

Теперь вопрос: что напечатает такая программа? #include <stdio.h>

void

main

(void)

{ int

i, a[10];

 

a[0] = 5;

 

printf ( "%d\n",

*a ); }

На первый взгляд кажется, что она даже не будет компилироваться – ведь мы пытаемся взять значение по переменной, не являющейся адресом. Но, вопреки ожиданиям, она запустится и напечатает число 5.

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

13

3.2Строки

Язык СИ не поддерживает отдельный строковый тип данных, но он позволяет опре-

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

В первом используется массив символов, а во втором – указатель на первый символ массива. Объявление char а[10] указывает компилятору на необходимость резервирования места для максимум на 10 символов. Константа а содержит адрес ячейки памяти, в которой помещено значение первого объекта типа char.

Второй способ определения строки – это использование указателя на символ. Объявление char *b; задает переменную b, которая может содержать адрес некоторого объекта. Однако в данном случае компилятор не резервирует место для хранения символов и не инициализирует переменную b конкретным значением. Когда компилятор встречает инструкцию вида b=”Москва”; , он производит следующие действия. Во-первых, как и в предыдущем случае, он создает в каком-либо месте объектного модуля строку Москва, за которой следует нулевой символ. Во-вторых, он присваивает значение начального адреса этой строки (адрес символа М) переменной b.

Константа (литерал) типа строка (string): " <текст> "

3.3Структуры

СТРУКТУРА (запись) – совокупность разнотипных элементов. Элементы структуры (вернее, поля структуры), в отличие от элементов массива, не имеют индекса, но имеют собственное ИМЯ. Элементом структуры может быть массив любого типа.

Пример: Представление текущей даты:

день месяца;

название месяца;

год;

Формат

структура

 

struct [<тип(имя)_структуры>] {

<список_описаний_элементов>

} [<список_объектов>];

 

<список_описаний_элементов> :=

 

 

<имя_типа> <имя_переменной> [, имя_переменной [,...]];

 

 

<имя_типа> <имя_переменной> [, имя_переменной [,...]];

 

 

Пример:

 

<имя_типа> <имя_переменной> [, имя_переменной [,...]];

 

 

1. struct

data {

/* Дата */

int day_nom;

/* День месяца */

char month_name[4];

/* Название месяца */

int year;

/* Год */

};

 

 

Таким образом, мы объявили новый тип данных – Data, представляющий из себя структуру. Если мы хотим объявить переменную day типа Data, то это следует делать так:

struct Data day;

Доступ к полям структуры осуществляется с помощью оператора точка:

14

day.day_nom = 5;

day. month_name = "март"; day.year = 2002;

Разрешается вкладывать структуры одна в другую.

Пример:

 

 

 

 

1.

 

 

struct

star

{

long nom_GC;//Номер по каталогу GC

floatmv;

//Блеск (звездная величина)

char spectr[5]; //Спектральный класс

struct fist {

 

 

double

alfa; //Прямое восхождение

double

delta; //Склонение

 

} koord;

 

 

 

 

 

/*переменная koord представлена составным элементом (вложенной структурой) ти-

па fist*/

 

 

 

 

 

struct

{

 

 

 

 

double

alfa;

 

//Собств. движение по alfa

double

delta; // ------

-------

по delta

} move;

 

 

 

 

 

char rem[15];

}; //Особенности(прим)

Допустимы массивы структур.

Пример:

 

 

 

 

struct

year {

/* Сведения о погоде за год */

struct

 

{

 

 

double max, min, mid;

 

}temperature; struct {

double max, min, mid;

}humidity; struct {

double max, min, mid;

}pressure;

int number_of_observations;

}weather[12];

15

Глава 4 ОПЕРАЦИИ И ВЫРАЖЕНИЯ

Выражение – это представление в тексте программы значения.

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

Назначение любого выражения – формирование некоторого значения. В зависимости от типа формируемых значений определяются типы выражений.

Если значениями выражений являются целые или вещественные числа, то говорят об арифметических выражениях.

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

Выражения отношения и логические выражения традиционно должны давать одно значение: истина или ложь. В СИ истина – всегда ненулевое значение, 0 – ложь.

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

Операндами логических выражений являются выражения отношения.

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

Р

Операции

Ассоциатив-

анг

 

ность

1

(); [];; .

2

!; ~; +; –; ++; ––; &; *; (тип); sizeof

3

*; /; % (мультипликативные бинарные)

4

+; – (аддитивные бинарные)

5

<<; >> (поразрядного сдвига)

6

<; <=; >=; > (отношения)

7

==; != (отношения)

8

& (поразрядная конъюнкция “И”)

9

^ (поразрядное исключающее “ИЛИ”)

10

| (поразрядная дизъюнкция “ИЛИ”)

11

&& (конъюнкция “И”)

12

|| (дизъюнкция “ИЛИ”)

13

?: (условная операция)

14

=; *=; /=; %=; +=; –=; &=; ^=; |=; <<=; >>=

15

, (операция запятая)

За исключением операций “[]”, “()” и “?:” все знаки операций распознаются компилятором как отдельные лексемы. В зависимости от контекста одна и та же лексема может обозначать разные операции, т.е. один и тот же знак операции может употребляться в различных выражениях и по разному интерпретироваться в зависимости от контекста.

Например, бинарная операция & – это поразрядная конъюнкция, а унарная & – это операция получения адреса.

16

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

Операции ранга 1 имеют наивысший приоритет.

Операции одного ранга имеют одинаковый приоритет, и если их в выражении несколько, то они выполняются в соответствие с правилом ассоциативности либо слева направо (), либо справа налево (). Если один и тот же знак операции приведен в таблице дважды (например знак *), то первое появление (с меньшим по номеру, т.е. старшим по приоритету, рангом) соответствует унарной операции, а второе – бинарной.

4.1 Унарные (одноместные) операции

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

&– операция получения адреса операнда. Нельзя &(x+1).

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

– унарный минус, изменяет знак арифметического операнда.

+– унарный плюс, введен для симметрии с унарным минусом.

~ – поразрядное инвертирование внутреннего двоичного кода целочисленного аргумента – побитовое отрицание.

Пример:

Unsigned char a:

A=201: (=c9 (16) = 11001001(2)) ~A=54: (= 36 (16) = 00110110(2))

! – логическое отрицание (НЕ) значения операнда. Применяется к стандартным операндам. Целочисленный результат 0 (если операнд не нулевой, т.е. истинный) или 1 (если операнд нулевой, т.е. ложный). Напомним, что в качестве логических значений в языке используются целые числа: 0 – ложь и не нуль, т.е. (!0) – истина. Отрицание любого ненулевого числа будет 0, а отрицанием 0 будет 1. Таким образом: !1 равно 0; !2 равно

0; !(–5) равно 0; !0 равно 1;

++ – увеличение на единицу (инкремент или автоувеличение); имеет две формы: ++<имя>префиксная операция – увеличение значения операнда на 1 до его исполь-

зования. Ассоциативность справа в соответствие со стандартом.

<имя>++постфиксная операция – увеличение значения операнда на 1 после его использования. Ассоциативность слева в соответствие со стандартом.

-выражение ++m увеличивает на 1 значение m, и это полученное значение используется как значение выражения ++m (префиксная форма).

-выражение – – k уменьшает на 1 значение k, и это полученное значение используется как значение выражения – –k (префиксная форма).

-выражение i++ (постфиксная форма) уменьшает на 1 значение i, однако значением выражения i++ будет предыдущее значение i (до его увеличения).

-выражение j – – (постфиксная форма) уменьшает на 1 значение j, однако значением выражения j – – будет предыдущее значение j (до его уменьшения.

Например

17

int arg=4, rez;

// rez=8, arg=5

rez= arg ++*2;

rez=++ arg *2;

// arg=6, rez=12

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

X+++b или z – – –d.

В этих случаях трактовка однозначно и полностью определяется рангами операций (бинарные аддитивные + имеют ранг 4;унарные ++ и –– имеют ранг 2).Таким образом:

x+++b эквивалентно (x++)+b z– – –d эквивалентно (z– –)–d.

Операнд для операции ++ (и для операции – – ) не может быть константой либо произвольным выражением. Записи ++5 или 84++ будут неверными. ++(j+k) также неверная запись. Операндами унарных операций ++ и – – должны быть всегда модифицируемые выражения (L– value, left value, l – значение, леводопустимое выражение).

Термины «леводопустимое выражение» и «l–значение» происходят от объяснения действия операции присваивания E=D, в которой операнд Е слева от знака операции присваивания может быть только модифицируемым l – значением. Примером модифицируемого l – значения служит имя переменной, которой выделена память. L – значение

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

Sizeof – операция вычисления размера (в байтах) для объекта того типа, который имеет операнд. Разрешается два формата операции:

sizeof <выражение>

sizeof (тип).

 

 

Пример:

 

 

int a, b[100], *x;

 

sizeof (20.0)

8

байтов

sizeof (a)

2 байта

sizeof (b)

200 байтов

sizeof (*x)

2

байта

sizeof (int)

2

байта

sizeof (date)

12 байтов

4.2 Бинарные (двуместные) операции

Делятся на следующие группы:

аддитивные;

мультипликативные;

сдвигов;

поразрядные;

операции отношений;

логические;

присваивания;

выбора компонента структурированного объекта;

операция “запятая”;

18

скобки в качестве операций;

Аддитивные операции (операнды: арифметические выражения или указатели). + – бинарный плюс – сложение арифметических операндов или сложение указа-

теля с целочисленным операндом.

– бинарный минус – вычитание арифметических операндов или вычитание указателей.

Мультипликативные операции.

* – умножение операндов арифметического типа.

/– деление операндов арифметического типа.

При целочисленных операндах абсолютное значение результата округляется до целого.

Например: 20/3 равно 6,

–20/3 равно –6, (–20)/3 равно –6, 20/(–3) равно –6.

% – получение остатка от деления целочисленных операндов (деление по модулю). При неотрицательных операндах остаток положительный. В противном случае остаток определяется реализацией. В компиляторе Turbo С у результата знак делимого:

13%4 равняется 1, (–13)%4 равняется –1;

13%(–4) равно +1, (–13)%(–4) равняется –1.

При ненулевом делителе для целочисленных операндов всегда выполняется соотношение (a/b)*b+a%b равно а.

Чтобы результат выполнения арифметической операции был вещественным, необходимо, чтобы вещественным был хотя бы один из операндов. Например, значением выражения 5.0/2 будет 2.5, что соответствует смыслу обычного деления.

Операции сдвига (определены только для целочисленных операндов).

Формат

<операнд_левый> <операция_сдвига><операнд_правый> << – сдвиг влево битового представления значения левого целочисленного операн-

да на количество разрядов, равное значению правого целочисленного операнда.

>> – сдвиг вправо битового представления значения левого целочисленного операнда на количество разрядов, равное значению правого целочисленного операнда.

E1>>E2, Е2 – число битов сдвига.

Результат не определен, если: Е2<0; значение Е2 >= размера Е1 в битах. E1>>E2 эквивалентно Е1 / (2E2)

E1<<E2 эквивалентно Е1 * 2E2

Пример:

 

 

 

4<<2

равняется 16.

двоичный код для 4

равен 100,

5>>1

равняется 2.

двоичный код для 5

– это 101.

При сдвиге влево на две позиции код 100 становится равным 10000 (десятичное значение равно 16). Остальные результаты операций сдвига могут быть прослежены аналогично.

19

Обратите внимание, что сдвиг влево на n позиций эквивалентен умножению значения на 2, а сдвиг кода вправо уменьшает соответствующее значение в 2 раз с отбрасыванием дробной части результата (Поэтому 5>>1 равно 2).

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

& – поразрядная конъюнкция (И) битовых представлений значений целочисленных операндов.

| – поразрядная дизъюнкция (ИЛИ) битовых представлений значений целочисленных операндов.

^ – поразрядное исключающее ИЛИ битовых представлений целочисленных операндов.

АВ !А А&B A|B

F

F

T

F

F

F

T

T

F

T

T

F

F

F

T

T

T

F

T

T

Пример: Результат выполнения операций сдвига и поразрядных операций: 6&5 равняется 4.

6|5 равняется 7. 6^5 равняется 3.

Напоминаем, что двоичный код для 5 – это 101, для 6 – 110 и т.д.

Операции отношения (сравнения).

Операнды: арифметические выражения и указатели. Указатели можно сравнивать только с целым. Результат целочисленный: 0 (ложь) или 1 ( истина).

<меньше, чем.

>больше, чем.

<= меньше или равно. >= больше или равно.

==равно.

!=

не равно.

Последние две операции (операции сравнения на равенство) имеют более низкий приоритет по сравнению с остальными операциями отношений. Таким образом, выражение

( x<b = = a<x )

есть 1, тогда и только тогда, когда значение х находится в интервале от a до b и а<b (Вначале вычисляются x<b и x>a, а к результатам применяется операция сравнения на равенство ==).

Пример:

a+b<b+c = = a+c<a+b

x1<x2 = = x3<x1 есть 1 тогда и только тогда, когда х1 в интервале [x3;x2] и

x3<x2.

Логические бинарные операции.

&& – конъюнкция (И) арифметических операндов или отношений. Целочисленный результат 0 (ложь) или 1 (истина). Если 1-й операнд равен 0, то 2-й не вычисляется.

20

|| – дизъюнкция (ИЛИ) арифметических операндов или отношений. Целочисленный результат 0 (ложь) или 1 (истина). Если 1-й операнд равен 1, то 2-й не вычисляется.

Пример:

 

3<5

равен 1.

3>5.1

равен 0.

3==5

равен 0.

3!=5равен 1.

3!=5 || 3==5 равен 1.

3+4>5 &&3+5>4 && 4+5>3 равен 1.

Задача 1. Написать условие попадания точки (x, y) в область. y

1

1x

1.Точка в верхней полуплоскости: y 0.

2.Точка в правой полуплоскости: x 0.

3.Точка выше прямой: y 1-x

Все три условия должны выполняться одновременно:

y 0 && x 0 && y 1-x – с границами

Задача 2. Написать условие не попадания точки (x, y) в область. y

1

1x

1.Попадание внутрь круга: x2 +y2 1.

2.Точка в I и III квадрантах: xy 0.

Оба условия должны выполняться одновременно:

!( x*x+y*y<1 && x*y > 0 ) – без границ

Задача 3 Деление нацело, кратность: m%n == 0.

21

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]