Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

37.ИНФОРМАТИКА Book си

.pdf
Скачиваний:
37
Добавлен:
23.03.2016
Размер:
1.14 Mб
Скачать

Часть 1. Язык Си

11

 

 

Разберем данную программу. Первая строка является комментарием. Вторая строка подключает стандартную библиотеку ввода-вывода stdio.h для работы с функцией printf (см. приложение). Точка с запятой не ставится, т.к. #include — не оператор, а директива препроцессора. С третьей строки начинается главная функция main и тело (блок) функции. Функция printf выводит на экран строку (последовательность символов). ―\n‖ означает перевод строки. Последняя строка закрывает блок функции. Для сравнения далее приведена подобная программа на Паскале.

{Программа на Pascal} begin

{Выводит на экран две строки} writeln('Hello!'); writeln('Pascal')

end.

ВПаскале функция вывода writeln является стандартной функцией, описанной в компиляторе, а не в библиотеке, как printf. После последней функции writeln точка с запятой, в отличие от Си, не ставится.

1.3Базовые типы данных

Вязыке Си определен набор базовых типов данных. Новые типы можно добавлять к этому набору посредством их объявления на основе уже определенных типов данных.

Далее приведена таблица базовых типов. Для целых типов даны

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

пов в Turbo Pascal 5.0.

Тип char может использоваться для хранения символа. Значением объекта типа char является код, соответствующий данному символу. Этот тип интерпретируется как однобайтовое целое. Символьная константа выделяется апострофами ('a').

Размер выделяемой памяти для типа int зависит от реализации языка. По теории должно выделяться машинное слово (равное разрядности машины), но на практике это не так. Тип int, в зависимости от реализации языка, эквивалентен либо short, либо long. В Turbo C 2.0 и 3.1 под int понимается short int.

11

12

 

 

 

Си и Си++

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Идентификатор типа

 

Размер

Название

 

Тип в

полный

сокращенный

 

(байт)

 

Паскале

 

 

 

 

 

 

 

Целые типы

 

 

signed char

char

 

 

1

знаковый символьный

 

shortint

signed int

signed, int

 

2 или 4

знаковый целый

 

?

signed short int

short

 

 

2

знаковый короткий целый

integer

signed short

 

 

 

 

 

 

 

 

signed long int

long

 

 

4

знаковый длинный целый

 

longint

signed long

 

 

 

 

 

 

 

 

 

unsigned char

 

―—

 

1

беззнаковый символьный

 

byte

unsigned int

unsigned

 

2 или 4

беззнаковый целый

 

?

unsigned short int

unsigned short

 

2

беззнаковый короткий

 

word

 

целый

 

 

 

 

 

 

 

 

unsigned long int

unsigned long

 

4

беззнаковый длинный

 

―—

 

целый

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Идентификатор типа

Размер

 

 

Название

 

 

Тип в

(байт)

 

 

 

 

Паскале

 

 

 

 

 

 

 

 

 

Типы с плавающей точкой

 

 

float

 

4

 

одинарной точности

 

single

double

 

8

 

двойной точности

 

double

long double

 

10

 

длинный, двойной точности

 

extended

 

 

 

 

Прочие

 

 

void

 

 

 

пустой

 

 

 

 

enum

 

 

 

перечислимый

 

 

Тип void (пустой) имеет специальное назначение. Подробно он будет рассмотрен позже. Непосредственно объявить переменную типа void нельзя.

Перечислимый тип при написании реальных программ применяется крайне редко, поэтому не будем на нем останавливаться. Скажем лишь, что данный тип схож с перечислимым типом в Паскале, только более гибкий.

ВСи, в отличие от Паскаля, нет логического типа данных

(boolean). Для этих целей можно использовать как целые типы, так

итипы с плавающей точкой. Любое ненулевое значение — истина, а ноль — ложь.

ВЯзыке Си нет самостоятельного строкового типа. Он реали-

зован как массив символов (char), однако есть строковые константы, выделяемые двойными кавычками (например, "abc").

12

Часть 1. Язык Си

13

 

 

1.4 Объявление переменных

Форма объявления переменных имеет вид:

<тип> <имя>[= <значение>] [, <имя>[= <значение>]]…;

Здесь ―тип‖ является идентификатором базового или определенного пользователем типа, а ―имя‖ — идентификатором объявляемой переменной. При объявлении переменной можно ее сразу и определить, для этого после идентификатора переменной ставится знак равенства и описывается (указывается) значение, принимаемое переменной. Можно сразу объявить несколько переменных одного типа, написав их через запятую. Например:

