Директиви # ifdef і # ifndef .

Nbsp;   КОНСПЕКТ ЛЕКЦІЙ     "Програмування мовою Сі"   Константи. Типи констант, правила опису.   Константа- це число, символ чи рядок символів. Константи використовуються в програмі як незмінні величини. У мові Сі розрізняють чотири типи констант: цілі константи, константи дійсного типу, константи-символи і рядкові літерали. Цілі константи. Ціла константа - це десяткове, восьмеричне чи шістнаддятиричне число, що представляє цілу величину. Десяткова константа має наступний формат представлення: <digits>, де < digits> - це одна чи більше десяткових цифр від 0 до 9. Восьмерична константа має наступний формат представлення: 0<odigits>, де <odigits> - це одна чи більше восьмеричних цифр від 0 до 7. Запис ведучого нуля необхідна. Шістнадцятирична константа має один з наступних форматів представлення: Ox<hdigits> OX<hdigits>, де <hdigits> одна чи більше шістнадцятиричних цифр. Шістнадцятирична цифра може бути цифрою від 0 до 9 чи літерою (великою чи малою) від А до F. У представленні константи допускається «суміш» великих і малих букв. Запис ведучого нуля і наступного за ним символу х чи X необхідна. Пробільні символи не допускаються між цифрами цілої константи. Приклади цілих констант: 132; 32179 - десяткові константи; 0204; 076663 - восьмеричні константи; 0x84; 0x7d3 - шістнадцятиричні константи. Цілі константи завжди специфікують позитивні величини. Якщо потрібні негативні величини, то необхідно сформувати константний вираз зі знака мінус і наступної за ним константи. Знак мінус розглядається як арифметична операція. Кожна ціла константа специфікується типом, що визначає її представлення в пам'яті і область значень. Десяткові константи можуть бути типу int чи long. Восьмеричні і шістнадцятиричні константи в залежності від розміру можуть бути типу int, unsigned int, long чи unsigned long. Восьмеричні і шістнадцатиричні константи не містять «знакових» розширень, коли вони перетворюються до більш довгих типів. Дійсні константи. Константа дійсного типу - це дійсне десяткове позитивне число. Величина дійсного числа включає цілу, дробову частині і експоненту. Константи дійсного типу мають наступний формат представлення: [<digits>] [. <digits>l [Е [-] <digits>], де <digits> - одна чи більш десяткових цифр (від 0 до 9), а Е чи е - символ експоненти. Ціла чи дробова частини константи можуть бути опущені, але не обидві відразу. Десяткова крапка може бути опущена тільки тоді, коли задана експонента. Експонента складається із символу експоненти, за яким слідує цілочисельна величина експоненти, можливо негативна. Пробільні символи не можуть розділяти цифри або символи константи. Константи дійсного типу завжди специфікують позитивні величини. Якщо необхідні негативні величини, то потрібно сформувати константний вираз зі знака мінус і наступної за ним константи. Знак мінус розглядається як арифметична операція. Приклади констант дійсного типу і константних виразів: 15.75 1.575Е1 1575е-2 Ціла частина дійсної константи може бути опущена, наприклад: .75 .0075е2 Усі константи дійсного типу мають тип double чи float. Константа-символ. Символьна константа - представляється символом, укладеним в апострофи. Керуюча послідовність розглядається як одиночний символ, припустимо її використовувати в символьних константах. Значенням символьної константи є числовий код символу. Приклади: ' '-пробіл, ‘Q' - буква Q, ‘\п' - символ нового рядка, ‘\\’ - зворотна дробова риса, ‘\v’ - вертикальна табуляція. Символьні константи мають тип int і при перетворенні типів доповнюються знаком. Константа-символ має наступну форму представлення: ‘<сhаr>', де <char> може бути будь-як символом з безлічі представимьіх символів, включаючи будь-який ESC - символ, крім одиночних лапок ('), похилу рису вліво (\) і символ нового рядка. Строкові літерали. Строковий літерал- це послідовність літер, цифр і символів, укладена в подвійних лапках. Строковий літерал розглядається як масив символів, кожен елемент якого представляє окремий символ. Строковий літерал має наступну форму представлення: "<characters>", де <characters> - це нуль чи більше символів з безлічі представимьіх символів, крім подвійних лапок ("), похилу рису вліво (\) і символ нового рядка. Щоб використовувати символ нового рядка в строковому літералі, необхідно надрукувати похилу рису вліво, а потім символ нового рядка. Символи строкового літерала зберігаються в області оперативної пам'яті. У кінець кожного строкового літерала компілятором додається нульовий символ, що представляється керуючою послідовністю \0. Строковий літерал має тип char[]. Це означає, що рядок розглядається як масив символів, а число елементів масиву дорівнює числу символів у рядку плюс 1, тому що нульовий символ (символ кінця рядка) також є елементом масиву. Усі строкові літерали розглядаються компілятором як різні об'єкти. Строкові літерали можуть розташовуватися на декількох рядках. Такі літерали формуються на основі використання зворотної дробової риси і клавіші введення. Зворотна риса із символом нового рядка ігнорується компілятором, що приводить до того, що наступна рядок є продовженням попереднього. Наприклад: "рядок невизначеної \n довжини" цілком ідентична литералу "рядок невизначеної довжини". Для зчеплення строкових літералів можна використовувати символ (чи символи) пробілу. Якщо в програмі зустрічаються два чи більше строкових літерала, розділених тільки пробілами, то вони будуть розглядатися як один символьний рядок. Цей принцип можна використовувати для формування строкових літералів, що займають більше одного рядка.   Використання коментарів у тексті програми.   Коментар - це набір символів, що ігноруються компілятором. Коментар має наступну форму представлення:   /* <characters> */ де <characters> - може бути будь-якою комбінацією символів з безлічі представимих символів, включаючи символи нового рядка. На цей набір символів, однак, накладаються наступні обмеження. Усередині набору символів, що представляє коментар не може бути спеціальних символів визначаючих початок і кінець коментарів, відповідно (/* і */). Коментарі можуть замінити як один рядок, так і декілька. Наприклад: /* коментарі до програми */ чи /* коментарі можна записати в наступному виді, однак треба бути обережним, щоб усередині послідовності, що ігнорується компілятором, не потрапилися оператори програми, що також будуть ігноруватися */ Це означає, що коментарі можуть займати більш одного рядка, але не можуть бути вкладеними. Неправильне визначення коментарів: /* коментарі до алгоритму/* рішення крайової задачі */*/ чи /* коментарі до алгоритму рішення*/ крайової задачі*/ Коментарі допускаються скрізь, де дозволені пробільні символи. Компілятор ігнорує символи коментарю, зокрема, у коментарях допускається запис ключових слів, і це не приведе до помилки. Тому що компілятор розглядає коментар як символ пробілу, то коментарі не можуть з'являтися усередині лексем. Оператор while.   Оператор циклу while називається циклом із передумовою і має наступний формат: while (вираз) тіло; де виразом може бути будь-яким умовним виразом мови Сі; тіло - будь-який оператор, у тому числі порожній чи складовий. Якщо вираз істинний, то оператор (тіло) виконується тільки раз, а потім вираз перевіряється знову. Ця послідовність дій повторюється до тих пір, поки вираз не стане помилковим. Кожна така послідовність зветься ітерацією. Розглянемо схему виконання оператора більш докладно:   1. Обчислюється вираз.   2. Якщо вираз помилковий, то виконання оператора while закінчується і виконується наступний оператор. Якщо вираз істинний, то виконується тіло оператора while. 3. Процес повторюється з пункту 1. Приклад: int n = 5; while (n < 7)   { printf("n = %d\n", n); n + +; printf("Tenepь n = %d\n'\ n);   } Оператор циклу виду for (вираз 1; вираз 2; вираз 3) тіло; може бути замінений оператором while у такий спосіб: вираз 1; while (вираз 2) { тіло вираз 3; } Так само як і при виконанні оператора for, в операторі while спочатку відбувається перевірка умови. Тому оператор while зручно використовувати в ситуаціях, коли тіло оператора не завжди потрібно виконувати.   Виконання оператора можна перервати використавши оператор if або break.   Усередині операторів for і while можна використовувати локальні змінні, котрі повинні бути об'явлені з визначенням відповідних типів.   Оператор do while.   Оператор циклу do while називається оператором циклу з постумовою і використовується в тих випадках, коли необхідно виконати тіло циклу хоча б один раз. Формат оператора має наступний вид:   do   тіло while (вираз); Схема виконання оператора do while: 1. Виконується тіло циклу (яке може бути складеним оператором). 2. Обчислюється вираз. 3. Якщо вираз помилковий, то виконання оператора do while закінчується і виконується наступний оператор. Якщо вираз істинний, то виконання оператора продовжується з пункту 1.   Щоб перервати виконання циклу до того, як умова стане помилковою, можна використовувати оператор break.   Оператори while і do while можуть бути вкладеними.   Приклад:   int i,j,k;   ….   i=0;j=0; k=0; do {i++; j--; while (a[k] < i) k++ } while (i<30 && j<-30); Оператор for,   Оператор for - це найбільш загальний спосіб організації циклу. Він має наступний формат:   for (вираз 1; вираз 2; вираз 3)   тіло   де - вираз 1 звичайне використовується для встановлення початкового значення змінних, керуючих циклом;   вираз 2 - це вираз, що визначає умову, при якій тіло циклу буде виконуватися;   вираз 3 визначає зміну змінних, керуючих циклом після кожного виконання тіла циклу. Схема виконання оператора for: 1. Обчислюється вираз 1. 2. Обчислюється вираз 2. 3. Якщо значення виразу 2 відмінно від нуля (істина), виконується тіло циклу, обчислюється вираз 3 і здійснюється перехід до пункту 2, якщо вираз 2 дорівнює нулю (неправда), то керування передається на оператор, що слідує за оператором for.   Істотно те, що перевірка умови завжди виконується на початку циклу. Це значить, що тіло циклу може жодного разу не виконатися, якщо умова виконання відразу буде помилковою.   Приклад:   int main() { int і, b; for (і = 1; і < 10; і ++) b = і*і; return 0;}   У цьому прикладі обчислюються квадрати чисел від 1 до 9.   Деякі варіанти використання оператора for підвищують його гнучкість за рахунок можливості використання декількох змінних, керуючих циклом.   Приклад:   int main() { int top, bot; char string[100], temp; for (top=0, bot=100 ; top < bot; top++, bot--) { temp=string[top]; string[bot]=temp; } return 0; } У цьому прикладі, що реалізує запис рядка символів у зворотному порядку, для керування циклом використовуються дві змінні top і bot. Відзначимо, що на місці виразу 1 і виразу 3 тут використовуються кілька виразів, записаних через кому, і виконуваних послідовно.   Іншим варіантом використання оператора for є нескінченний цикл. Для організації такого циклу можна використовувати порожній умовний вираз, а для виходу з циклу звичайно використовують додаткову умову і оператор break.   Приклад:   for (;;) {... ... break; … } Відповідно до синтаксису мови Сі оператор може бути порожнім, тому тіло оператора for також може бути порожнім. Така форма оператора може бути використана для організації пошуку.   Приклад:   for(i=0; t[i]<10; і++);   У даному прикладі змінна циклу і приймає значення номера першого елемента масиву t, значення якого більше 10.   Специфікації при введенні і виведенні інформації.   Специфікації типу використовуються в керуючому рядку при введенні (функція scanf()) чи виведенні даних (функція printf()) і вказують, який тип даних зараз вводиться/виводиться. Символи специфікації типу:   Символ типу Формат уведення/висновку %с Інтерпретує введення/виведення як символ. %d Інтерпретує введення/виведення як десяткове ціле число зі знаком. %е, %f, %g Інтерпретує введення/виведення як дійсне число (тип даних float). %Е, %G Інтерпретує введення/виведення як дійсне число (тип даних float). %і Інтерпретує введення/виведення як десяткове ціле число зі знаком. %lf Інтерпретує введення/виведення як дійсне число (тип даних double). %о Інтерпретує введення/виведення як восьмеричне ціле число зі знаком. %р Інтерпретує введення/виведення як вказівник (адреса). %s Інтерпретує введення/виведення як рядок; введення починає з першого символу, що не є службовим, і включає всі символи до наступного службового символу. %u Інтерпретує введення/виведення як десяткове ціле число без знака. %х, %Х Інтерпретує введення/виведення як шестнадцатирічне ціле число зі знаком. Приклад: scanf("%d %lf %с %f ', &а, &b, &ch, &d); У цьому прикладі вводяться ціле, дійсне (тип double) числа, одиночний символ і дійсне число (тип float). рrintf("количество слов = %d\n", n); Тут виводиться ціле десяткове число зі знаком. Функції виведення   Функція printf().   Дві функції: printf() для виведення і scanf() для введення дозволяють перетворювати чисельні величини в символьне представлення і назад. Вони також дозволяють генерувати і інтерпретувати форматні рядки. Функція printf(control, arg1, arg2,...); перетворює, визначає формат і друкує свої аргументи в стандартний поток виведення під керуванням рядка CONTROL. Керуючий рядок містить два типи об'єктів: звичайні символи, що просто копіюються у вихідний потік, і специфікації перетворень, кожна з який викликає перетворення і друк чергового аргументу printf(). Специфікація формату функції: % [ прапорець][довжина][. точність][F/N][h/l] тип Кожне поле специфікації формату є одиночним символом або числом, що задає конкретний режим формату. Якщо за знаком % стоїть символ, що не є полем формату, то символ просто копіюється у вихідний потік. Символ прапорця керує вирівнюванням виведення (прапорець -) і друком знака числа (прапорець +), пропусків (прапорець пропуск), десяткової крапки, префіксів восьмеричної і шестнадцатирічної систем числення (прапорець #). Поле довжина - позитивне ціле число, що задає мінімальне число виведених символів. Поле точність - позитивне ціле число, що визначає кількість виведених символів, кількість десяткових позицій або кількість значущих цифр. Специфікації формату для поля тип будуть розглянуті пізніше.   Функція виведення рядків puts().   Функція puts() дуже проста у використанні. Досить передати їй адресу рядка як аргумент. #include <stdio.h> int main () { char strl[80]; puts ("Введите строку"); gets(strl); puts(strl); return 0; } На відміну від printf(), при виведенні функція puts() автоматично здійснює перехід на новий рядок. Вона припиняє виведення, зустрівши нульовий символ, тому краще, щоб рядок містив такий символ. Функція fputs().   Функція fputs() є файл - орієнтованою версією функції puts(). Основні розходження між цими функціями полягають у наступному: - Функція fputs() використовує другий аргумент, що вказує, у який файл варто виконати запис. Для виведення на екран дисплея в якості цього аргумента можна використовувати stdout (від standard output - стандартне виведення), обумовлений у файлі stdio.h. - На відміну від puts(), функція fputs() не додає до виводу символ переходу на інший рядок автоматично. Необхідно звернути увагу, що функція gets() відкидає символ переходу на інший рядок при введенні даних, a puts() додає його до виведення. І навпроти, fgets() зберігає символ нового рядка у введенні, a fputs() не додає цей символ до виведенні.   Виведення символів на екран - putchar().   Функція putchar(), поміщає свій аргумент у «стандартне виведення», що за замовчуванням є терміналом. Виведення можна направити і у деякий файл. Приклад використання функції: putchar(ch); Струюура Сі - програми   Звичайна Сі-програма є визначенням функції main, яка для виконання необхідних дій викликає інші функції. Наприклад, програма, що є одним початковим файлом, який містить визначення функції main і функцій, що викликаються з main (виключаючи функції бібліотеки Сі, які в більшості своїй доступні програмісту у відкомпільованому, об'єктному вигляді). Ці функції здійснюють зв'язок за даними за допомогою передачі параметрів і повернення значень. Проте реальний програмний проект розробляється як безліч початкових файлів, які компілюються окремо, а потім об'єднуються у виконувану програму редактором зв'язків. При такій структурі початкової програми функції з різних файлів можуть використовувати глобально доступні зовнішні змінні. Самі функції за визначенням завжди зовнішні і доступні з будь-яких файлів. Приклад структури програми, що складається з двох файлів fнlel.c і fнle2.c, представлений нижче: fнlel.c                                  fнle2.c main()                                 шпс2() {                                              { }                                              } func1()                               func3() {                                              { }                                               } В даному прикладі функція main може виконати будь-яку з трьох функцій ftmcl, func2, func3. Кожна з цих функцій може викликати будь-яку з тих двох, що залишилися. Для того, щоб визначувана функція могла виконати яку-небудь роботу, вона повинна використовувати змінні. В мові Сі всі змінні повинні бути оголошені до їх використання. Оголошення встановлюють відповідність між ім'ям і атрибутами змінної, функції або типу. Розглянемо основні поняття Сі-програми. Початкова програма- це сукупність наступних об'єктів: директив, вказівок компілятору, оголошень і визначень. Директиви задають дії препроцесора по перетворенню тексту програми перед компіляцією. Вказівки компілятору - це команди, виконувані компілятором під час процесу компіляції. Оголошення задають імена і атрибути змінних, функцій і типів, що використовуються в програмі. Визначення - це оголошення, що визначають змінні і функції. Визначення змінної в доповненні до її імені і типу задає початкове значення оголошеної змінної. Крім того, визначення припускає розподіл пам'яті для змінної. Визначення функції специфікує її структуру, яка є сумішшю з оголошень і операторів, які утворюють саму функцію. Визначення функції також задає ім'я функції, її формальні параметри і тип величини, що повертається. Початкова програма може містити будь-яке число директив, вказівок компілятору, оголошень і визначень. Будь-якій з об'єктів програми має певний синтаксис, і кожна складова може з'являтися у будь-якому порядку, хоча вплив порядку, в якому слідують змінні і функції може бути використано в програмі. Нетривіальна програма завжди містить більше одного визначення функції. Функція визначає дії, виконувані програмою. В наступному прикладі ілюструється проста початкова програма на мові Сі. int х = 1;                        /*визначення змінної х */ inty=2;   extern intprintf (char* ...);/*оголошення функції */ main () /* оголошення головної функції або точка початку програми */ { int z;                          /*оголошення змінної */ int w; z = у + х; w = у - х; printf("z = %d\n w = %d \n", z, x); Ця початкова програма визначає функцію з ім'ям main і оголошує функцію printf(). Змінні х і у задаються своїми визначеннями. Змінні z і w тільки оголошуються. Початкові Сі-файли. Початкові програми можуть бути розділені на декілька файлів. Початковий файл Сі - це текстовий файл, який містить частину або всю початкову програму. Він може, наприклад, містити тільки деякі функції, що потрібні програмі. При компіляції початкової програми кожний з початкових файлів повинен бути відкомпільований окремо, а потім оброблений складальником. Окремі початкові файли перед компіляцією можна сполучати в один великий початковий файл за допомогою директиви #include. Початковий файл може містити будь-яку комбінацію наборів: директив, вказівок компілятору, оголошень і визначень. Такі об'єкти, як визначення функцій або великі структури даних, не можуть розриватися, починаючись в одному файлі і продовжуючись в іншому. Початковий файл не обов'язково повинен містити виконувані оператори. Іноді корисно розміщувати описи змінних в одному файлі з тим, щоб використовувати їх шляхом оголошення посилань з інших файлів. В цьому випадку визначення стають легко доступними для пошуку і модифікації. З тих же самих міркувань константи і макроси часто організовують в окремих #include- файлах і включають їх, якщо потрібно, в початкові файли. Директиви початкового файла відносяться тільки до цього початкового файла і файлів, що включають його (за допомогою #include). Крім того, кожна директива відноситься тільки до частини файла, яка слідує за нею. Якщо безліч директив повинні відноситися до всієї початкової програми, то всі початкові файли повинні містити ці директиви. Вказівки компілятору звичайно ефективні для окремих областей початкового файла. Специфічні дії компілятора, що задається вказівками, визначаються змістом останніх. Виконання програм. Кожна програма містить головну програмну функцію. В Сі головна програмна функція повинна бути поіменована як main. Функція main служить точкою старту при виконанні програми і звичайно управляє виконанням програми, організовуючи виклики інших функцій. Програма звичайно завершує виконання по закінченню функції main, хоча вона може завершитися і в інших точках, залежно від навколишнього оточення. Початкова програма звичайно включає декілька функцій, кожна з яких призначена для виконання певного завдання. Функція main може викликати ці функції з тим, щоб виконати те або інше завдання. Функція повертає управління при виконанні оператора return або по закінченні самої функції (вихід на кінець функції). Всі функції, включаючи функцію main, можуть бути оголошені з параметрами. Функції, що викликаються, набувають значення параметрів із викликаючих функцій. Значення параметрів функції main можуть бути передані із зовнішнього оточення. Наприклад, вони можуть бути передані з командного рядка. Угода Сі вимагає, щоб перші два параметри функції main називалися arge і argv. Параметр argc визначає загальне число аргументів, що передаються функції main. Параметр argv оголошується як масив вказівників, кожний елемент якого посилається на рядкове представлення аргументу, передаваного функції main. Третій параметр функції main (якщо він є) традиційно задається ім'ям envp. Проте Сі не вимагає цього імені. Параметр envp- це покажчик на масив вказівників рядкових величин, які визначають оточення, в якому виконується програма. Операційна система підтримує передачу значень для argc, argv, і envp параметрів, а користувач підтримує завдання значень фактичних параметрів для функції main. Угода про передачу параметрів більшою мірою визначається операційною системою, ніж самою мовою Сі. Формальні параметри функції повинні бути оголошені під час опису функції. Час життя і видимість. Концепції "Час життя" і "Видимість" є дуже важливими для розуміння структури програм на Сі. Час життя змінної може бути або "глобальним" або "локальним". Об'єкт з глобальним часом життя характеризується певною пам'яттю і значенням протягом всього життя програми. Об'єкт з локальним часом життя захоплює нову пам'ять при кожному вході в «блок», в якому він визначений або оголошений. Коли блок завершується, локальний об'єкт пропадає, а отже пропадає його значення. Об'єкт вважається «видимим» в блоці або початковому файлі, якщо відомий тип і ім'я об'єкту в блоці або початковому файлі. Об'єкт може бути «глобально видимим», коли мається на увазі, що він бачимий або може бути оголошений видимим протягом всього початкового файла, створюючого програму. Блок - це складовий оператор. Складові оператори складаються з оголошень і операторів. Блоки можуть бути вкладеними. Структура функції є сукупністю складових операторів. Таким чином, функції мають блокову структуру, блоки, у свою чергу, можуть містити усередині себе інші блоки. Всі функції мають глобальний час життя, незважаючи на те, де вони оголошені. Змінні, оголошені на зовнішньому рівні, завжди мають глобальний час життя. Змінні, оголошені на внутрішньому рівні, завжди мають локальний час життя. Типи даних і їхнє об'явлення. Правила опису змінних.   Важливою відмінністю мови Сі від інших мов є відсутність принципу змовчання, що приводить до необхідності об'явлення всіх змінних, що використовуються в програмі явно разом із указівкою відповідних їм типів. Об'явлення змінної має наступний формат: [специфікатор-класа-пам 'яті] специфікатор-типу описувач [=ініціатор][, описувач[= ініціатор]]... Описувач - ідентифікатор простої змінної або більш складна конструкція із квадратними дужками, круглими дужками або зірочкою (набором зірочок). Специфікатор типу - одно чи кілька ключових слів, що визначають тип змінної, що об'являється. У мові Сі є стандартний набір типів даних, використовуючи який можна сконструювати нові (унікальні) типи даних. Ініціатор - задає початкове значення або список початкових значень, що привласнюються змінним при об'явленні. Специфікатор класу пам'яті - визначається одним з чотирьох ключових слів мови Сі: auto, extern, register, static, і вказує, яким чином буде розподілятися пам'ять під оголошувану змінну, з одного боку, а з іншого, область видимості цієї змінної, тобто, з яких частин програми можна до неї звернутися. Категорії типів даних. Ключові слова для визначення основних типів даних: Цілі типи:                                                                                                 Дійсні типи: Char                                                                                                                                 float Int                                                                                                                                      double Short                                                                                                                                long double Signed Unsigned Змінна будь-якого типу може бути об'явлена як немодифікована. Це досягається додаванням ключового слова const до специфікатора-типу. Об'єкти з типом const являють собою дані, використовувані тільки для читання, тобто цій змінній не може бути привласнене нове значення. Якщо після слова const відсутній специфікатор-типу, то мається на увазі специфікатор типу int. Якщо ключове слово const стоїть перед об'явленням складених типів (масив, структура, суміш, перерахування), то це приводить до того, що кожний елемент також повинен бути немодифікованим, тобто значення йому може бути привласнено тільки один раз. Приклади: const double А = 2.128Е-2; const В = 286; (мається на увазі const int В = 286). Цілий тип даних. Для визначення даних цілого типу використовуються різні ключові слова, що визначають діапазон значень і розмір області пам'яті, яка виділяється під змінну (табл. 1). ______________________________________________________________ Таблиця І Tun Розмір пам'яті в байтах Діапазон значень Char 1 Від-128 до 127 Int 2   Short 2 Від -32 768 до 32 767 Long 4 Від -2 147 483 648 до 2 147 483 647 Unsigned char 1 Від 0 до 255 Unsigned int 2 * Unsigned short 2 Від 0 до 65535 Unsigned long 4 Від 0 до 4 294 967 295   Ключові слова signed і unsigned необов'язкові. Вони вказують, як інтерпретується нульовий біт оголошуваної змінної, тобто, якщо зазначене ключове слово unsigned, то нульовий біт інтерпретується як частина числа, у противному випадку нульовий біт інтерпретується як знаковий. У випадку відсутності ключового слова unsigned ціла змінна вважається знаковою. У тому випадку, якщо специфікатор типу складається з ключового типу signed чи unsigned і далі стоїть ідентифікатор змінної, то вона буде розглядатися як змінна типу int. Наприклад: unsigned int n; unsigned int b; int c; (мається на увазі signed int c); unsigned d; (мається на увазі unsigned int d); Модифікатор-типу char використовується для представлення символу (з масиву представлення символів) або для об'явлення строкових літералів. Значенням об'єкта типу char є код (розміром 1 байт), що відповідає символу, що представляється. Для представлення символів російського алфавіту, модифікатор типу ідентифікатора даних має вид unsigned char, тому що коди російських букв перевищують величину 127.   Дійсні дані Для змінних, що представляють дійсне число, використовуються наступні модифікатори-типу: float, double, long double (у деяких реалізаціях мови Сі long double відсутній). Величина з модифікатором-типу float займає 4 байти. З них 1 байт приділяється для знака, 8 біт для надлишкової експоненти і 23 біта для мантиси. Старший біт мантиси завжди дорівнює 1, тому він не заповнюється, у зв'язку з цим діапазон значень дійсної змінної, приблизно дорівнює від 3.14Е -38до3.14Е +38. Величина типу double займає 8 біт у пам'яті. її формат аналогічний формату float. Біти пам'яті розподіляються в такий спосіб: 1 біт для знака, 11 біт для експоненти і 52 біта для мантиси. З урахуванням опущеного старшого біта мантиси діапазон значень дорівнює від 1.7Е -308 до 1.7Е +308. Приклади: float а, з; double х, у; Вирази. Перетворення при обчисленні виразів.   Комбінація знаків операцій і операндів, результатом якої є певне значення, називається виразом. Знаки операцій визначають дії, що повинні бути виконані над операндами. Кожен операнд у виразі може бути виразом. Значення виразу залежить від розташування знаків операцій і круглих дужок у виразі, а також від пріоритету виконання операцій. У мові Сі присвоювання також є виразом, і значенням такого виразу є величина, що привласнюється. При обчисленні виразів тип кожного операнда може бути перетворений до іншого типу. Перетворення типів можуть бути неявними, при виконанні операцій і викликів функцій, чи явними, при виконанні операцій приведення типів. Операнд - це константа, літерал, ідентифікатор, виклик функції, індексний вираз, вираз вибору елемента або більш складний вираз, сформований комбінацією операндів, знаків операцій і круглих дужок. Будь-який операнд, що має константне значення, називається константним виразом. Кожен операнд має тип. Якщо в якості операнда використовується константа, то йому відповідає значення і тип константи, що його представляє. Ціла константа може бути типу int, long, unsigned int, unsigned long, у залежності від її значення і від форми запису. Символьна константа має тип int. Константа дійсного типу завжди має тип double чи float. Константний вираз - це вираз, результатом якого є константа. Операндом константного виразу можуть бути цілі константи, символьні константи, константи дійсного типу, константи перерахування, вирази приведення типів, вирази з операцією sizeof і інші константні вирази. Однак на використання знаків операцій у константних виразах накладаються наступні обмеження. 1.У константних виразах не можна використовувати операції присвоювання і послідовного обчислення (,). 2. Операція «адреса» (&) може бути використана тільки при деяких ініціалізаціях. Вирази зі знаками операцій можуть бути використані у виразах як операнди. Вирази зі знаками операцій можуть бути унарними (з одним операндом), бінарними (із двома операндами) і тернарними (із трьома операндами). Унарний вираз складається з операнда і попереднього йому знаку унарної операції і має наступний формат: знак-унарної-операції операнд Бінарний вираз складається з двох операндів, розділених знаком бінарної операції: операнд 1 знака-бінарної-операції операнд2 Тернарний вираз складається з трьох операндів, розділених знаками тернарної операції (?) і (:), і має формат: операнд 1 ? операнд2 : операндЗ Вирази в дужках. Будь-який операнд може бути укладений у дужки. Вони не впливають на тип і значення виразу, укладеного в дужки. Наприклад, у виразі (10 + 5)/5 дужки, у яких міститься запис 10 + 5, означають, що величина 10 + 5 є лівим операндом операції ділення. Результат виразу (10 +5) /5 дорівнює 3. Без дужок значення запису 10 + 5/5 дорівнювало 6 11. Хоча дужки впливають на те, яким шляхом групуються операнди у виразі, вони не гарантують детальний порядок обчислення виразу. Перетворення при обчисленні виразів. При виконанні операцій виконується автоматичне перетворення типів, щоб привести операнди виразів до загального типу або щоб розширити короткі величини до розміру цілих величин, використовуваних у машинних командах. Виконання перетворення залежить від специфіки операцій і від типу операнда чи операндів. Розглянемо загальні арифметичні перетворення: 1 .Операнди типу float перетворяться до типу double. 2.Якщо один операнд long double, то другий перетвориться до цього ж типу. З.Якщо один операнд double, то другий також перетвориться до типу double. 4. Будь-які операнди типу char і short перетворяться до типу int. 5.Будь-які операнди unsigned char чи unsigned short перетворяться до типу unsigned int. 6.Якщо один операнд типу unsigned long, то другий перетвориться до типу unsigned long. 7.Якщо один операнд типу long, то другий перетвориться до типу long. 8.Якщо один операнд типу unsigned int, то другий операнд перетвориться до цього ж типу. Таким чином, при обчисленні виразів операнди перетворяться до типу того операнда, що має найбільший розмір. Приклад: double ft, sd; unsigned char ch; unsigned long in; int i; Операції. Типи операцій.   Операції - це спеціальні комбінації символів, які специфікують дії по перетворенню різних величин. Компілятор інтерпретує кожну з цих комбінацій як самостійну одиницю, котра зветься лексемою (token).   Розрізняють арифметичні операції, операції співвідношення, логічні операції, побітові операції, операції присвоювання, операції обчислення розміру (sizeof) і операція слідування (кома). 1. Арифметичні операції До арифметичних операцій відносять: + додавання - віднімання / ділення * множення % остача від ділення     Всі операції (за винятком остачі від ділення) визначені для змінних типу int, char і float. Остача від ділення не визначена для змінних типу float. 2. Операції співвідношень. У мові Сі визначені наступні операції відносини. <=                                                                                          Менше або дорівнює >                                                                                             Більше >=                                                                                          Більше або дорівнює = =                                                                                         Дорівнює ! =                                                                                          Нерівно <                                                                                             Менше Усі перераховані операції приводять до появи результату типу int. Якщо дане співвідношення між операндами істинно, то значення цього цілого -одиниця, а якщо співвідношення помилкове, то нуль. Всі операції типу більше-менше мають рівний пріоритет, причому він вище, ніж пріоритет операцій = = і ! =. Пріоритет операції присвоювання нижче пріоритету всіх операцій співвідносин. Для завдання правильного порядку обчислень використовуються дужки. 3. Логічні операції У мові маються 3 логічні операції. && Логічне I (and) || Логічне АБО (or) !                                                                                                                  Логічне НЕ (заперечення) Логічні операції звичайно в якості операндов використовують умовні вирази. Логічні операції мають низький пріоритет, і тому у виразах з такими операціями дужки використовуються рідко. Обчислення виразів тут виконується зліва направо і припиняється, як тільки вдається визначити результат. Приклад: if(i>50 && j = = 24) 6 > 2 && 3= = 3 - істинно ! (6 > 2 && 3 = = 3) - ложно (істинно, якщо сам вираз помилковий і навпаки). 4. Операції присвоювання. До операцій присвоювання відносять: =                                                                                             Просте присвоювання + =                                                                                         Додавання з присвоюванням - =                                                                                          Відніміння з присвоюванням * =                                                                                         Множення з присвоюванням / =                                                                                            Ділення із присвоюванням а також префіксні і постфіксні операції: + + Інкремент -- Декремент     Всі операції присвоювання привласнюють змінній результат обчислення виразу. Приклад: а = (b = с)*d; Операції +=, - =, * = і / = є укороченою формою запису операції присвоювання. їхнє застосування: а+= b означає а = а + b а-= b означає а = а - b а*= b означає а = а * b а/= b означає а = a/b Префіксні і постфіксні операції ++ і -і використовують для збільшення (інкремент) і зменшення (декремент) на одиницю значення змінної. Семантика зазначених операцій наступна: ++а збільшує значення змінної а на 1 до використання цієї змінної у виразі. а++ збільшує значення змінної а на 1 після використання цієї змінної у виразі. --а зменшує значення змінної а на 1 до використання цієї змінної у виразі. a-- зменшує значення змінної а на 1 після використання цієї змінної у виразі. 5. Повітові операції До побітових операцій відносять: ~                                                                         Побітове доповнення «                                                                         Зрушення вліво »                                                                         Зрушення вправо &                                                                         Побітове І, видає адресу наступної за цим змінної ç                                                                             Побітове включаюче АБО ^                                                                             Побітове виключаюче АБО Операція sizeof() - видає розмір операнда праворуч (в одиницях розміру значення char). Операція «, » поєднує два вираза в один і гарантує, що лівий вираз буде обчислюватися першим. Значення усього виразу дорівнює значенню правого. Функції введення інформації. Функція scanf().   Функція scanf() найбільш загальна з функцій введення, оскільки може читати ряд форматів. Вона перетворює різні форми, що уводяться з клавіатури рядка в: цілі числа, числа з плаваючою комою, символи і рядки Сі. Вона використовує керуючий рядок виду: Scanf(control, arg1, arg2,...); де control - формат символів, що вводяться, специфікації формату; argl, arg2,... - аргументи, у які записуються результати. Якщо за рядком керування форматом аргументів більше, ніж специфікацій формату, зайві аргументи ігноруються. Якщо для специфікацій формату недостатньо аргументів, результат не визначений. Специфікація формату функції має наступний вид: % [*][довжина] [F/N] [h/l] тип Кожне поле специфікації формату є одиночним символом або числом, що означає конкретний режим формату. Символ типу визначає, як інтерпретується вхідне поле. Якщо за символом відсотка (%) стоїть символ, що не є символом керування форматом, цей символ і всі наступні символи (до наступного символу відсотка) розглядаються як звичайна послідовність символів, тобто послідовність символів, що повинна збігатися з введенням. Наприклад, щоб указати символ відсотка, треба використовувати %%. Зірочка (*), що випливає за символом відсотка, подавляє присвоювання наступного вхідного поля , яке інтерпретується як поле зазначеного типу. Поле читається, але не зберігається. Поле довжина (позитивне десяткове ціле число) задає максимальне число символів, що може бути прочитане з вхідного потоку. З вхідного потоку читається задана кількість символів, якщо тільки раніш не зустрінеться пропуск або символ, що не може бути перетворений відповідно до заданого формату. В останньому випадку може бути прочитане менше символів, ніж потрібно в специфікації довжини. Префікси F і N дозволяють подавити угоди за замовчуванням про адресацію використовуваної моделі пам'яті. Префікс F повинний використовуватися для аргументу, що вказує на об'єкт far, а префікс N - для аргументу, що вказує на об'єкт near. Префікс 1 означає, що відповідний специфікації формату аргумент повинний указувати на об'єкт типу long чи double, а префікс h означає, що аргумент повинний бути покажчиком на тип short. Символи типу, що можуть бути задані в специфікації формату будуть розглянуті пізніше. Зауваження: при введенні числових чи інших даних, крім рядка, перед аргументом ставиться знак одержання адреси &. Якщо ж із вхідного потоку вводиться рядок символів, то такий знак не ставиться. Приклад: int асе; float sim; char name[20]; scanf("%d %f %s",&ace, &sim, name); Необхідно також відзначити, що хоча функція scanf() і є універсальною, для введення різних типів даних: символів, рядків, існують спеціальні функції введення. Вони простіше у вживанні, працюють тільки з визначеним типом даних і не вимагають специфікацій формату.   Функція gets().   Функція gets() (get string - одержати рядок) дуже зручна для використання в інтерактивних програмах. Вона одержує рядок зі стандартного пристрою введення системи - звичайно клавіатури. Вона зчитує символи доти, поки не досягне символу переходу на інший рядок (‘\n’), дописує нульовий символ (‘\0’) і передає рядок викликаючій програмі. Приклад: #include <stdio.h> int main () { char name [25]; gets (name); printf("name - %s\n", name); return 0; }   Функція fgets().   Один з недоліків функції gets() полягає в тому, що вона не перевіряє, чи дійсно дані, що вводяться, розмістяться в зарезервованій для них області пам'яті. Зайві символи просто перекривають суміжні комірки пам'яті. Функція fgets() виправляє це, дозволяючи указувати верхню межу кількості підлягаючих зчитуванню символів. Оскільки функція fgets() призначена для введення/виведення файлів, вона трохи менш зручна для введення з клавіатури, чим функція gets(). Від функції gets() вона відрізняється в трьох відношеннях: - Вона приймає другий аргумент, що вказує максимальну кількість символів, що підлягають зчитуванню. Якщо цей аргумент має значення n, функція fgets() зчитує до n-1 символів або всі символи аж до символу переходу на інший рядок (у залежності від того, яка умова виконається раніш). - Якщо функція fgets() зчитує символ нового рядка, вона зберігає його в рядку, на відміну від функції gets (), що його відкидає. - Вона приймає третій аргумент, що вказує на підлягаючий зчитуванню файл. Щоб виконати зчитування з клавіатури, як аргумент необхідно використовувати stdin (скорочення від standard input - стандартне введення); цей ідентифікатор визначається у файлі stdio.h.   Функція getchar().   Функція getchar() не має аргументів, вона повертає черговий символ із вхідного потоку і передає його виконуваній програмі. Наприклад, слідуючий оператор читає черговий вхідний символ і привласнює його значення змінній ch: 0 ch = getchar(); Оператори. Види операторів.   Оператори Сі керують процесом виконання програми. У Сі, як і в інших мовах програмування, є умовні оператори, оператори циклу, вибору, передачі керування і т.д. Нижче представлений список цих операторів: break continue do for goto if null return switch while   Таким чином всі оператори мови Сі можуть бути умовно розділені на наступні категорії:   - умовні оператори, до яких відносяться оператор умови if і оператор вибору switch; - оператори циклу (for, while, do while); - оператори переходу (break, continue, return, goto); - інші оператори (оператор "вираз", порожній оператор). Всі оператори мови Сі, крім складених операторів, закінчуються крапкою з комою ";".   Оператори Сі складаються з ключових слів, виразів і інших операторів. В операторах Сі припустимі наступні ключові слова: break default for return case do goto switch continue else if while Оператор, що є компонентом іншого оператора, називається "тілом" включаючого оператора. Часто оператор - тіло є складеним оператором, що складається з одного чи більше операторів. Складений оператор обмежується фігурними дужками. Всі інші оператори Сі закінчуються крапкою з комою (;). Будь-який з операторів Сі може бути попереду позначений міткою, що складається з імені і двокрапки. Операторні мітки позначаються тільки оператором goto. Порядок виконання програми Сі збігається з порядком розташування операторів у тексті програми, за винятком тих випадків, коли оператор явно передає керування в іншу частину програми.   Оператор вираз.   Будь-який вираз, що закінчується крапкою з комою, є оператором.   Виконання оператора виразу полягає в обчисленні виразу. Отримане значення виразу ніяк не використовуються, тому, як правило, такі вирази викликають побічні ефекти. Необхідно зауважити, що викликати функцію, що неповертає значення можна тільки за допомогою оператора виразу.   Приклади:   ++ і; Цей оператор представляє вираз, що збільшує значення змінної і на одиницю.   А = cos (b * 5);   Цей оператор представляє вираз, що включає в себе операції присвоювання і виклику функції.   А (х, у);   Цей оператор представляє вираз, що складається з виклику функції.   Порожній оператор.   Порожній оператор складається тільки з крапки з комою. При виконанні цього оператора нічого не відбувається. Він звичайно використовується в наступних випадках:   - в операторах do, for, while, if у рядках, коли місце оператора не потрібно, але по синтаксису потрібен хоча б один оператор; - при необхідності позначити фігурну дужку.   Синтаксис мови Сі вимагає, щоб після мітки обов'язково слідував оператор. Фігурна ж дужка оператором не є. Тому, якщо треба передати керування на фігурну дужку, необхідно використовувати порожній оператор.   Приклад:   int main () { {if (...) goto a; /* перехід на дужку */ {... } а:;} return 0; } Складений оператор.   Складений оператор являє собою кілька операторів і повідомлень, укладених у фігурні дужки:   { [повідомлення]      .      . оператор; [оператор];    .    .   } Наприкінці складеного оператора крапка з комою не ставиться.   Виконання складеного оператора полягає в послідовному виконанні складових його операторів.   Приклад:   int main () { int q,b; double t,d; . . if(…) { int e,g; double f,q; . . } return (0); } Змінні e, g, f, q будуть знищені після виконання складеного оператора. Відзначимо, що перемінна q є локальною в складеному операторі, тобто вона ніяким чином не зв'язана зі змінною q оголошеної на початку функції main з типом int. Відзначимо також, що вираз стоїть після return може бути укладений в круглі дужки, хоча наявність останніх необов'язкова. Оператор if.   Оператор if називається оператором розгалуження, тому що він являє собою пункт, при досягненні якого програма повинна зробити вибір, по якому шляху йти далі. Узагальнена форма оператора має вигляд: if (вираз) оператор де оператор - будь-який оператор Сі, у тому числі простий чи складовий; вираз - умовний вираз, що порівнює величини двох і більш кількісних об'єктів. Оператор виконується, якщо вираз істинний, .у противному випадку він ігнорується. Таким чином, найпростіша форма дає можливість вибору оператора або його пропуска. Приклад: if (score>big) printf("Baша ставка выиграла"); Друга форма оператора надає можливість вибору одного оператора з двох: if (вираз) оператор 1 else оператор 2 Якщо вираз справедливий, то виконується оператор 1, інакше виконується оператор 2. Якщо між if і else необхідно поставити більш одного оператора, тобто складений, необхідно скористатися фігурними дужками. Існує також третя форма оператора, значно розширююча його можливості: if (вираз 1) оператор1  else if (вираз 2) оператор 2 else оператор З Якщо вираз 1 вірний, то виконується оператор 1. Якщо вираз 1 помилковий, але вираз 2 істинний, то виконується оператор 2. Якщо обидва вираза помилкові, виконується вираз 3. Приклад: if (score < 1000) bonus = 0; else if (score < 1500) bonus =1; else bonus = 6; При використанні складеного оператора if необхідно пам'ятати, що else відноситься до найближчого if, якщо фігурні дужки не встановлюють інший порядок. Приклад: if (number > 6) if (number < 12) printf(“Вы близки к цели! \n"); else printf("K сожалению, вы пропустили свою очередь! \n"); Число                         Відповідь 5                                 Немає відповіді 10                              Вы близки к цели! 15                             К сожалению, вы пропустили свою очередь! Тепер розставимо фігурні дужки: if (number > 6) { if (number < 12) printf ("Вы близьки к цели! \n"); } else printf("K сожалению, вы пропустили свою очередь! \n"); і одержимо такі відповіді: Число             Відповідь 5                         К сожалению, вы пропустили свою очередь! 10                      Вы близки к цели! 15                      Немає відповіді Оператор if допускає до 15 рівнів вкладеності. Одновимірні масиви Масив утворюється рядом елементів одного типу. Для вказівки компілятору про необхідність обробки даних у вигляді масиву використовуються оголошення. При оголошенні масиву компілятор повідомляється про кількість і тип елементів, що входять до складу масиву. Оголошення масиву Синтаксис: <специфікація типу><декларатор> [<конст вираз>]; <специфікація типу><декларатор> []; Тут квадратні дужки - це термінальні символи. Оголошення масиву визначає тип масиву і тип кожного елемента. Воно може визначати також число елементів в масиві. Змінна типу масив розглядається як покажчик на елементи масиву. Оголошення масиву може представлятися в двох синтаксичних формах, вказаних вище. <Декларатор> задає ім'я змінної. Квадратні дужки, наступні за декларатором, модифікують декларатор на тип масиву. <Константний вираз>, укладений в квадратні дужки, визначає число елементів в масиві. Кожний елемент має тип, що задається <специфікатором типа>, який може специфікувати будь-який тип, виключаючи void і тип функції. В другій синтаксичній формі опущений константний вираз в квадратних дужках. Ця форма може бути використана тільки тоді, коли масив ініціалізується або оголошений як формальний параметр, або оголошений як посилання на масив, явно визначений десь в програмі. Наприклад: Int days[] = {31, 28, 31, ЗО, 31, 31}; При використанні порожніх квадратних дужок для ініціалізації масиву компілятор підраховує кількість елементів в списку і встановлює розмір масиву рівним цьому числу. Типу масив відповідає пам'ять, яка потрібна для розміщення всіх його елементів. Елементи масиву з першого до останнього запам'ятовуються в послідовних зростаючих адресах пам'яті. Між елементами масиву в пам'яті розриви відсутні. Елементи масиву запам'ятовуються один за одним послідовно, а доступ до них здійснюється за допомогою цілочисельного індексу (або шляхом вказівки зсуву). Наприклад: int scores[10], game; char *name[20]; В першому прикладі оголошується змінна типу масив з ім'ям scores з 10 елементів типу int. Змінна з ім'ям game оголошена як проста змінна цілого типу. В другому прикладі оголошений масив покажчиків. Масив складається з 20-ти елементів, кожний з яких є покажчиком на величину типу char. В мові Сі перший елемент має індекс 0, тому останній елемент масиву має індекс, рівний п - 1. Значення елементам масиву можна привласнювати, використовуючи індекс масиву, або порядковий номер.   Покажчики і масиви.   В мові Сі існує сильний взаємозв'язок між покажчиками і масивами, настільки сильна, що покажчики і масиви дійсно слід розглядати одночасно. Будь-яку операцію, яку можна виконати за допомогою індексів масиву, можна зробити і за допомогою покажчиків. Варіант з покажчиками звичайно виявляється більш швидким, але і дещо більш важким для безпосереднього розуміння, принаймні для початківця. Опис: INT А[10]; визначає масив розміру 10, тобто набір з 10 послідовних об'єктів, званих А[0], А[1] А[9]. Запис А[І] відповідає елементу масиву через І позицій від початку. Якщо РА - покажчик цілого, описаний як INT*PA; то привласнення: РА = &А[0]; призводить до того, що РА указує на нульовий елемент масиву А; це означає, що РА містить адресу елемента А[0]. Тепер привласнення X = *РА; копіюватиме вміст А[0] в X. Якщо РА указує на деякий певний елемент масиву А, то за визначенням РА+1 указує на наступний елемент, і взагалі РА-І указує на елемент, що стоїть на І позицій до елемента, указуваного PA, а РА+І на елемент, що стоїть на І позицій після. Таким чином, якщо РА указує на А[0], то *(РА+1); посилається на вміст А[1], РА+І - адреса А[І], а *(РА+І) - одержиме А[І]. Очевидно існує дуже тісна відповідність між індексацією і арифметикою покажчиків. Насправді компілятор перетворить посилання на масив в покажчик на початок масиву. В результаті цього ім'я масиву є вказівним виразом. Звідси витікають декілька вельми корисних слідств. Оскільки ім'я масиву є синонімом місцеположення його нульового елемента, то привласнення РА=&А[0] можна записати як РА = А; Ще більш дивним, принаймні на перший погляд, здається той факт, що посилання на А[І] можна записати у вигляді *(А+І). При аналізі виразу А[І] в мові Сі воно негайно перетвориться до вигляду *(А+І); ці дві форми абсолютно еквівалентні. Якщо застосувати операцію & до обох частин такого співвідношення еквівалентності, то ми отримаємо, що &А[І] і А+І теж ідентичні: А+І - адреса 1-го елемента від початку А. З другого боку, якщо РА є покажчиком, то у виразах його можна використовувати з індексом: РА[І] ідентично *(РА+І). Коротше, будь-який вираз, що включає масиви і індекси, може бути записаний через покажчики і зсуви і навпаки, причому навіть в одному і тому ж твердженні. Є одна відмінність між ім'ям масиву і покажчиком, яке необхідно мати на увазі. Покажчик є змінною, так що операції РА=А і РА++ мають сенс. Але ім'я масиву є константою, а не змінною: конструкції типу А=РА або А++, або Р=&А будуть незаконними. Багатовимірні масиви.   В мові Сі передбачені прямокутні багатовимірні масиви, хоча на практиці існує тенденція до їх значно більш рідкісного використання в порівнянні з масивами покажчиків. Масив масивів або багатовимірний масив визначається шляхом завдання списку константних виразів в квадратних дужках, наступного за декларатором: <специфікатор типу><декларатор>[<константний вираз>] [<константний вираз>]... Кожний константний вираз в квадратних дужках визначає число елементів в даному вимірюванні масиву, так що оголошення двовимірного масиву містить два константні вирази, трьохвимірного- три і т.д. Якщо багатовимірний масив оголошується усередині функції або якщо він ініціалізується, або оголошується як формальний параметр, або оголошується як посилання на масив, явно визначений десь в програмі, то перший константний вираз може бути опущений. Наприклад: Float Нор[10][10]; IntA[2][3][3]; Двовимірне уявлення - всього лише зручний спосіб візуалізації масиву, що має два індекси. В пам'яті комп'ютера такий масив зберігається послідовно, починаючи з першого елемента. Перший індекс багатовимірного масиву також має індекс 0. Взагалі, все розглянуте раніше щодо одновимірних масивів має відношення і до багатовимірних.   Динамічне виділення пам'яті.   Об'єм пам'яті, необхідний для зовнішніх, статичних і зовнішніх статичних класів пам'яті, відомий під час компіляції, і дані, що зберігаються в цій секції, доступні під час виконання програми. Кожна змінна з цих класів виникає при запуску програми і зникає, коли робота програми завершена. Автоматична змінна створюється, коли програма передає управління блоку коду, що містить визначення змінної, і руйнується, коли блок закінчує виконання. Тому, оскільки функції викликають програми, а потім час роботи функцій закінчується, то об'єм пам'яті, що використовується автоматичними змінними, то збільшується, то зменшується. Ця секція пам'яті звичайно обробляється як стек. Це означає, що нові змінні послідовно додаються в пам'ять в тому порядку, в якому вони були створені, а потім вони видаляються в порядку, протилежному надходженню. Динамічно розподілена пам'ять з'являється, коли викликається функція malloc() або інша, пов'язана з нею, і вивільняється при зверненні до функції free(). Постійність об'єму пам'яті регулюється програмістом, а не набором жорстких правил, так що блок пам'яті може бути створений в одній функції, а розпоряджатися їм можна з іншій функції. Через це частина пам'яті, що використовується для динамічного розподілу пам'яті, може виявитися фрагментованою, тобто невикористані ділянки пам'яті можуть виявитися серед її активних блоків. Використання динамічної пам'яті відноситься до більш повільних процесів, ніж використовування пам'яті стека. Символьні рядки. Правила описи й ініціалізації символьних масивів.   Рядок - це ряд символів, які обробляються як один блок. У Сі немає спеціального типу змінної для рядків, як наприклад, в Паскалі. Замість цього рядки мають тип char і збережені в масиві. Символи в рядку зберігаються в суміжних комірках пам'яті, один символ міститься в один осередок, масив складається із суміжних комірок пам'яті, так що рядок розміщається в масиві природним образом. Нумерація елементів масиву починається з нуля. У мові Сі рядки представлені рядом символів, що закінчуються нульовим символом 70'. Тому, будь-який рядок займає в пам'яті на один символ більше, ніж записано між подвійними лапками. Приклад: ‘Т' - це символ (літера), "Т" - це рядок, що складається з двох символів: Т і '\0'. Звідси слідує, що порожніх рядків не буває. При визначенні масиву символьних рядків компілятору необхідно повідомити, скільки місця потрібно для його збереження. Для цього існує два способи: 1)         тому що рядок - це масив, то іниіціалізується рядок так само як звичайний масив плюс один елемент для завершального нульового символу. Приклад: char name [ЗО]. 2) рядок у мові Сі - це різновид константи і її можна привласнювати деякій змінній, що представляє масив символів. Наприклад: char str[] = "ТЕКСТ"; Такий запис і коротше і зрозуміліше, ніж загальноприйнята для початкової ініціалізації масивів. char str[] = {‘Т’,'Е','К','С',’Т’}; Якщо довжина рядка в квадратних дужках опущена, то вона визначається автоматично, по кількості символів, що привласнюються. У приведеному вище прикладі вона дорівнює шести. Для того, щоб зчитати в програму, спочатку необхідно зарезервувати місце в пам'яті для її збереження, а потім використовувати функцію введення для завантаження рядка. Для введення рядків призначена функція gets(), а для їхнього виведення - puts().   Функція gets().   Функція gets() (get string - одержати рядок) дуже зручна для використання в інтерактивних програмах. Вона одержує рядок зі стандартного пристрою введення системи - звичайно клавіатури. Оскільки рядок не має заздалегідь визначеної довжини, функція gets() має потребу в способі визначення моменту припинення своєї роботи. Вона зчитує символи доти, поки не досягне символу переходу на інший рядок (‘\n'), що генерується шляхом натискання клавіші Enter. Функція приймає всі символи аж до символу зміни рядка (але не включаючи його), дописує нульовий символ (‘\0’) і передає рядок викликаючій програмі. Сам символ зміни рядка зчитується і відкидається, тому наступне зчитування починається з початку наступного рядка. Найпростіші способи використання функції gets(): #include <stdio.h> #defineMAX81 int main () { char name [MAX]; /* виділення області в пам'яті */ printf("Hi, what's your name?\n"); gets (name); /* приміщення рядка в масив name */ printf("Nice name, %s\n", name); return 0; } Головне розходження між функціями scanf() і gets() полягає в тому, як вони визначають момент досягнення кінця рядка: scanf() є скоріше функцією «одержання слова», чим функцією «одержання рядка». Функція gets() зчитує всі символи аж до першого символу нового рядка. Для переривання уведення функція scanf() має дві можливості. У будь-якому випадку рядок починається з першого зустрінутого символу, відмінного від службового. При використанні формату %s рядок продовжується до наступного службового символу (пробілу, символу табулящї або символу переходу на інший рядок), не включаючи його. У випадку вказівки ширини поля, як у форматі %10s, функція scanf() зчитує до 10 символів або усі символи до першого службового символу (у залежності від того, яке умова виконається раніше).   Функція puts().   Функція puts() дуже проста у використанні. Досить передати їй адресу рядка як аргумент. #include <stdio.h> #define DEF "I am a fdefined string." int main () { char strl [80] = "An array was initialized to me."; char *str2 = "A pointer was initialized to me."; puts ("I'm an argument to puts()."); puts(DEF); puts(strl); puts(str2); return 0; } Тут кожен рядок відображається у своєму рядку виведення. На відміну від printf(), при виведенні функція puts()() автоматично здійснює перехід на новий рядок. Вона припиняє виведення, зустрівши нульовий символ, тому краще, щоб рядок містив такий символ. Строкові функції strlen(), strcmp(), strcpy(), strtok()   Бібліотека Сі містить кілька функцій обробки рядків; прототипи цих функцій визначаються в заголовному файлі string.h. До них відносяться функції: strlen(), strcat, strncat, strcmp(), strncmp(), strcpy(), strncpy() та інші.   Функція strlen().   Функція strlen() визначає довжину рядка в символах, виключаючи нульовий символ. Довжина, що повертається, являє собою ціле число типу int. Наприклад: #include <stdio.h> int main () { char strl[80]; gets(str1); printf("Довжина рядка str1 %d символів \n",strlen(str1)); return 0; } Функції strcmp() і strncmp().   Формати функцій: int strcmp(const char *s1, const char *s2); int strncmp(const char *sl, const char *s2, size n); Функція strcmp() (від string comparision - порівняння рядків) призначена для порівняння рядків, причому порівнюється їхній вміст, а не їхня адреса. Ця функція діє стосовно рядків аналогічно тому, як оператори відносин діють стосовно чисел. Має три значення, які повертає: 1 - якщо перший рядок більше другого; 0 - якщо обидва рядки однакові; -1 - якщо перший рядок менше другого. Функція strcmp() порівнює рядки доти, поки не знайде відповідний символ, що відрізняється, а для цього може знадобитися перегляд одного з рядків до кінця. Функція strncmp() порівнює рядки доти, поки вони не будуть відрізнятися або поки не буде виконане порівняння скількох символів, скільки зазначено третім аргументом функції.   Функції strcpyO() і strncpy().   Функція strcpy() призначена для копіювання рядків, являє собою строковий еквівалент операції присвоювання. Працює вона в такий спосіб, рядок, що вказується другим аргументом, копіюється в масив, що задається першим аргументом, і його повертає. Копія називається метою, а вихідний рядок -джерелом. Таким чином, функція strcpy() приймає як аргументи два строкових вказівника. Другий вказівник, що вказує на вихідний рядок, може бути об'явленим вказівником, ім'ям масиву або строковою константою, але перший вказівник, що вказує на копію, повинен указувати на такий об'єкт даних, як масив, досить великий, щоб рядок міг поміститися в ньому. Формат: char *strcpy(char *s1, const char *s2); Функція stmcpy(), формат якої наступний: char *strncpy(char *s1, const char *s2, size n); копіює до n-го символу або до порожнього символу з рядка, зазначеної вказівником s2, у розташування, зазначене вказівником si; якщо порожній символ у рядку s2 потрапляється раніш, ніж n символів скопійовано, рядок доповнюється порожніми символами до розміру n; якщо n символів скопійовано до появи порожнього символу, рядок порожніми символами не доповнюється; функція повертає si.   Функція strtok().   Формат функції: char *strtok(char *s1, const char *s2); Ця функція переформує рядок si в окремі знаки; рядок s2 містить символи, що використовуються як роздільники. Функція викликається послідовно. Для першого виклику si повинен указувати на рядок, який необхідно розбити на знаки. Функція знаходить перший роздільник, який слідує за символом, що не є роздільником, і заміняє його пропуском. Вона повертає вказівник на рядок, що містить перший знак. Якщо жодного знака не знайдено, вона повертає NULL. Щоб знайти наступний знак у рядку, необхідно викликати strtok() знову, але першим аргументом поставити NULL. Кожен послідовний виклик повертає покажчик на наступний знак чи на NULL, якщо більше знаків не знайдено. Функція strtok() трохи незвичайна у використанні, тому нижче приведений невеликий приклад, у якому підраховується кількість слів у реченні. #include <stdio.h> #include <string.h> int main () { int і = 0; char data[40]; const char razd[] = " " /* символи-роздільники */ char *pt; gets(data); pt = strtok(data, razd); /* вихідний виклик */ while (pt) /* вихід після одержання NULL */ { puts(pt); /* показати знак */ pt = strtok(NULL, razd); /* наступний знак */   і к++; } printf("Рядок містить %d слів \n", k); return 0;   } Структури.   Структура - це складений об'єкт, набір з однієї чи більше змінних, можливо різних типів, згрупованих під одним ім'ям для зручності обробки. У структуру можуть входити елементи будь-яких типів, за винятком функцій. (У деяких мовах, наприклад Паскалі, структури називаються "записами"). На відміну від масиву, що є однорідним об'єктом, структура може бути неоднорідною. Традиційним прикладом структури є облікова картка працюючого: "службовець" описується набором атрибутів таких як прізвище, ім'я, по батькові (П.І.Б.), адреса, код соціального забезпечення, зарплата і т.д. Деякі з цих атрибутів самі можуть виявитися структурами - П.І.Б. Структури виявляються корисними при організації складних даних особливо у великих програмах, оскільки в багатьох ситуаціях вони дозволяють згрупувати зв'язані дані таким чином, що з ними можна працювати, як з одним цілим, а не як з окремими об'єктами. Тип структури визначається записом виду: struct { список визначень } У структурі обов'язково повинний бути зазначений хоча б один компонент. Визначення структури має наступний вид: тип даних описувач; де тип даних указує тип структури для об'єктів, обумовлених в описувачах. У найпростішій формі описувачі являють собою ідентифікатори або масиви. Приклад: struct { double х,у;} si, s2, sm[9]; struct { int year; char moth, day; } date1, date2; Змінні si, s2 визначаються як структури, кожна з який складається з двох компонентів х и у. Змінна sm визначається як масив з дев'яти структур. Кожна з двох змінних date1, date2 складається з трьох компонентів year, moth, day. Існує і інший спосіб асоціювання імені з типом структури, він заснований на використанні тега структури. Ter структури аналогічний тегу перечислимого типу. Тег структури визначається в такий спосіб: struct тег {список описів;}; де тег є ідентифікатором. У приведеному нижче прикладі ідентифікатор student описується як тег структури. struct student { char name[25]; int id, age; char prp;  }; Опис структури, що складається з заключеного у фігурні дужки списку описів, починається з ключового слова STRUCT. За словом STRUCT може слідувати необов'язкове ім'я - ярлик структури. Такий ярлик іменує структури цього виду і може використовуватися надалі як скорочений запис докладного опису. Тег структури використовується для наступного об'явлення структур даного виду у формі: struct тег списківндентифікаторів; Приклад: struct student st1,st2; Елементи або змінні, згадані в структурі, називаються членами. Ярлики і члени структур можуть мати такі ж імена, що і звичайні змінні, оскільки їхні імена завжди можна розрізнити по контексту. Звичайно однакові імена привласнюють тільки тісно зв'язаним об'єктам. Опис структури, за яким не слідує список змінних, не приводить до виділення якої-небудь пам'яті; він тільки визначає шаблон або форму структури. Зовнішню чи статичну структуру можна ініціалізувати, помістивши слідом за її визначенням список ініціалізаторів для її компонентів. Член визначеної структури може бути зазначений у виразі за допомогою конструкції виду: ім'я структури. член Операція вказівки члена структури «.» звязує ім'я структури і ім'я члена. Т.ч. доступ до компонентів структури здійснюється за допомогою вказівки імені структури і наступного через крапку імені виділеного компонента, наприклад: st1 .name = «Іванов»; st2.id=st1.id; st1_node. data=st1.age;   Структури і функції.   У мові Сі існує ряд обмежень на використання структур. Обов'язкові правила полягають у тім, що єдині операції, які можна проводити зі структурами, складаються у визначенні її адреси за допомогою операції & і доступі до одного з її членів. Це призводить до того, що структури не можна привласнювати чи копіювати як ціле, і що вони не можуть бути передані функціям або повернуті ними. На покажчики структур ці обмеження не накладаються, так що структури і функції все-таки можуть зі зручністю працювати спільно. Автоматичні структури, як і автоматичні масиви, не можуть бути ініціалізовані; ініціалізація можлива тільки у випадку зовнішніх чи статичних структур. Директиви препроцесора   Директиви препроцесора являють собою інструкції, записані в тексті програми на Сі і виконувані до трансляції програми. Препроцесор Сі - це текстовий процесор, використовуваний для обробки текстового вихідного файлу на першій фазі компіляції. Компілятор звичайно викликає препроцесор у своєму першому проході, однак препроцесор може бути викликаний автономно для обробки тексту без компіляції. Директиви препроцесора дозволяють змінити текст програми, наприклад, замінити деякі лексеми в тексті, вставити текст з іншого файлу, заборонити трансляцію частини тексту і т.п.   Препроцесор Сі розпізнає наступні директиви:   # define                                   #if                    #liпе #elif                                           #ifdef         #undef # else                                         # ifndef # endif                                      # include Знак номера (#) повинний бути першим (без попередніх пропусків) у рядку, що містить директиву. Пропуски допускаються між знаком номера і першою буквою директиви. Деякі директиви вимагають аргументи або значення. Директиви можуть з'являтися де завгодно у вихідному файлі, але вони застосовні тільки до кінця вихідного файлу від місця, де вони з'явилися. Після директив препроцесора крапка з комою не ставиться. Розглянемо директиви препроцесора більш докладно.   Директива #include.   Директива #include включає в текст програми вміст зазначеного файлу. Ця директива має дві форми.   #include "ім'я файлу" #include<імя файлу>   Ім'я файлу повинне відповідати угодам операційної системи і може складатися або тільки з імені файлу, або з імені файлу з його маршрутом. Якщо ім'я файлу зазначене в лапках, то пошук файлу здійснюється відповідно до заданого маршруту, а при його відсутності в поточному каталозі. Якщо ім'я файлу задане в кутових дужках, то пошук файлу вироконується в стандартних директоріях операційної системи, що задаються командою PATH.   Директива //include може бути вкладеною, тобто у файлі, що включається, теж може міститися директива #include, що заміщається після включення файлу, який містить цю директиву. Директива #include широко використовується для включення в програму так званих заголовних файлів, що містять прототипи бібліотечних функцій, і тому більшість програм на Сі починаються з цієї директиви.   Директива #define.   Директива #define служить для заміни констант, що часто використовуються, ключових слів, чи операторів виразів деякими ідентифікаторами. Ідентифікатори, що заміняють текстові чи числові константи, називають іменованими константами. Ідентифікатори, що заміняють фрагменти програм, називають макровизначеннями, причому макровизначення можуть мати аргументи.   Директива #define має дві синтаксичні форми:   #define ідентифікатор текст #define ідентифікатор (список параметрів) текст   Ця директива заміняє всі наступні входження ідентифікатора на текст. Такий процес називається макропідстановкою. Текст може являти собою будь-який фрагмент програми на Сі або може бути відсутній. В останньому випадку всі екземпляри ідентифікатора видаляються з програми.   Приклад:   #define WIDTH 80 #define LENGTH (WIDTH+10)   Ці директиви змінять у тексті програми кожне слово WIDTH на число 80, а кожне слово LENGTH на вираження (80+10) разом з його дужками.   Дужки, що містяться в макровизначенні, дозволяють уникнути непорозумінь, зв'язаних з порядком обчислення операцій. Наприклад, при відсутності дужок вираз t = LENGTH*7 буде перетворено у вираз t = 80 +10*7, а не у вираз t = (80+10)*7, як це виходить при наявності дужок, і в результаті вийде 780, а не 630.   В другій синтаксичній формі в директиві #define мається список формальних параметрів, що може містити один чи кілька ідентифікаторів, розділених комами. Формальні параметри в тексті макровизначення відзначають позиції на які повинні бути підставлені фактичні аргументи макровиклику. Кожен формальний параметр може з'явитися в тексті макровизначення кілька разів. При макровиклику слідом за ідентифікатором записується список фактичних аргументів, кількість яких повинна збігатися з кількістю формальних параметрів.   Директива #undef   Директива #undef використовується для скасування дій директиви #с1ешіе. Синтаксис цієї директиви наступний   #undef  ідентифікатор   Директива скасовує дію поточного визначення #define для зазначеного ідентифікатора. Не є помилкою використання директиви #undef для ідентифікатора, що не був визначений директивою #define. Приклад: #undef WIDTH Ці директиви скасовують визначення іменованої константи WIDTH. Умовна компіляція. Існують директиви, що керують умовною компіляцією. Ці директиви дозволяють скасувати компіляцію частин вихідного файлу за допомогою перевірки константних виразів чи ідентифікаторів, при якій визначається чи потрібно передавати на вихід або пропустити дану частину вихідного файлу на стадії препроцессування. Директиви #іf, #elif, #else, #endif. Синтаксис: #if<константнии вираз> [<текст>] [#elif <константнии вираз><текст>] [elif/ <константний вираз><текст>] . . . [#else <текст>] #епdif Директива Ш разом з директивами #е1іf, #else і #endif керує компіляцією частин вихідного файлу. Кожній директиві #if у вихідному файлі повинна відповідати закриваюча директива #endif. Між директивами #if і #endif допускається нуль або більше директив #elif і не більш однієї директиви #else. Директива #else, якщо вона є, повинна бути розташована безпосередньо перед директивою #endif. Препроцесор вибирає одну з ділянок тексту <текст> для подальшої обробки. Ділянка <текст> - це будь-яка послідовність тексту. Він може займати більше одного рядка. Звичайно це ділянка програмного тексту, що має сенс для компілятора чи препроцесора. Однак, ця не обов'язкова вимога. Препроцесор можна використовувати для обробки будь-якого тексту. Обраний текст обробляється препроцесором і посилається на компіляцію. Якщо <текст> містить директиви препроцесора, то ці директиви виконуються. Будь-яка ділянка тексту, не обрана препроцесором, ігнорується на стадії препроцессування і згодом не компілюється. Препроцесор вибирає окрему ділянку тексту на основі обчислення обмеженого константного виразу <константний вираз>, що стоїть за кожною #if чи #elif директивою, поки не буде знайдений виражез зі значенням істина (не нуль). Вибирається <текст>, що іде за істинним константним виразом до найближчого знака номера (#). Якщо обмежений константний вираз помилковий або відсутня директива #elif, то препроцесор вибирає <текст> після запису #else. Якщо запис #else опущений, а вираз директиви #if помилковий, то текст не вибирається. Директиви #if, #elif, #else, #endif можуть бути вкладеними. Кожна з вкладених директив #else, #elif, #endif належить до найближчої попередньої директиві #if.

Директиви # ifdef і # ifndef .

Синтаксис:

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

Директиви #ifdef і #ifndef виконують ті ж самі задачі, що і директива #if, яка використовує defined (ідентифікатор). Ці директиви можуть бути використані там же, де використовується директива #if, і використовуються винятково для компактності запису.

Коли препроцесор обробляє директиву ifdef, то робиться перевірка ідентифікатора на істинність.

 

Директива #ifdef є запереченням директиви #ifdef. Іншими словами, якщо ідентифікатор не визначений (чи його визначення скасоване директивою #undef), то його значення істинне. У противному випадку значення помилкове

(нуль).


Функції в мові Сі. Формальні і фактичні параметри.

 

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

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

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

З використанням функцій в мові Сі зв'язано три поняття; визначення функції, оголошення функції і виклик функції.

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

Визначення функції.

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

[специфікатор-класу нам'яті[специфікатор-типа] описувач ([список-формальных-параметрів]) тіло-функції

де клас пам'яті - необов'язковий специфікатор, задає клас пам'яті функції, який може бути або static, або extern. Якщо він не заданий, то за умовчанням вважається extern;

специфікатор-типа і описувач задають тип значення, що повертається функцією, і ім'я функції. Якщо специфікатор типу не заданий, то передбачається, що функція повертає значення типу int. Описувач функції може бути заданий із зірочкою, що означає, що функція повертає покажчик. Функції не можуть повертати масив або функцію, але можуть повертати покажчики на будь-який тип, включаючи масиви і функції. Функція повертає значення, якщо її виконання закінчується виконанням оператора return в тілі функції і управління повертається в точку виклику. Якщо оператор return не заданий або не містить виразу, функція не повертає ніякого значення. В цьому випадку специфікатор типу значення, що повертається, повинен бути заданий ключовим словом void, що означає відсутність значення, що повертається.

список формальних параметрів - послідовність оголошень формальних параметрів, розділених комами;

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

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

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

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

Якщо формальний параметр представлений в списку, але не оголошений, то передбачається, що параметр має тип int.

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

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

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

Робота з файлами в Сі

 

Мова Сі розглядає файл як послідовність байтів, кожний з яких може бути прочитаний індивідуально. Програми Сі автоматично відкривають п'ять файлів. Вони мають назви стандартне введення, стандартне виведення, стандартне виведення помилок, стандартний додатковий потік і стандартний друк: stdin, stdout, stderr, stdaux і stdprn. Для роботи з довільним файлом користувача використовується поняття потоку.

Потік - файл на диску або фізичний пристрій. Для відкриття потоку використовується функція fopen().

FOPEN().

#include <stdio.h>
FILE *fopen(pathname, type);
char *pathname;                   path-ім'я файла,

char *type;                              дозволений тип доступу.

Функція fopen відкриває файл, визначуваний path-ім'ям. Символи в рядку
type визначають тип доступу для файла, таким чином.___________________________

Режим Опис
“r” відкрити файл для читання. (Цей файл повинен існувати).
"w" відкрити порожній файл для запису; якщо цей файл раніше існував, його вміст знищується.
"а" відкрити файл для запису (додавання) в кінець. Якщо даного файла немає, то спочатку він створюється.
"r+" відкрити файл одночасно для читання і запису. Файл повинен існувати.
w+” відкрити порожній файл для читання і запису. Якщо цей файл раніше існував, його вміст знищується.
“a+" відкрити файл для читання і додавання. Якщо файла немає, спочатку він створюється.


Якщо файл відкритий за допомогою типу "а" або "а+", всі операції запису виконуються в кінець файла. При використанні функцій fseek або rewind можливо перепозиціонування покажчика на файл; не дивлячись на це, покажчик на файл перед виконанням будь-яких операцій запису завжди повертається в кінець файла. Таким чином, існуючі дані не будуть перезаписані. При використанні типів "r+", "w+", "а+" допускається одночасно читання і запис. (Вважається, що файл відкривається для оновлення). Тому, при перемиканні читання на запис і навпаки потрібно використовувати функції fseek або rewind. Для функції fseek (при необхідності) може бути точно визначена поточна позиція.

Якщо t або b в рядку type не задається, режим перетворення визначається змінні fmode і режимом, встановлюваним за умовчанням.

Функція fopen повертає покажчик на відкритий файл. Значення покажчика NULL свідчить про помилку.

 

FCLOSE().

 

Функція fclose() закриває окремий вказаний потік. Все буфера, пов'язані з потоком, перед закриттям потоку вивантажуються. Якщо потік явно не закривається в програмі, він автоматично закривається при завершенні програми.

 

FEOF().

 

Функція feof() визначає, чи досягнутий кінець потоку. Після того, як він досягнутий, операції читання з потоку повертатимуть умову кінця потоку до тих пір, поки потік не буде закритий або не буде виконана функція ге\уіпе() для потоку.

 

FSEEK().

 

#include <stdio.h>
int fseek (stream, offset, origin);
FILE * stream; //покажчик на структуру FILE,
long offset; //число байтів від origin,
int origin; //початкова позиція.
Функція fseek() переміщає покажчик, відповідний потоку stream, на нове
місце розташування, віддалене від origin на offset байтів. Наступна операція в
потоці виконується над новим місцерозташуванням. Якщо потік відкритий для
оновлення, то наступною операцією буде або читання, або запис. Аргумент
origin може бути однією з наступних констант, визначених в <stdio.h>.
ORIGIN                                                     ВИЗНАЧЕННЯ

SEEK-SET                    початок файла.

SEEK-CUR                   поточна позиція покажчика на файл.

SEEK-END                   кінець файла.

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

Функція fseek() повертає значення 0, якщо покажчик успішно переміщений. У разі помилки повертається будь-яке ненульове значення. Для пристроїв, не сумісних з операцією seek, (таких як термінал і принтер), значення, що повертається, невизначено.


REWIND().

 

#include <stdio.h>

void rewind(stream);

FILE * stream;   //покажчик на структуру FILE.

Функція rewind() переміщає покажчик на файл, пов'язаний з потоком stream, до початку файла.

 

Читання і запис у файл.

 

FWRITE() і FREAD().

 

Функція fwrite() записує двійкові дані у файл. Повертає кількість успішно записаних блоків.

Функція fread() читає дані з двійкового файла і повертає число успішно прочитаних блоків.

Для читання і запису в текстовий файл застосовуються всі вивчені раніше функції введення/виведення, до яких як префікс додається буква/, вказуюча на роботу з файлом і першим аргументом в них виступає ім'я файла (потоку). Наприклад: fscanf(), fputs(), fprintf() та інші.


Введення.

Мова Сі і Турбо Сі. Достоїнства і недоліки.

 

Мова Сі була створена в 1972 р. співробітником фірми Bell Laboratories Деннісом Рітчи, коли він і Кен Томпсон займалися розробкою ОС UNIX. Проте мова Сі не виникла на порожньому місці. Вона з'явилася від розробленої Томпсоном мови В. Важньїм моментом є те, що мова Сі була створена як інструмент для працюючих програмістів, тому головна мета розробки цієї мови програмування полягає в тому, щоб її застосування було корисним при розробці різних програм.

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

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

 

Еволюція мови програмування Сі.

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

В 90-ті роки велика кількість фірм по розробці ПЗ для виконання великих програмних проектів перейшли на мову C++. Мова C++ - це мова Сі, до якої додали засоби об'єктно-орієнтованого програмування. Мова програмування C++ є, практично, розширенням мови Сі.

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

Ця мова побудована так, що дозволяє користувачам природним чином застосовувати програмування «зверху-вниз», структурний підхід і модульне проектування програм. В результаті виходять більш надійні і зрозумілі програми.

Турбо Сі

 

В грудні 1986 p. невелика компанія під назвою Wigard Software Systems Inc. оголосила про свій переїзд з міста Армінгтон, штат Массачусетс, в місто Монте Серено, штат Каліфорнія. Ця компанія створила і почала продаж компілятора Сі вартістю 450 доларів під назвою Wizard С.

Wizard С був компілятором, заслуговуючим пошани, завжди одержуючим хороші відгуки в оглядах і навіть названий, принаймні одним з оглядачів, «кращим» компілятором Сі. Його достоїнства полягали у високій швидкості компіляції, ефективної оптимізації одержуваного коду, відповідності вимогам стандарту ANSI і великому числі розширень мови, дозволяючих розробляти програми обробки переривань. Ці розширення містили в собі функцію переривання спеціального типу, можливість вбудовування в тіло програми фрагментів на мові асемблера, псевдозмінни, за допомогою яких з мови Сі виконується доступ до регістрів мікропроцесора.

В лютому 1987 р. фірма Borland International з Скоттс-Веллей, штат Каліфорнія, оголосила про створення компілятора Турбо Сі, який очікувався з нетерпінням після появи його попередника, дуже вдалого компілятора Турбо Паскаль.

В тому ж місяці Wizard зробила своє останнє оголошення. В травні 1987 р. з'явилася версія 1.0 Турбо Сі (спільно з T-shirts), який подавив всіх своїми характеристиками.

Насправді фірма Borland International придбала фірму Wigard Systems для того, щоб створити Турбо Сі. Промисловість робила припущення про те, коли Borland вийде на ринок компіляторів Сі, після того, як вона вже представила свої вироби: Турбо Паскаль, а вслід за ним дуже популярний Турбо Бейсік. Замість того, щоб робити великі зусилля, починаючи з нуля, фірма Borland ухвалила мудре рішення: вона купила кращий компілятор Сі і сконцентрувала зусилля на тому, щоб зробити його ще краще.

На момент анонсування фірмою Borland свого компілятора на ринку було представлено 17 компіляторів Сі для IBM PC. Після публікації інформації про Турбо Сі багато хто сумнівався, небагато мали уявлення про нього, але всі жадали побачити його на власні очі. Мир Сі був готовий прийняти ще один компілятор, за умови, що він поступить від Borland. Сам цей стан очікування мав дуже велике значення. Фірма Borland почала справу не для того, щоб створити черговий компілятор Сі; Borland поставила за мету змінити уявлення про те, як повинне виглядати програмне середовище для розробки програм на мові Сі.

Турбо Сі позначає два програмні вироби: пакет програм, забезпечуючий виконання послідовності команд в стилі Unix: make/compiler/linker, і інтегроване програмне середовище для розробки програм.

Пакет програм містить утиліту make, компілятор tec і компонувальник, що настроюється. Компілятор, що входить в пакет, схожий на більшість інших компіляторів Сі для IBM PC, але є більш швидким.

Інтегроване програмне середовище є програмою під назвою tc, яка об'єднує в собі текстовий редактор, орієнтований на створення текстів програм на мові Сі, будівник задач, орієнтований на реалізацію програмного проекту, і утиліти виконання програм.

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

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

- модель пам'яті: крихітна, мала, середня, компактна, велика, величезна;

- угода про функції, що викликаються - Сі або Паскаль;

- плаваюча арифметика;

- рівень оптимізації;

- рівень контролю за помилками.

Можна вибирати і більше число параметрів Турбо Сі. Турбо Сі здатний здійснювати строгий контроль за помилками і підозрілими місцями в програмі і видавати застережливі повідомлення.

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


Дата добавления: 2019-02-13; просмотров: 213; Мы поможем в написании вашей работы!

Поделиться с друзьями:




Мы поможем в написании ваших работ!