Лекція 1

Тема: Мова програмування С.

План

Мова програмування С: історія виникнення, коротка характеристика мови.

Елементи мови програмування С.

Мова С: структура програми.

Інструкції Define, Include.

Стандартні бібліотеки С-функцій.


1. Мова програмування С: історія виникнення, коротка характеристика мови.

C — універсальна, процедурна, імперативна мова програмування, розроблена у 1972 році Денісом Рітчі у Bell Telephone Laboratories для використання з операційною системою UNIX. З тих пір її версії з'явилися для багатьох інших операційних систем, і наразі С є однією з найбільш поширених мов програмування. C також здійснив великий вплив на інші мови програмування, особливо на C++, котра спочатку проектувалася, як розширення для С. Найчастіше використовується для написання системного програмного забезпечення, хоча, досить часто на ній пишуть і прикладне програмне забезпечення.

Філософія

С — мінімалістична мова програмування. Серед її головних цілей: можливість прямолінійної реалізації компіляції, використовуючи відносно простий компілятор, забезпечити низькорівневий доступ до оперативної пам'яті, формувати лише декілька інструкцій машинної мови для кожного елементу мови, і не вимагати обширної динамічної підтримки. У результаті, код С придатний для більшості системного програмного забезпечення, котре традиційно писалося на асемблері.

Незважаючи на її низькорівневі можливості, мова проектувалася для машинно-незалежного програмування. Сумісна зі стандартами та машинно-незалежно написана програма на С може легко компілюватися на великій кількості апаратних платформ та операційних систем з мінімальними змінами. Мова стала доступною для великої кількості платформ, від вбудованих мікроконтроллерів до суперкомп'ютерів.

С використовується, як проміжна мова деякими високорівневими мовами програмування.

Вихідний код С передається компілятору С, котрий видає завершений машинний або двійковий код. Це зроблено задля набуття мобільності (компілятори мови С існують майже для усіх платформ) і уникання необхідності розвитку специфічних для машини генераторів команд.

Критика

Не дивлячись на велику популярність, С часто критикується. Двома основними широкими класами, що підпадають під критику є: бажані дії, котрі дуже важко досягти використовуючи С, і небажані дії, які дуже легко випадково здійснити використовуючи С. Коротко кажучи, ефективне використання С вимагає від програміста більше навиків, досвіду та зусиль, ніж це потрібно для деяких інших мов програмуання.

Серед переваг мови С потрібно відзначити основні:
• універсальність (використовується майже на всіх існуючих ЕОМ);
• компактність та універсальність коду;
• швидкість виконання програм;
• гнучкість мови;
• висока структурованість.


2. Елементи мови програмування С.


Будь-яка мова (українська, російська, англійська, французька та інші) складається з декількох основних елементів - символів, слів, словосполучень і речень. В алгоритмічних мовах програмування існують аналогічні структурні елементи, тільки слова називають лексемами, словосполучення - виразами, а речення - операторами.

Лексеми в свою чергу утворюються із символів, вирази - із лексем і символів, оператори - із символів, лексем і виразів.

Алфавіт мови, або її символи - це основні неподільні знаки, за допомогою яких пишуться всі тексти на мові програмування.

Лексема, або елементарна конструкція - мінімальна одиниця мови, яка має самостійний зміст.

Вираз задає правило обчислення деякого значення.

Оператор задає кінцевий опис деякої дії.


Алфавіт

Алфавіт мови С включає:

великі та малі літери латинської абетки;

арабські цифри;

пробільні символи : пробіл, символи табуляції, символ переходу на наступний рядок тощо;

символи , . ; : ? ' ! | / \ ~ ( ) [ ] { } < > # % ^ & - + * =

Ідентифікатори

Ідентифікатори використовуються для іменування різних об'єктів : змінних, констант, міток, функцій тощо. При записі ідентифікаторів можуть використовуватися великі та малі літери латинської абетки, арабські цифри та символ підкреслення. Ідентифікатор не може починатися з цифри і не може містити пробілів.

Компілятор мови С розглядає літери верхнього та нижнього регістрів як різні символи. Тому можна створювати ідентифікатори, які співпадають орфографічно, але відрізняються регістром літер. Наприклад, кожний з наступних ідентифікаторів унікальний:

Sum sum sUm SUM sUM

Слід також пам'ятати, що ідентифікатори не повинні співпадати з ключовими словами.

Константи

Константами називають сталі величини, тобто такі, які в процесі виконання програми не змінюються. В мові С існує чотири типи констант : цілі, дійсні, рядкові та символьні.

1. Цілі константи можуть бути десятковими, вісімковими або шістнадцятковими.

Десяткова константа - послідовність десяткових цифр (від 0 до 9), яка починається не з нуля якщо це число не нуль. Приклади десяткових констант: 10, 132, 1024.

Вісімкові константи починаються з символу 0, після якого розміщуються вісімкові цифри (від 0 до 7). Наприклад: 023. Запис константи вигляду 08 буде сприйматися компілятором як помилка, так як 8 не є вісімковою цифрою.

Шістнадцяткові константи починаються з символів 0х або 0Х, після яких розміщуються шістнадцяткові цифри (від 0 до F, можна записувати їх у верхньому чи нижньому регістрах). Наприклад: 0ХF123.

Дійсні константи складаються з цілої частини, десяткової крапки, дробової частини, символу експоненти (e чи E) та показника степеня. Дійсні константи мають наступний формат представлення:

[ціла_частина][. дробова_частина][Е[-]степінь]

У записі константи можуть бути опущені ціла чи дробова частини (але не обидві разом), десяткова крапка з дробовою частиною чи символ E (e) з показником степеня (але не разом). Приклади дійсних констант: 2.2, 220е-2, 22.Е-1, .22Е1.

Якщо потрібно сформувати від'ємну цілу або дійсну константу, то перед константою необхідно поставити знак унарного мінуса.

Символьні константи. Символьна константа - це один або декілька символів, які заключені в апострофи. Якщо константа складається з одного символу, вона займає в пам'яті 1 байт (тип char). Двосимвольні константи займають в пам'яті відповідно 2 байти (тип int).

Послідовності символів, які починаються з символу \ (обернений слеш) називаються керуючими або escape-послідовностями (таблиця 1).

Таблиця 1 Escape-послідовності


Спеціальний символ

Шістнадцятковий код

Значення

\a

07

звуковий сигнал

\b

08

повернення на 1 символ

\f

0C

переведення сторінки

\n

0A

перехід на наступний рядок

\r

0D

повернення каретки

\t

09

горизонтальна табуляція

\v

0B

вертикальна табуляція

\\

5C

символ \

\'

27

символ '

\"

22

символ "

\?

3F

символ ?

\0

00

нульовий символ

\0ddd

-

вісімковий код символу

\0xddd

ddd

шістнадцятковий код символу


4. Рядкові константи записуються як послідовності символів, заключених в подвійні лапки.

"Це рядковий літерал!\n"

Для формування рядкових констант, які займають декілька рядків тексту програми використовується символ \ (обернений слеш):

"Довгі рядки можна розбивати на \
частини"

Загальна форма визначення іменованої константи має вигляд:

const тип ім'я = значення ;

Модифікатор const попереджує будь-які присвоювання даному об'єкту, а також інші дії, що можуть вплинути на зміну значення. Наприклад:

const float pi = 3.14l5926;

const maxint = 32767;

char *const str="Hello,P...!"; /* покажчик-константа */

char const *str2= "Hello!"; /* покажчик на константу */

Використання одного лише модифікатору const еквівалентно const int.

Коментарі

Текст на С, що міститься у дужках /* та */ ігноруватиметься компілятором, тобто вважатиметься коментарем до програми. Такі коментарі можуть розміщуватися в будь-якому місці програми.

Коментарі здебільшого використовуються для "документування програм" та під час їх налагодження. В програму бажано вміщувати текст, що хоч якось пояснює її роботу та призначення. Проте неслід надто зловживати коментарями, а використовувати більш розумні форми найменування змінних, констант, функцій тощо. Якщо, наприклад, функція матиме назву add_matrix, очевидно не зовсім раціональним буде включення у програму після її заголовної частини коментар про те, що:

/*функція обчислює cуму матриць */

У цьому випадку ім'я функції пояснює її призначення. У більш сучасних версіях С широко застосовується так званий угорський запис імен, коли ім'я змінної містить в собі інформацію про її призначення і тип.

2.5 Ключові слова

Ключові слова - це зарезервовані ідентифікатори, які мають спеціальне значення для компілятора. Їх використання суворо регламентоване. Імена змінних, констант, міток, типів тощо не можуть співпадати з ключовими словами.

Наводимо перелік ключових слів мови С:

auto

continue

float

interrupt

short

unsigned

asm

default

for

long

signed

void

break

do

far

near

sizeof

volatile

case

double

goto

pascal

static

while

cdecl

else

huge

switch

struct

 

char

enum

if

register

typedef

 

const

extern

int

return

union

 



Мова С: структура програми

Функція main()

Усі програми, написані на мові С, повинні містити в собі хочаб одну функцію.

Функція main() - вхідна точка будь-якої програмної системи, причому немає різниці, де її розміщувати. Але потрібно пам'ятати наступне: якщо вона буде відсутня, завантажувач не зможе зібрати програму, про що буде виведене відповідне попередження. Перший оператор програми повинен розміщуватися саме в цій функції.

Мінімальна програма на мові Сі має вигляд:

main()

{

    return 0;

}

Функція починається з імені. В даному прикладі вона не має параметрів, тому за її ім'ям розташовуються порожні круглі дужки (). Далі обидві фігурні дужки {...} позначають блок або складений оператор, з яким ми працюватимемо, як з єдиним цілим. У Паскалі аналогічний зміст мають операторні дужки begin ... end.

Мінімальна програма має лише один оператор - оператор повернення значення return. Він завершує виконання програми та повертає в нашому випадку деяке ціле значення (ненульове значення свідчить про помилки в програмі, нульове про успішне її завершення). Виконання навіть цієї найпростішої програми, як і решти багатьох, проходить у декілька етапів (рис 1).

код запуску функція main() код завершення

Рис. 1 Етапи виконання програми на мові Сі

4. Директиви препроцесора

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

Директивами називаються інструкції препроцесора. Всі директиви повинні починатися з символу #, перед яким в рядку можуть розташовуватися тільки пробільні символи.

Примітка. Після директив препроцесора крапка з комою не ставиться.

4.1 Директива #include

Синтаксис:

#include "ім'я_файла"

#include <ім'я_файла>

Директива #include використовується для включення копії вказаного файла в те місце програми, де знаходиться ця директива.

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

Якщо ім'я файла розміщене в "кутових" дужках < >, то послідовність пошуку препроцесором заданого файла в каталогах визначається встановленими каталогами включення (include directories).

Якщо ж ім'я файла заключне в лапки, то препроцесор шукає в першу чергу файл у поточній директорії, а потім вже у каталогах включення.

Робота директиви #include зводиться практично до того, що директива #include прибирається, а на її місце заноситься копія вказаного файла.

Текст файла, що включається може містити директиви препроцессора, і директиву #include зокрема. Це означає, що директива #include може бути вкладеною. Допустимий рівень вкладеності директиви #include залежить від конкретної реалізації компілятора.

#include <stdio.h> /* приклад 1*/

#include "defs.h" /* приклад 2*/

В першому прикладі у головний файл включається файл з ім'ям stdio.h. Кутові дужки повідомляють компілятору, що пошук файла необхідно здійснювати в директоріях, вказаних в командному рядку компіляції, а потім в стандартних директоріях.

В другому прикладі в головний файл включається файл з ім'ям defs.h. Подвійні лапки означають, що при пошуку файла спочатку повинна бути переглянута директорія, що містить поточний файл.

В ТС є також можливість задавати ім'я шляху в директиві #include за допомогою іменованої константи. Якщо за словом include слідує ідентифікатор, то препроцесор перевіряє, чи не іменує він константу або макровизначення. Якщо ж за словом include слідує рядок, що заключений в лапки або в кутові дужки, то ТС не буде шукати в ній ім'я константи.

#define myincl "c:\test\my.h"

#include myincl

4.2 Директива #define

Синтаксис:

#define ідентифікатор текст

#define ідентифікатор (список_параметрів) текст

Директива #define заміняє всі входження ідентифікатора у програмі на текст, що слідує в директиві за ідентифікатором. Цей процес називається макропідстановкою. Ідентифікатор замінюється лише в тому випадку, якщо він представляє собою окрему лексему. Наприклад, якщо ідентифікатор є частиною рядка або більш довгого ідентифікатора, він не замінюється. Якщо за ідентифікатором слідує список параметрів, то директива визначає макровизначення з параметрами.

Текст представляє собою набір лексем, таких як ключові слова, константи, ідентифікатори або вирази. Один або більше пробільних символів повинні відділяти текст від ідентифікатора (або заключених в дужки параметрів). Якщо текст не вміщується в рядку, то він може бути продовжений на наступному рядку; для цього слід набрати в кінці рядка символ обернений слеш \ і зразу за ним натиснути клавішу Enter.

Текст може бути опущений. В такому разі всі екземпляри ідентифікатора будуть вилучені з тексту програми. Але сам ідентифікатор розглядається як визначений і при перевірці директива #if дає значення 1.

Список параметрів, якщо він заданий, містить один або більше ідентифікаторів, розділених комами. Ідентифікатори в рядку параметрів повинні відрізнятися один від одного. Їх область дії обмежена макровизначенням. Список параметрів повинен бути заключений в круглі дужки. Імена формальних параметрів у тексті відмічають позиції, в які повинні бути підставлені фактичні аргументи макровиклику. Кожне ім'я формального параметра може з'явитися в тексті довільне число раз.

В макровиклику за ідентифікатором записується в круглих дужках список фактичних аргументів, що відповідають формальним параметрам із списку параметрів. Текст модифікується шляхом заміни кожного формального параметра на відповідний фактичний параметр. Списки фактичних параметрів і формальних параметрів повинні містити одне і те ж число елементів.

Примітка. Не слід плутати підстановку аргументів в макровизначеннях з передачею параметрів у функціях. Підстановка в препроцесорі носить чисто текстовий характер. Ніяких обчислень при перетворенні типу при цьому не виконується.

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

Всередині тексту в директиві #define можуть знаходитися вкладені імена інших макровизначень або констант.

Після того, як виконана макропідстановка, отриманий рядок знову переглядається для пошуку інших імен констант і макровизначень. При повторному перегляді не розглядається ім'я раніше проведеної макропідстановки. Тому директива

#define a a

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

Приклад 1:

#define WIDTH 80

#define LENGTH (WIDTH+10)

В даному прикладі ідентифікатор WIDTH визначається як ціла константа із значенням 80, а ідентифікатор LENGTH - як текст (WIDTH+10). Кожне входження ідентифікатора LENGTH у програму буде замінено на текст (WIDTH+10), який після розширення ідентифікатора WIDTH перетвориться на вираз (80+10). Дужки дозволяють уникнути помилок в операторах, подібних наступному:

val=LENGTH*20;

Після обробки програми препроцесором текст набуде вигляду:

val=(80+10)*20;

Значення, яке буде присвоєно змінній val рівне 1800.

При відсутності дужок значення val буде рівне 280.

val=80+10*20;

Приклад 2:

#define MAX(x,y) ((x)>(y))?(x):(y)

В даному прикладі визначається макровизначення MAX. Кожне входження ідентифікатора MAX в тексті програми буде замінено на вираз ((x)>(y))?(x):(y), в якому замість формальних параметрів x та y підставляються фактичні. Наприклад, макровиклик:

MAX(1,2)

заміниться на вираз ((1)>(2))?(1):(2).


4.3 Директива #undef

Синтаксис:

#undef ідентифікатор

Визначення символічних констант і макросів можуть бути анульовані за допомогою директиви препроцесора #undef. Таким чином, область дії символічної константи або макросу починається з місця їх визначення і закінчується явним їх анулюванням директивою #undef або кінцем файла.

Після анулювання ідентифікатор може бути знову використаний директивою #define.

Приклад:

#define WIDTH 80

/* … */

#undef WIDTH

/* … */

#define WIDTH 20

6