int a;

unsigned int b=60000; double x,y,z;

double N_Avag=6.022045e23;

unsigned char c1=100, c2=’A’, c3=5+5*2;

Объявить переменную можно как в функции, так и вне нее. Если переменная определена вне каких-либо функций, в том числе и main, то такая переменная является глобальной и может быть использована почти в любом месте программы. Также переменная может быть объявлена внутри блока, в том числе внутри тела функции. При таком объявлении переменные являются локальными и могут использоваться только внутри этого блока. Понятно, что использовать еще не описанную переменную нельзя.

В Си переменные должны объявляться до первого исполняемого оператора в блоке, то есть:

{int a; printf("Начало");

. . .

}

1.5 Операции языка Си

Операции в языке Си имеют либо один операнд (унарные опера-

ции), либо два операнда (бинарные операции), либо три (тернарная операция). Унарные операции предшествуют своему операнду и реализуются справа налево. Бинарные операции работают, наоборот,

13

14

Си и Си++

 

 

слева направо. В языке Си имеется одна тернарная операция — операция условия (арифметическое если), обозначаемая ―? :‖.

Большинство операций выполняет преобразование типов для приведения своих операндов к общему типу либо для того, чтобы расширить значения коротких по размеру типов до размера, используемого в машинных операциях. Например, все операнды типов char и short преобразуются к типу int, а при бинарных операциях операнд с менее емким типом, чем второй, автоматически преобразуется к типу другого операнда.

Арифметические операции

Карифметическим операциям относятся:

+сложение

-вычитание

* умножение

/деление

% остаток от деления

Операции сложения, вычитания, умножения и деления действуют почти так же, как и в Паскале. Единственное отличие состоит в том, что при делении целых чисел результат не является действительным числом, как в Паскале, а получается целым числом. Таким образом, при делении двух целых чисел операция деления работает как операция целочисленного деления div в Паскале. Операция % возвращает остаток от деления, аналогично mod в Паскале. Следует заметить, что операция % может применяться только к целочисленным операндам. Операции + и могут быть как унарными, так бинарными. Приоритет операций при их выполнении такой же, как для соответствующих математических действий. Например:

int a=7, b=2, c, d;

 

float a2=7, b2=2, e, f;

c=a/b;

d=a%b;

/* c=3

d=1 */

e=a/b;

f=a2/b2;

/*

e=3

f=3.5 */

a=-a;

/* унарный

минус, a=-7 */

f=2+2*2;

/* f=2+(2*2)=6 */

Особое внимание следует обратить на операцию деления. В примере первый раз делятся целые числа, и соответственно получаем целое число (7/2=3). Второй раз получаем остаток от деления. В третьем примере показана распространенная ошибка применения этой опе-

14

Часть 1. Язык Си

15

 

 

рации: делятся два целых числа (7 на 2) и ожидается получить действительное число (3.5). На самом деле результат будет, как и в первом случае, целым числом (3). Для получения действительного числа необходимо, чтобы хотя бы один операнд был действительным числом, например как в четвертом варианте.

Иногда возникают случаи, когда непосредственно делятся целые константы (к примеру: e=7/2), и ожидается получить, как и в третьем примере, действительное число. В этом случае необходимо сделать хотя бы одну константу действительной — поставить после целой части числа точку.

e=7./2;

/* e=3.5 */

Операции присваивания

Язык Си очень богат на операции присваивания. Наряду с простым присваиванием ―=‖ есть присваивания с действием и операции декремента и инкремента. При выполнении операций присваивания полученное значение преобразуется к значению требуемого типа (тип получающей переменной). Преобразования при присваивании выполняются даже в тех случаях, когда они влекут за собой потерю информации. Например:

int a,b; float p=3.14; unsigned int s=60000; a=p; b=s; /* a=3; b= -5536; */

В отличие от других языков, в Си оператор присваивания сам возвращает значение, равное присваиваемому значению. Эта особенность позволяет осуществлять многократное присваивание:

a=b=s/6;

/* a=b=10000 */

a=100+(b=s/6);

/* b=10000 a=10100 */

Заметим, что значение выражения ―присваивается‖ только идентификатору переменной. Например, нельзя реализовать следующую конструкцию: a+5=10.

В Си имеются дополнительные операции присваивания +=, -=, *=, /=, %= и др. Действия этих операций аналогичны добавлению, уменьшению, умножению и т.д. левой переменной на выражение, стоящее справа, то есть:

a+=5; b*=2; s/=6; /* a=a+5; b=b*2; s=s/6; */

15

16 Си и Си++

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

Язык Си имеет еще две интересные операции: инкремент ++ и декремент --. Эти операции являются унарными. Операция ++ прибавляет единицу к операнду, операция -- вычитает единицу из операнда. Знак этих операций может стоять как перед операндом, так и после. Следовательно, четыре написанных ниже оператора дают одно и то же изменение значения переменной a.

a=a+1; a+=1; ++a; a++;

Разница в расположении знака операции заключается в возвращаемом значении. Если знак стоит до операнда, то возвращается измененное значение переменной, а если после, то возвращается значение переменной до изменения.

int a, b, c, d;

a=b=7;

c= ++a;

d= b++;

/* a=b=8 c=8 d=7 */

d++;

/* d=8 */

 

Операции отношения

Операции отношения используются для сравнения. Полный список операций отношения в языке Си следующий:

<

меньше

>

больше

<=

меньше или равно

>=

больше или равно

==

равно

!=

не равно

Для реализации ―меньше или равно‖ и ―больше или равно‖ нельзя писать =< и =>. Также надо быть внимательными при написании равенства и неравенства. Нельзя писать просто = или <>.

Логические операции

Вязыке Си имеется только три логические операции:

&&И (and),

|| ИЛИ (or),

!НЕ (not).

Операции && и || являются бинарными, а ! — унарной. Заметим, что в отличие от Паскаля логическое И (&&) имеет больший приоритет, чем ИЛИ (||), то есть следующие логические выражения эквивалентны:

16

 

 

 

Часть 1. Язык Си

17

 

 

 

 

 

 

a>0

||

b>0

&& a!=0 ||

b==0

 

a>0

||

(b>0

&& a!=0) ||

b==0

 

Поразрядные (побитовые) операции

Поразрядные (побитовые) операции можно производить с любыми целочисленными переменными и константами. Нельзя использовать эти операции с переменными вещественного типа (float, double и long double). Результатом побитовой операции будет целочисленное значение.

Поразрядными операциями являются:

& поразрядное И (and) | поразрядное ИЛИ (or)

^поразрядное ИСКЛЮЧАЮЩЕЕ ИЛИ (xor)

~ обратный код (поразрядное отрицание) (not) << сдвиг влево >> сдвиг вправо

Первые четыре операции аналогичны соответствующим логическим операциям.

x

y

x&y

x|y

x^y

~x

0

0

0

0

0

1

 

 

 

 

 

 

0

1

0

1

1

1

 

 

 

 

 

 

1

0

0

1

1

0

 

 

 

 

 

 

1

1

1

1

0

0

Единственная разница состоит в том, что эти операции производят соответствующее действие над каждым битом.

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

unsigned int a=0x0F07; /*или 0000 1111 0000 0111*/ unsigned int b=0xF10F; /*или 1111 0001 0000 1111*/ unsigned int c;

c=a&b;

/* 0107 или 0000 0001 0000 0111 */

c=a|b;

/*

FF0F или 1111 1111 0000 1111

*/

c=a^b;

/*

FE08 или 1111 1110 0000 1000

*/

c=~a;

/*

F0F8

или

1111 0000 1111 1000

*/

c=a<<4;

/*

F070

или

1111 0000 0111 0000

*/

17

18

Си и Си++

 

 

c=a>>4;

/* 00F0 или 0000 0000 1111 0000 */

Сначала беззнаковым целым числам размером в два байта присваиваем значения, записанные в виде шестнадцатеричных констант.

Шестнадцатеричными константами считается последовательность цифр и латинских букв от A до F (можно писать и строчными буквами от a до f), перед которыми стоит "0x" или "0X".

Операции сдвига смещают все биты числа на заданное положительное целое число бит. Освобождающиеся биты заполняются нулями, например:

unsigned int x=0x00AA, y=0x5500, z;

z=(x<<8) | (y>>8); /*z=0xAA00 | 0x0055=0xAA55*/ z<<=4; z>>=8; z<<=4; /* z=0x0A50 */

В последней строке примера показаны операции присваивания со сдвигами вправо и влево. Так же можно писать и присваивания с поразрядными бинарными операциями: &=, |=, ^=. Заметим, что результат последней строки примера можно получить, написав:

z&=0x0FF0;

Иногда бывают случаи, когда необходимо получить или присвоить только несколько бит числа. Это можно реализовать следующим образом:

unsigned int a,b;

. . .

a=0x574A;

b=(a&0x0FF0)>>4; /*Получаем число с 5 по 12 бит */ if (a&0x0FF0).../* Если число с 5 по 12 бит > 0 */

. . .

b=99;

a=a&0xF00F | (b<<4); /* Поместить число b в 5-12 бит. Можно и так: a&=0xF00F; a|=(b<<4); */

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

a

574A

0101 0111 0100 0111

22346

 

 

 

 

a&0x0FF0

0740

0000 0111 0100 0000

1856

(a&0x0FF0)>>4

0074

0000 0000 0111 0100

116

b

0063

0000 0000 0110 0011

99

 

 

 

 

b<<4

0630

0000 0110 0011 0000

1584

 

 

 

 

18

 

Часть 1. Язык Си

19

 

 

 

 

 

 

 

 

 

 

 

a&0xF00F

500A

0101 0000 0000 0111

20490

 

(a&0xF00F) | (b<<4)

563A

0101 0110 0011 0111

22074

Обратите внимание на то, что число b задано не в шестнадцатеричном виде, а в десятичном. Это сделано для демонстрации того, что неважно, в каком виде задавать значения переменных.

Другие операции

В языке Си круглые скобки также рассматриваются как операция. Причем эта операция имеет наивысший приоритет. Иногда полезно поставить лишние скобки для наглядности выражения или в случае, если вы сомневаетесь в расстановке приоритетов в вашем выражении. Лучше поставить лишние скобки, чем не поставить их там, где надо.

Операция ―запятая‖ имеет самый низкий приоритет. Операция ―запятая‖ выполняется слева направо, и ее значением является значение правого оператора.

int a=7,b;

b=(a++,a*=2+a);/* I. a=8 II. a=a*(2+a)=80 b=a=80*/ b++ , --a; /* b=81 a=79 */

Операция ―условие‖ — единственная операция языка Си, имеющая три операнда. Она имеет следующий вид:

<выр1> ? <выр2> : <выр3>

Вычисляется выражение ―выр1‖. Если его значение верно (не равно нулю), то вычисляется выражение ―выр2‖, значение которого будет результатом данной операции. Если значение ―выр1‖ ложно (равно нулю), то результатом этой операции будет ―выр3‖. Например:

float a=-7,

b=3, max, abs;

abs=(a>=0) ? a : -a;

/* модуль a abs=7 */

max=(a>b) ?

a : b; /*

максимум из a и b max=3 */

Операция sizeof (<тип или выражение>) возвращает размер типа или размер типа значения выражения, то есть:

int a,b;

 

 

 

 

 

a=sizeof(char);

b=sizeof(int);

/*

a=1

b=2 */

a=sizeof(7/2);

b=sizeof(a);

/*

c=2

d=2 */

a=sizeof(double);

b=sizeof(float);/*

a=8

b=4

*/

a=sizeof(7./2.);

b=sizeof(a);

/*

c=8

d=2

*/

19

20

Си и Си++

 

 

Ряд операций не был рассмотрен здесь. Это операции, связанные с указателями и структурами. Они будут рассмотрены в соответствующих разделах. Все операции языка Си, расположенные по приоритету при выполнении, приведены в приложении. Заметим, что некоторые операции имеют двойной смысл, в зависимости от местоположения в выражении.

Преобразование типов

Преобразование типов производится либо неявно (например, при присваивании), либо явно (путем выполнения операции приведения типа). Преобразования при присваивании осуществляется даже в тех случаях, когда они влекут за собой потерю информации. Явное преобразование типа может быть выполнено посредством операции приведения типа. Для вызова этой операции необходимо перед преобразуемым значением написать желаемый тип. Например, для преобразования значения переменной a типа int в значение типа double надо написать (double)a. Например:

int a=7,

b=2, d;

double c;

c=a/b;

/* c=3 ,

т.к. a и b типа int */

c=(double)a/b;

/*

c=3.5 */

d=(double)a/b;

/*

d=3 */

1.6 Операторы

Условный оператор if

Форма этого оператора следующая:

if (<условие>) <оператор> [ else <оператор> ]

Если значение условия ―истина‖, то выполняется оператор (им может быть блок), следующий за условием. Если же условие принимает значение ―ложь‖, то выполняется оператор, следующий за ключевым словом else. В записи оператора if вторая часть (т.е. оператор else) может отсутствовать. В операторе if лишь проверяется, является ли значение этого выражения ненулевым (истинным) или нулевым (ложным). Оператор if в Си отличается от аналогичного оператора в Паскале тем, что условие заключается в круглые скобки и после не ставится лексема then. Так, например, для нахождения максимума из a и b можно написать:

20