· Вступ
· Вирази, операції, стандартні функції
· Задання значень змінних, оператор присвоєння
· Виведення значень на екран дисплею
· Об'єднання, бітові поля. Двійкова і шістнадцяткова системи числення
· Операції із комплексними змінними у Сі++
· Функції роботи з графікою у Сі
· Використання вказівників на змінні для імітації процедур
· Робота з файлами в Сі. Стандартні файли
· Додавання до тексту програми текстів із файлів
· Основні етапи створення і виконання програм на ЕОМ
· Додатки
Мову програмування Сі створив Денісом Ритчі (Dennis Ritshie) з компанії AT&T Bell Labs у 1970 р. Основна мета
автора полягала у створенні простої і ефективної мови програмування, яка дає змогу розширювати свої можливості
шляхом використання бібліотечних процедур, зокрема можна використовувати бібліотеки програм, написаних
іншими мовами програмування ( Паскаль, Фортран тощо). Показником ефективності мови Сі може бути
співвідношення між розміром тексту програми, записаної мовою Сі, та розміром відтрансльованого
(перекладеного у машинні команди) модуля — близько 1/2. Унаслідок цього Сі забезпечує високу швидкодію
виконуваних модулів. Розширення Сі засобами об’єктно-орієнтованого програмування (Б.Старуструп) відоме
під назвою С++.
Мова програмування Сі є знаковою, тобто всi вирази i конструкції мови складаються зі знакiв, якi містить алфавiт Сі. Алфавiт
Сі охоплює:
букви латинського алфавiту — A, B, C, D, E, F...Z, a, b, c, d, e, f, …z;
десяткові цифри — 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
спеціальні символи . , “ [ ] ( ) { } + - / % \ ; : ? < = > ~ ^ & * # , символ прогалини тощо.
Із символів складаються базові елементи мови — лексеми. У Сі є шість типів лексем:
ідентифікатори;
ключові слова;
константи;
рядки;
роздільники;
знаки операцій.
Ідентифікатор — це послідовність букв, цифр і символів підкреслення, яка починається з букви. Її використовують
для позначення різних об’єктів: змінних, констант, функцій тощо. Ідентифікатори, які використовують для позначення
конструкцій мови, називають ключовими словами:
позначення типів даних – char, int, float,
double, union, long, short, unsigned, enum, typedef, struct, void;
позначення класів пам’яті — auto, extern,
static, register;
модифікатори видимості — private, protected, public;
позначення операторів та їх складових частин — break case continue
default do else for goto if return switch while.
Ключові слова
asm |
auto |
|||
const
cast |
||||
default |
delete |
|||
dynamic_cast |
explicit |
export |
||
friend |
||||
inline |
||||
mutable |
namespace |
new |
operator |
|
register |
reinterpret_cast |
|||
static
cast |
||||
template |
||||
typedef |
typeid |
typename |
||
using |
||||
volatile |
wchar
t |
|
|
Загальну структуру програми мовою Сі можна зобразити так:
# include <stdio.h>
.
.
.
# include <ім’я бібліотечного файла>
void main()
/* службове слово void перед main означає, що програма не передає значень*/
{ /* аналог службового слова Паскалю Begin */
описи змінних;
виконувані оператори(команди);
} /* аналог службового слова Паскалю End. */
Конструкція типу /* пояснювальний текст */ є коментарем. Змінні описують до їхнього використання, найкраще
це робити на початку програми.
Арифметичнi вирази у Сі, як i в математицi, складаються з чисел (констант), iмен змiнних, імен функцій, знакiв
арифметичних операцiй i дужок. Числові константи можна записувати у виглядi цiлої i дробової частини числа,
десятковою крапкою (цілі константи записують без дробової частини). Кiлькiсть цифр у числi — не бiльше 12.
Наприклад:
-7.58
10345.7563
0.0000347
Дiапазон чисел, якi можна записати у такий спосіб, невеликий — вiд 0.00000000001 до 999999999999.
Для розширення дiапазону чисел у Сі використовують форму запису чисел з плаваючою крапкою:
знак(+або-)числоEзнак (+ або -)число.
Наприклад:
34.578E23 — що означає 34.578 * 1023
2.1268E-19 — що означає 34.578 * 10-19
-7.4588E21 — що означає -7.4588 * 1021
Для позначення iмен змiнних використовують ідентифікатори, які не повинні збігатися з ключовими словами
та іменами функцій.
Виконуючи обчислення на ЕОМ, ми можемо мати справу з рiзними числовими значеннями.
Довжина числа (кiлькiсть знакiв у числi) впливає на розмiр областi пам’ятi, необхiдний для зберiгання цього числового
значення. У Сі передбачено такі базові типи змінних:
Тип |
Ім’я типу |
Розмір(байт) |
Діапазон значень |
Цілі |
int |
2 або 4 |
див.далі |
short int |
2 |
від -32768 до 32767 |
|
long int |
4 |
від -2 147 483 648 до 2 147 483 647 |
|
Беззнакові цілі |
unsigned int |
2 або 4 |
див.далі |
unsigned short |
2 |
від 0 до 65535 |
|
unsigned long |
4 |
від 0 до 4 294 967 295 |
|
unsigned char |
1 |
від 0 до 255 |
|
Дійсні(плаваючі) |
float |
4 |
3.14*10-38— 3.14*1038 |
double (long float) |
8 |
1.7*10-308 — 1.7*10308 |
|
Символьні |
char |
1 |
від -128 до 127 |
Логічні |
bool |
1 |
true, false |
Кількість байтів, які відводять під цілі змінні, залежить від довжини машинного
слова (визначається мікропроцесором, який встановлений у системному блоці). Для визначення розміру у
байтах цілої змінної можна скористатись функцією sizeof, наприклад
a = sizeof(int);
b = sizeof(long int);
c = sizeof(unsigned long);
d = sizeof(short);
Розглянемо приклад опису змiнних:
float x,y;
int i; char
v;
Крім скалярних змінних (з одним значенням) у Сі можна використовувати масиви (індексовані змінні), які дають
змогу зберігати під одним іменем багато значень. Розглянемо приклади описів масивів:
int a[2][3]; /* ціла матриця з двох рядків і трьох стовпців */
double b[10]; /* вектор з 10 елементів типу double */
int w[3][3] = { { 2, 3, 4 },
{ 3, 4, 8 },
{ 1, 0, 9 } };
Останній приклад опису масиву w містить, окрім опису, задання (ініціалізацію) числових значень масиву.
Конструкція enum
enum [<ім’я множини>] { <назва константи> [=<значення>] } [список змінних]
, де
<ім’я множини> - опціональне ім’я множини
<назва константи> - ім’я елементу множини якому можна присвоїти певне цілочисельне значення
Вирази, операції, стандартні функції
Вирази описують процеси породження значень застосуванням операцій над іншими
значеннями (константами, змінними, значеннями функцій). У Сі вирази поділяють на:
арифметичні;
відношення;
логічні;
присвоювання.
Вирази складаються з операцій і операндів. Операндами можуть бути константи, змінні,
вирази в дужках та значення, які повертаються функціями. За кількостю операндів, які використовують
в операції, їх (операції) поділяють на унарні, бінарні і тернарні.
Унарні операції:
- зміна знаку;
~ побітове логічне заперечення (доповнення);
! логічне заперечення;
* розадресація (непряма адресація);
& обчислення адреси;
+ унарний плюс;
++ збільшення (інкремент);
-- зменшення (декремент);
sizeof розмір .
Унарні операції виконуються справа наліво. Операції збільшення і зменшення змінюють значенння
операнда на одиницю. Їх можна записати як справа, так і зліва від операнда. Якщо знак операції
розміщений перед операндом (префіксна форма), то зміна операнда відбувається до його використання
у виразі. Якщо знак операції розміщений після операнда (постфіксна форма), то операнд спочатку
використовується у виразі, а потім змінюється його значення. Наприклад:
префіксна форма постфіксна форма
int i,j; int i,j;
i=1; i=1;
j=++i; j=i++;
тут i=2,j=2 тут i=2,j=1(спочатку використано значення i=1, післо чого виконано збільшення значення i на 1).
Бінарні операції поділяють на:
арифметичні операції
+ додавання
- віднімання
* множення
/ ділення
% залишок при діленні цілих чисел
логічні операції
! заперечення
¦¦ логічне “або”
&& логічне “і”
¦ побітове “або”
& побітове “і”
операції відношення
< менше
> більше
== дорівнює
!= не дорівнює
<= менше або дорівнює
>= більше або дорівнює
Бінарні операції виконуються зліва направо з урахуванням пріоритету виконання операцій.
Пріоритет виконання арифметичних операцій такий самий, як в алгебрі (лише до операцій множення
і ділення додається операція обчислення залишку від ділення). Для зміни порядку виконання операцій
використовують круглі дужки. Як уже було зазначено на початку цього розділу, вирази в дужках
обраховуються у першу чергу. Варто зауважити, що зайві дужки, наприклад a+(18*x+12*y),
ігноруються компілятором. Тип виразу і породжуваного ним значення визначається за операціями та
типами операндів у виразі.
Розглянемо приклади виразів:
(x+5/(z-3*sin(q-2.4)) — арифметичний вираз;
x*x+y*y<=1 — вираз відношення.
Тернарна операція (лише одна) має вигляд:
Змінна = вираз1 ? вираз2: вираз3;
Виконання цієї операції можна задати алгоритмом:
ЯКЩО вираз1 =0 ТО змінна=вираз2 ІНАКШЕ змінна=вираз3.
Розглянемо приклад:
/* визначення більшого з двох значень (a b) і присвоєння його змінній max*/
max=(a<=b)? b:a;
Для вирахування числових значень елементарних функцiй у програмах, записаних мовою Сі,
потрібно під’єднати бібліотечний файл із програмами обчислення цих функцій
( у заголовку програми вставити рядок # include <math.h>
[для операцій з комплексними значеннями — # include <complex.h>]). Розглянемо ці функції:
абсолютне значення
abs — для цілих значень
fabs, fabsl — для дійсних значень
cabs, cabsl — для комплексних значень
labs — для дійсних значень
округлення значень
ceil, ceill — найближче ціле, але не менше аргумента функції
floor, floorl — найближче ціле, але не більше аргумента функції
тригонометричні функції (аргумент задається у радіанах!)
sin,
sinl — синус
cos,
cosl — косинус
tan,
tanl — тангенс
зворотні тригонометричні функції
asin,
asinl — арксинус
acos,
acosl — арккосинус
atan,
atanl — арктангенс
atan2(x,y), atan2l — арктангенс відношення x/y
гіперболічні функції
sinh,
sinhl — гіперболічний синус {sinh(x) =(exp(x)-exp(-x))/2}
cohs, coshl
— гіперболічний косинус {cosh(x)
=(exp(x)+exp(-x))/2}
tanh, tanhl
— гіперболічний тангенс {tanh(x)
=sinh(x)/cosh(x)}
зворотні гіперболічні функції
asinh, asinl
— арксинус гіперболічний
acos, acosl
— арккосинус гіперболічний
atan, atanl
— арктангенс гіперболічний
показникові і логарифмічні функції
exp,
expl — експонента { для комплексного аргумента exp(z) = exp(Rez)*(cos(Imz)+jsin(Imz)),
тут Rez — дійсна частина комплексного значення, Imz — уявна частина комплексного значення}
log, logl — натуральний логарифм
log10,log10l — десятковий логарифм
pow10(p),
pow10l — 10**p
pow(x,y),
powl — x**y
sqrt,sqrtl — корінь квадратний
Задання значень змінних, оператор присвоєння
Основним способом задання значень змiнних є оператор присвоєння, який можна записати так:
ім’я змiнної= вираз;
Наприклад
w= (x-y)/(z+5);
sq=
f+(r+s)/(d+7);
d=sqrt(sqr(a)+sqr(b));
day=”понедiлок”;
q=’y’;
Оператор присвоєння
x=x*0.2;
можна прочитати так:
змiннiй х надається (присвоюється) значення рiвне добутку попереднього значення х на 0.2.
Тепер ми взнали досить для того, щоб написати першу програму мовою Сі. Напишемо програму
вирахування значення функції:
y = 5sin(x-3)+v(z+7)
при x=5.9, z=2476.89. Для порівняння зліва розмістимо текст аналогічної Паскаль-програми
Program
one;
# include <stdio.h>
Var x,y,z:Real;
void main() {
Begin
float x,y,z;
x:=5.9;
x=5.9;
z:=2476.89;
z=2476.89;
y:=5*sin(x-3)+sqrt(z+7);
y=5*sin(x-3)+sqrt(z+7);
End.
}
Окрім команди присвоєння типу
iм’я змiнної= вираз;
в Сі можливі ще й такі форми операторів присвоєння:
zm+= вираз; що означає «нове значення zm =старе значення zm+вираз”
zm-= вираз; що означає «нове значення zm =старе значення zm-вираз”
zm*= вираз; що означає «нове значення zm =старе значення zm*вираз”
Наприклад
x+=0.2; /*нове значення x рівне попередньому значенню x +0.2 */
x-=0.2; /*нове значення x рівне попередньому значенню x -0.2 */
x*=0.2; /*нове значення x рівне попередньому значенню x *0.2 */
x/=0.2; /*нове значення x рівне попередньому значенню x /0.2 */
double a[4]={ 2.0, 3.3, 5.2, 7.5 } ;
double b=3.0;
b+=a[2];
/* еквівалентно b=b+a[2] тобто b=3.0+3.3 */
a[3]/=b+1;
/* еквівалентно a[3]=a[3]/(b+1) */
Виведення значень на екран дисплею
Основним способом задання значень змiнних є оператор присвоєння, який можна записати так:
ім’я змiнної= вираз;
Наприклад
w= (x-y)/(z+5);
sq=
f+(r+s)/(d+7);
d=sqrt(sqr(a)+sqr(b));
day=”понедiлок”;
q=’y’;
Оператор присвоєння
x=x*0.2;
можна прочитати так:
змiннiй х надається (присвоюється) значення рiвне добутку попереднього значення х на 0.2.
Тепер ми взнали досить для того, щоб написати першу програму мовою Сі. Напишемо програму
вирахування значення функції:
y = 5sin(x-3)+v(z+7)
при x=5.9, z=2476.89. Для порівняння зліва розмістимо текст аналогічної Паскаль-програми
Program
one;
# include <stdio.h>
Var x,y,z:Real;
void main() {
Begin
float x,y,z;
x:=5.9;
x=5.9;
z:=2476.89;
z=2476.89;
y:=5*sin(x-3)+sqrt(z+7);
y=5*sin(x-3)+sqrt(z+7);
End.
}
Окрім команди присвоєння типу
iм’я змiнної= вираз;
в Сі можливі ще й такі форми операторів присвоєння:
zm+= вираз; що означає «нове значення zm =старе значення zm+вираз”
zm-= вираз; що означає «нове значення zm =старе значення zm-вираз”
zm*= вираз; що означає «нове значення zm =старе значення zm*вираз”
Наприклад
x+=0.2; /*нове значення x рівне попередньому значенню x +0.2 */
x-=0.2; /*нове значення x рівне попередньому значенню x -0.2 */
x*=0.2; /*нове значення x рівне попередньому значенню x *0.2 */
x/=0.2; /*нове значення x рівне попередньому значенню x /0.2 */
double a[4]={ 2.0, 3.3, 5.2, 7.5 } ;
double b=3.0;
b+=a[2];
/* еквівалентно b=b+a[2] тобто b=3.0+3.3 */
a[3]/=b+1;
/* еквівалентно a[3]=a[3]/(b+1) */
Сі має три форми команди циклу:
цикл з попередньою умовою
while (логічний вираз)
{тiло циклу
};
Якщо логічний вираз істинний (значення 1), то команди, які входять у тіло циклу, виконуються.
Коли ж логічний вираз хибний (значення 0), то команди, які входять у тіло циклу, не виконуються.
Розглянемо приклад:
a=-5;
b=5;
x=a;
while
(x<=b)
{
y=sin(x);
printf(“ x= %f
y= %f \n”,x,y);
x=+0.2;
}
У цьому циклі послідовно обчислюється значення функції sin(x) для значень аргумента
з ряду -5, -4.8, -4.6 …5. Виконання циклу припиняється, як тільки значення x стане
більшим 5 (логічний вираз x<=b стане хибним).
цикл з післяумовою:
do
{тiло циклу
}
while (логічний вираз);
Команди, які входять у тіло циклу, виконуватимуться щонайменше один раз. Далі,
якщо логічний вираз істинний (значення 1), то команди, які входять у тіло циклу, виконаються
ще раз. Коли ж логічний вираз хибний (значення 0), то виконання циклу припиняється. Запишемо
попередній приклад з використанням циклу do - while :
a=-5;
b=5;
x=a;
do
{
y=sin(x);
printf(“ x= %f
y= %f \n”,x,y);
x=+0.2;
}
while (x<=b);
Правила запису логічних виразів у Сі розглянемо далі. Зараз розглянемо, що означає
термiн "тiло циклу". Тiлом циклу може бути будь-який виконуваний оператор Сі, або їхня сукупнiсть.
Ще одна форма команди циклу має вигляд:
параметричний цикл
For (вираз1; умова; вираз2)
{ тіло циклу};
вираз1 визначає дії, які проводяться до виконання циклу (тут може бути кілька виразів,
розділених комами), умова задає умови продовження виконання циклу (умова істинна —
цикл продовжується, хибна — виконання циклу припиняється), вираз2 задає метод зміни
параметрів та змінних циклу. Розглянемо приклад:
arg=-5;
n=20;
for (i=1;
i<=n; i++)
{
y[i]=sin(arg);
x[i]=
arg;
arg=+0.05;
}
У цьому прикладі змінна циклу і перед виконанням циклу набуває значення 1.
Цикл виконується, поки i<=n , при кожному виконанні тіла циклу значення змінної і збільшується на одиницю.
Логічні вирази (умови) можуть бути простими або складеними. Просту умову записують
як операцiю вiдношення, у якiй значення двох виразiв порiвнюються мiж собою.
Для запису операцiй вiдношення використовують позначення (у цих прикладах z=7):
Операцiя відношення |
Позначення |
Приклад |
Значення |
дорівнює |
== |
(z==7) |
1 |
менше |
< |
(z<5) |
0 |
більше |
> |
(z>6) |
1 |
не дорівнює |
!= |
(z!=2) |
1 |
менше або дорівнює |
<= |
(z<=7) |
1 |
більше або дорівнює |
>= |
(z>=6.5) |
0 |
Як видно з таблицi значенням умовних виразiв може бути 1 (True — iстина)
або 0 (False — не iстина). Зверніть увагу — умовний вираз обов’язково виділяють
дужками. Складенi умовні вирази утворюються шляхом об’єднання простих за допомогою дужок та логiчних операцiй :
&& — логiчне i;
¦¦ — логiчне або;
! — логiчне не .
Наприклад:
((x>7) && (y/x<=5))
((z-x==12) ¦¦ (r>0.3))
Операцiя ! перетворює значення 1 (True) у значення 0 (False) i навпаки. Навчитися правильно складати логічні вирази є надзвичайно важливо не лише для опрацювання числової інформаці, а й для пошуку інформації (напр. у мережі Інтернет).
Розглянемо приклад використання складних
логічних виразів та оператора
ЯКЩО. Нехай ми маємо такий сигнал:
|
|
|
|
Рис.3.21. Графік сигналу, заданого складним виразом (файл )
Обчислення значення цього сигналу можна здійснити за допомогою таких операторів Сі:
if
((t>0)&&(t<=0.02)) s=5*t/0.02;
if
((t>0.02)&&(t<=0.06)) s=5.0;
if ((t>0.06)&& (t<=0.08)) s=5 -
5*(t-.06)/.02;
if ((
t>0.08)&& (t<=0.16)) s=7.0*sin(2*Pi*t/.16);
Для об'єднання в одне ціле різнорідної інформації у мові Сі використовують структури . Опис структури має вигляд:
struct ім'я_структурного_ типу {визначення елементів} список_структур;
Такий опис вводить похідний об'єднуючий тип змінних — тобто тип змінних, який побудований на базових типах змінних (float, int, char і т.ін.). Розглянемо програму з прикладом структури, яка об'єднує у собі масив значень функції, проміжок табуляції і кількість точок табуляції.
#include
<stdio.h>
#include
<math.h>
#include
<conio.h>
#include
<dos.h>
void main()
{
float dx,r;
int i;
struct tabul
{float x[50],y[50];
float xp,xk;
int n;
} pryklad;
pryklad.xp=-5.0; pryklad.xk=5.0;
pryklad.n=20;
dx=(pryklad.xk-pryklad.xp)/pryklad.n;
r=pryklad.xp;
for (i=0;
i<=pryklad.n;i++)
{
pryklad.x[i]=r;
pryklad.y[i]=sin(r);
r+=dx;
printf(" x= %f y=
%f\n",pryklad.x[i],pryklad.y[i]);
}
getch();
}
У цій програмі введено структуру
struct tabul
{float x[50],y[50];
float xp,xk;
int n;
}
pryklad;
тут tabul — ім'я структурного типу, pryklad — ім'я змінної цього типу. До складу структури входять компоненти:
масиви — float x[50],y[50];
скалярні змінні — float xp,xk; int n;
Доступ до конкретної компоненти структури здійснюють через вказання імен структури і компоненти, наприклад:
pryklad.xp=-5.0;
pryklad.n=20;
pryklad.x[i]=r;
pryklad.y[i]=sin(r);
Змінні структурного типу можна описувати і таким чином:
1) спочатку описують структурний тип;
2) потім описують змінні цього типу.
Наприклад:
struct tabln
{float x[50],y[50];
float xp,xk;
int n;};
тут описано структурний тип tabln з п'ятьма компонентами. Змінні цього новоствореного типу можна описати так:
tabln prykl;
тут prykl є змінною типу tabln.
Ще один метод опису структур побудований
на використанні службового слова typedef. Розглянемо приклад
typedef struct
{char processor[10];
int
frequency;
int
memory;
int hdd;}comp;
тут описано структурний тип comp. Наступний рядок вводить три змінні цього типу:
comp eom1, eom2, eom3;
Компоненти змінних типу comp можна задати так:
eom1.processor="I80486DX4";
eom1.frequency=100;
eom1.memory=16;
eom1.hdd=40;
eom2.processor="K6-2+";
eom2.frequency=450;
eom2.memory=128;
eom2.hdd=4300;
У цьому прикладі змінна eom1 задає параметри ЕОМ з процесором I80486DX4 і
тактовою частотою 100МГц., оперативною пам'яттю 16Мб і жорстким магнітним
диском 40Мб, а змінна eom2 задає параметри ЕОМ з процесором K6-2+ і тактовою частотою
450МГц., оперативною пам'яттю 128Мб і жорстким магнітним диском 4.3Гб.
Об'єднання, бітові поля. Двійкова і шістнадцяткова системи числення
На відміну від структур, які під одним іменем містять різнорідну інформацію (кожна компонента
має свій тип і для неї відводять потрібну кількість байт пам'яті), об'єднання забезпечують різне
подання однієї і тієї самої ділянки пам'яті. Розглянемо приклад:
union
{ char b[2];
int i;
} pr_un;
тут задано об'єднання двох компонент — цілої i та символьного масиву b[2]. Оскільки обидві
компоненти розміщені у одній тій самій ділянці пам'яті (2 байти), то b[0] містить у собі молодший
байт змінної i, а b[1] - старший байт змінної i. Ще однією дуже корисною властивістю структур
і об'єднань є можливість використання бітових полів — компонентами структур і об'єднань може
бути бітове поле заданої ширини. Для прикладу розглянемо використання бітових полів для перетворення
послідовності бітів на цифровому виході вольтметра В7-16А у змінну типу float. Результати
вимірювань цифрового вольтметра В7-16А (з роботою цифрового вольтметра ви познайомитесь у загальному
лабораторному практикумі з фізики) індикуються чотиризначним десятковим числом, для кожного
десяткового розряду на вихідному рознятті вольтметра відведено чотири сигнальних лінії (двійкових розряди).
Нижче подана відповідність між десятковим числом одного розряду і двійковим кодом (двійково-десятковий код)
0 — 0000, 5 — 0101,
1 — 0001, 6 — 0110,
2 — 0010, 7 — 0111,
3 — 0011, 8 — 1000,
4 — 0100, 9 — 1001.
Для введення в IBM-подібну ПЕОМ цифрової інформації використовують порти
вводу-виводу (з портами вводу-виводу ви ознайомитесь у курсах "Основи цифрової
і мікропроцесорної техніки" та "Автоматизація фізичного експерименту").
Одним із засобів роботи з портами вводу-виводу мови Сі є функції
in(номер_порта) — читання двійкового восьмибітного коду з порта з заданим номером,
out(номер_порта) — вивід двійкового восьмибітного коду у порт із заданим номером.
Після читання двійкової інформації з порта інструкцією in ви отримаєте беззнакове
ціле значення (unsigned char). Наступна програма аналізує введені два байти (v7_16b1,v7_16b2)
і перетворює їх у результат вимірювання (змінна rezult) з урахуванням заданої межі
вимірювань (перемикачем на передній панелі вольтметра або за допомогою дистанційного керування).
Об'єднання v7_16 має три компоненти:
беззнакову байтову vymir;
та дві беззнакові чотирибітні c1,c2.
Для задання байтів використовуємо оператор присвоєння з шістнадцятковою константою
(шістнадцяткові константи починаються з символів 0X). Наберіть і виконайте цю програму:
# include
<stdio.h>
# include
<math.h>
# include
<conio.h>
# include
<dos.h>
void main ()
{
float rezult;
union
{
unsigned char
vymir;
struct
{
unsigned char
c1:4;
unsigned char
c2:4;
} vv_byte;
}v7_16b1,v7_16b2;
/* задаємо перший байт результата вимірювання 97 */
v7_16b1.vymir=0X97;
/* задаємо другий байт результата вимірювання 56 */
v7_16b2.vymir=0X56;
/* обчислюємо результат з урахуванням межі вимірювання 1В */
rezult=v7_16b2.vv_byte.c2*0.1+v7_16b2.vv_byte.c1*0.01+v7_16b1.vv_byte.c2*0.001+v7_16b1.vv_byte.c1*0.0001;
printf(" rezult= %f
\n", rezult);
getchar();
}
Операції із комплексними змінними у Сі++
Комплексну арифметику широко використовуєть при дослідженні коливних процесів, радіоелектронних і радіотехнічних пристроїв.
Мова програмування Сі++ має широкий спектр засобів для роботи з комплексними змінними, розглянемо частину з них.
Для використання змінної, яка матиме своїм значенням комплексне число, у рядку опису потрібно зазначити
complex <ім'я змінної>;
наприклад,
complex z(1.0, 2.1), z1, z2;
Тут описано три комплексні змінні — z, z1, z2. Значення змінної має дійсну частину, яка дорівнює 1, та уявну 2.1 (ініціалізація під час опису).
Усі функції модуля math.h, які означені у полі комплексних чисел, можна використовувати у програмах із коплексними змінними.
Розглянемо кілька простих програм із комплексними змінними (призначення функцій, які використані у цих програмах, подано у коментарях).
Змінні, які отримують (або задають) значення модуля, аргумента, дійсної або уявної частини комлексної змінної повинні мати тип double.
Як приклад розглянемо програму виділення дійсної та уявної частини комплексного числа, обчислення його модуля та аргумента і
задання комплексного числа через модуль і аргумент:
#include
<stdio.h>
#include
<math.h>
#include
<complex.h>
void main()
{
complex z(1.0,
2.0),z1,z2; /* опис комплексних змінних */
double mz,x,y,fi;
mz =
abs(z); /* обчислення модуля комплексної змінної z */
printf("IzI=
%f\n", mz);
x=real(z); /* виділення дійсної частини комплексної змінної z */
y=imag(z); /* виділення уявної частини комплексної змінної z */
printf("Rez=
%f\n", x);
printf("Imz=
%f\n", y);
/* задання комплексної змінної z1 через дійсну та уявну частини */
z1=complex(x,y);
mz = abs(z1);
printf("Iz1I=
%f\n", mz);
fi=arg(z1); /* обчислення аргумента комплексної змінної z1 */
printf("fi=
%f\n", fi);
/* задання комплексної змінної z2 через модуль і аргумент */
z2=polar(mz,fi);
mz = abs(z2);
printf("Iz2I=
%f\n", mz);
}
У курсі електрики (який ви зараз вивчаєте) для опису електричних кіл змінного струму використовують комплексні опори
основних компонент електричного кола:
ємності — Zc-=1/ (Zc-=1/ (i*w*C);
індуктивності — ZL-=i*w*L;
резистора — ZR-=R.
Тут i — уявна одиниця, w — колова частота напруги, яка діє на коло, C, L, R — величини ємності, індуктивності і опору.
Після уведення комплексних опорів кола змінного струму розраховують так само, як кола постійного струму.
Розглянемо програму табуляції модуля комплексного коефіцієнта передачі RC-кола (коефіцієнт передачі кола рівний відношенню
вихідної напруги кола до вхідної), яке зображено на рис. 3.22а.
#include
<stdio.h>
#include
<math.h>
#include
<complex.h>
void main()
{
complex
z1,z2,k;
double mk,r,c,w;
r=5000;
c=1e-6;
w=0.1;
/* задання комплексного опору резистора R */
z1=complex(r,0);
while
(w<=1000)
{
/* задання комплексного опору ємності C */
z2=complex(0,-1.0/(w*c));
/* обчислення комплексного коефіцієнта передачі кола */
k = z2/(z1+z2);
/* обчислення модуля комплексного коефіцієнта передачі кола */
mk=abs(k);
printf("w=
%f IkI= %f\n",w,mk);
w=w+50;
}
}
|
|
|
|
|
|
|
|
|
|
|
а)
б)
Коло змінного струму (а — з опором і ємністю, б- із комплексними опорами Z1, Z2)
З використанням комплексних опорів Z1, Z2 відношення вихідної напруги кола до вхідної обчислюємо як
K=Uвих/Uвх; Uвих =I*Z2; I= Uвх /(Z1+Z2)
Остаточно
K=Z2 /(Z1+Z2).
Аналогом процедур-функцій та процедур загального виду у Паскалі (підпрограм у багатьох
інших мовах програмування, наприклад Fortran, Basic) у мові Сі є функції. Кожна програма,
написана мовою Сі, зазвичай є сукупністю функцій. Одна з них є обов'язковою — функція main,
інші додаються за потреби. Розглянемо правила написання функцій. Після прийняття стандарту
ANSI у мові Сі діє два варіанти опису і визначення функцій:
стандартний;
"достандартний", який збережено для того, щоб була можливість використання програм та підручників,
написаних до прийняття стандарту ANSI.
Розглянемо структуру стандартного опису функції:
тип_результату ім'я_функції(список_формальних_параметрів)
{
опис об'єктів;
виконувані оператори;
}
Розглянемо обчислення середнього значення результатів вимірювання за допомогою функції.
float seredne(int n,
float x[]);
{
int i;
float r;
r=0;
for
(i=0;i<n;i++)
r=r+x[i];
r=r/n;
return r;
}
У наступній програмі обчислюємо середнє значення вимірювання довжини d.
#include
<stdio.h>
#include
<conio.h>
float seredne(int n,
float x[]) /* заголовок функції */
{
float r;
int i;
r=0;
for
(i=0;i<n;i++)
r+=x[i]; /* аналог r=r+x[i]; */
r/=n; /* аналог r=r/n; */
return r; /* передача отриманого значення за іменем функції */
}
void main()
{
/* опис і ініціалізація масиву d */
float
d[]={2.07,2.1,2.12,2.2,2.08,2.13,2.03,2.11,2.15};
float
ser_zn_vym;
ser_zn_vym=seredne(9,d); /* виклик функції */
printf(" середнє значення=
%f\n",ser_zn_vym);
getch();
}
Доповнимо цю програму функцією обчислення середньоквадратичного відхилення.
Внаслідок цього отримаємо програму статистичної обробки результатів експерименту з двома функціями:
float
seredne(int n, float x[])
float
ser_kw_vidhyl(int n, float x[], float sz).
#include
<stdio.h>
#include
<math.h>
#include
<conio.h>
float seredne(int n,
float x[])
{
float r;
int i;
r=0;
for
(i=0;i<n;i++)
r+=x[i]; /* r=r+x[i]; */
r/=n; /*
r=r/n; */
return r;
}
float ser_kw_vidhyl(int
n, float x[], float sz)
{
float r,sum;
int i;
sum=0;
for
(i=0;i<n;i++)
r=x[i]-sz;
sum+=r*r;
/* sum=sum+r*r; */
r=sqrt(sum/(n*(n-1)));
return r;
}
void main()
{
/* опис і ініціалізація масиву d */
float
d[]={2.07,2.1,2.12,2.2,2.08,2.13,2.03,2.11,2.15};
float
ser_zn_vym,skw;
/* виклик функції обчислення середнього значення */
ser_zn_vym=seredne(9,d);
printf(" середнє значення=
%f\n",ser_zn_vym);
/* виклик функції обчислення середньоквадратичного відхилення */
skw=ser_kw_vidhyl(9,d,ser_zn_vym);
printf(" середньоквадратичне відхилення= %f\n",skw);
getch();
}
У цій програмі для статистичної обробки результатів експерименту використані дві
функції з тієї причині, що одна функція може повернути у викликаючу програму лише одне
значення (тобто функція у Сі є аналогом процедури-функції Паскалю). Для того щоб функція
передавала більше ніж одне значення, використовують вказівники на змінні ( див. далі).
На завершення розглянемо приклад “достандартного” опису функції:
float
ser_kw_vidhyl(n,x,sz)
int n;
float x[];
float sz;
{
float r,sum;
int i;
sum=0;
for
(i=0;i<n;i++)
r=x[i]-sz;
sum+=r*r;
/* sum=sum+r*r; */
r=sqrt(sum/(n*(n-1)));
return r;
}
Цей опис відрізняється від стандартного тим, що типи формальних параметрів функції подано після заголовка функції.
Функції роботи із графікою у Сі
void
arc(int x, int y, int stAngel, int endAngle, int radius);
void
arc(int x, int y, int stAngel, int endAngle, int radius, COLORS color);
void
arc(int x, int y, int stAngel, int endAngle, int radius, int color);
void
bar(int x, int y, int x1, int y1);
void bar(int
x, int y, int x1, int y1, COLORS color);
void
bar(int x, int y, int x1, int y1, int color);
void
bar3d(int x, int y, int x1, int y1, int z, bool top);
void
circle(int x, int y, int radius);
void
circle(int x, int y, int radius, COLORS color);
void circle(int
x, int y, int radius, int color);
void
cleardevice();
void
close();
void
closegraph();
void
drawfunc(int numOfPoints, double *arrayX, double *arrayY);
void
drawpoly(int numOfPoints, int* array);
void drawpoly(int
numOfPoints, int* arrayX, int* arrayY);
void
drawpoly(int numOfPoints, int** arrayXY);
void
ellipse(int x, int y, int rWidth, int rHeight);
void
ellipse(int x, int y, int rWidth, int rHeight, COLORS color);
void
ellipse(int x, int y, int rWidth, int rHeight, int color);
void
fillellipse(int x, int y, int rWidth, int rHeight);
void
fillellipse(int x, int y, int rWidth, int rHeight, int color);
void
fillellipse(int x, int y, int rWidth, int rHeight, COLORS color);
int
getmaxx();
int getmaxy();
void
image(int x, int y, char* path);
void
initgraph();
void
initgraph(int drv, int drm, char *text);
void
initgraph(int setWidth, int setHeight);
void
line(int x, int y, int x1, int color);
void
line(int x, int y, int x1, COLORS color);
void line(int
x, int y, int x1, int color);
void
lineto(int x, int y);
void
lineto(int x, int y, int color);
void
lineto(int x, int y, COLORS color);
void
moveto(int x, int y);
void
outtext(const char* text);
void
outtext(const char* text, int color);
void outtext(const
char* text, COLORS color);
void
outtextxy(int x, int y, const char* text);
void
outtextxy(int x, int y, const char* text, int color);
void
outtextxy(int x, int y, const char* text, COLORS color);
void pieslice(int
x, int y, int stAngle, int endAngle, int radius);
void
pieslice(int x, int y, int stAngle, int endAngle, int radius, int color);
void
pieslice(int x, int y, int stAngle, int endAngle, int radius, COLORS color);
void
putpixel(int x, int y);
void
putpixel(int x, int y, COLORS color);
void
putpixel(int x, int y, int color);
void
rectangle(int x, int y,int x1,int y1);
void
rectangle(int x, int y,int x1,int y1, COLORS color);
void
rectangle(int x, int y,int x1,int y1, int color);
void
save(const char* path);
void
setbkcolor(COLORS color);
void
setbkcolor(int color);
void
setcolor(COLORS color);
void
setcolor(int color);
void setfillcolor(int
color);
void
setfillcolor(COLORS color);
void
setfillstyle(PATERN patern, COLORS color);
void
setfillstyle(int patern, COLORS color);
void
setfillstyle(PATERN patern, int color);
void
setfillstyle(int patern, int color);
void
setlinestyle(int linestyle, unsigned upattern, int thickness);
void
setlinestyle(LINESTYLE linestyle, unsigned upattern, int thickness);
void
settextstyle(char* font, int direction, int size);
Використання вказівників на змінні для імітації процедур
У процедурах Паскалю формальні параметри поділяють на дві групи:
параметри-значення, які не можуть змінюватись процедурою;
параметри-змінні (перед іменем такого параметра стоїть слово var), які змінюються або
взагалі створюються у процедурі. У функціях Сі є лише параметри-значення, а це означає,
що аналога процедурам Паскалю у мові Сі немає.
Однак завдяки використанню вказівників на змінні в якості параметрів
функції можна написати функції, у яких значення вказівників на змінні не змінюватимуться,
а значення, на які показують вказівники, будуть змінені.
Насамперед розглянемо поняття вказівника на змінну. Змінним, які описані у програмі,
при компіляції програми у пам’яті ЕОМ відводиться певна кількіть байтів (задається фізична адреса)
для зберігання значення змінної (кількість відведених байтів залежить від типу змінної). Після запуску
програми на виконання у відведені комірки пам’яті програма вписує значення змінних. Отже, з
кожною змінною у програмі пов’язані ім’я змінної, її тип, значення і фізична адреса області оперативної
пам’яті, у якій це значення зберігається. У більшості випадків ми визначаємо ім’я змінної, її тип і значення,
а технічну справу розміщення значення змінної в оперативній пам’яті покладаємо на компілятор
(при програмуванні у машинних командах розподілом пам’яті керує програміст). За допомогою
спеціальної конструкції — вказівника на змінну ми можемо отримати доступ до адреси змінної,
яку призначив змінній компілятор. Оскільки змінні різних типів отримують для зберігання своїх значень
різну кількість байт (комірок пам’яті), то опис вказівника на змінну здійснюємо таким чином:
тип_змінної *ім’я_змінної;
наприклад:
float *x — вказівник на змінну типу float.
Якщо x є масивом, то *x вказує на компоненту x[0], *(x+1) - на компоненту x[1],
*(x+i) на компоненту x[i]. У наступній програмі функція stat_obr(n, *x) має два параметри
n —кількість елементів масиву і *x — вказівник на масив.
Під час виконання функції ( наприклад stat_obr(9,d);) функція змінює два останні значення масиву:
нульове значення d[10] замінюється середнім значенням результатів вимірювання;
нульове значення d[11] — середньоквадратичним відхиленням.
#include
<stdio.h>
#include
<math.h>
#include
<conio.h>
void stat_obr(int n,
float *x) /* функція не повертає значення */
/* float *x — вказівник на змінну типу float */
{
float r,sum;
int i;
sum=0;
for
(i=0;i<n;i++)
sum+=*(x+i); /*
sum=sum+x[i], *(x+i) — вказівник на x[0]+i; */
*(x+n)=sum/n; /* елемент масиву x[n]=sum/n; */
sum=0;
for
(i=0;i<n;i++)
{
r=*(x+i)-*(x+n);
sum+=r*r;
/* sum=sum+r*r; */
}
*(x+n+1)=sqrt(sum/(n*(n-1))); /* елемент масиву x[n+1]=sqrt(sum/(n*(n-1))); */
}
void main()
{
float
d[]={2.17,2.1,2.12,2.2,2.18,2.13,2.13,2.11,2.15,0,0};
stat_obr(9,d);
printf("
seredne= %f\n",d[9]);
printf("
ser_kw_vydh= %f\n",d[10]);
getch();
}
Робота з файлами в Сі. Стандартні файли
Для довготривалого зберiгання програм, даних, текстiв, зображень та фонограм на ЕОМ
використовують магнiтнi та оптичнi диски. Як уже було зазначено, записи інформації на
дисках називають файлами (англ. file — шеренга, ряд бітів). Щоб вiдрiзнити один файл
вiд iншого використовують iмена файлiв. Зазвичай iм’я файла складають з двох частин:
власне iмені файлу довжиною до 256 знаків ( у MS DOS 8 знакiв);
розширення імені файлу ( у MS DOS до трьох знаків). Розширення вiддiляють вiд iменi крапкою.
Наприклад:
boll.pas
readme.txt
vdisk.sys
tabl.dat
lab3.c
lab4.cpp
Деякi розширення є стандартними, наприклад:
sys — системнi файли;
pas — програми, написанi мовою Паскаль;
c — програми, написанi мовою C;
cpp — програми, написанi мовою C++;
txt — текстовi файли;
dat — файли даних.
Файл можна зобразити довгим рядком, на якому зроблено написи
I ім’я файлу I запис I запис I... I запис I кiнець файлу I
Роботу з файлами на магнітних дисках у мові Сі можна здійснювати на трьох рівнях:
потоковий ввід/вивід;
ввід/вивід нижнього рівня (побайтовий ввід/вивід з використанням засобів операційної системи);
ввід/вивід для консолі і портів.
Розглянемо потоковий ввід/вивід. Потоковий ввід/вивід побудований на обміні
байтами (вивід на пристрій друку, дисплей, диск; ввід з клавіатури, диска).
Кожна програма під час своєї роботи має доступ до стандартних потоків
stdin (вхідний потік байтів з клавіатури ), stdout (вихідний потік байтів на дисплей),
stderr (потік повідомлень про помилки). Функція scanf працює з stdin,
printf — з stdout, повідомлення про помилки (потік stderr) виводяться на дисплей.
Для роботи з файлами використовують структуру FILE, визначену у стандартному
файлі stdio.h. Цю структуру позв’язують з вказівником на файл рядком опису
FILE *ім’я_файлової_змінної;
Для відкриття файла використовують функцію fopen(ім’я_файла, режим_відкриття). Параметр режим_відкриття може мати значення:
“w” — відкриття нового файлу для запису;
“wt” — відкриття нового текстового файлу для запису;
“r” — відкриття файлу для читання;
“rt” — відкриття текстового файлу для читання;
“a” — відкриття файлу для додавання інформації в кінець файлу;
“w+” — відкриття файлу для запису і багаторазових виправлень, відкриття існуючого
файлу з таким режимом призводить до втрати його вмісту;
“r+” — відкриття файлу для читання з можливістю змін його вмісту без збільшення
його розміру (дописування в кінець файлу неможливе!);
“a+” — відкриття файлу для читання і запису, на відміну від “w+” відкриття існуючого
файлу з таким режимом не призводить до втрати його вмісту.
Під час відкриття файлу вказівник файлу встановлюється на його початок,
для роботи з режимами “w+”, “r+”, “a+” використовують функцію
задання позиції вказівника файлу fseek(вказівник_на_файл, зміщення, початок_відліку),
початок_відліку задають константами, які означені у файлі stdio.h:
SEEK-SET — початок файлу;
SEEK-CUR — поточна позиція вказівника;
SEEK-END — кінець файлу.
Для форматного виводу у файл використовують функцію
fprintf (файлова_змінна, “керуючий рядок”, список виводу);
Форматний ввід з файлу здійснюють функцією
fscanf (файлова_змінна, “керуючий рядок”, список вводу);
Для закінчення роботи з файлом використовують функцію
fclose(файлова_змінна );
Для прикладу розглянемо програму запису у файл zn_x.txt значень змінної x
та у файл zn_y.txt значень змінної y з подальшим читанням інформації з цих файлів і виводом їх на екран дисплею
#include
<stdio.h>
#include
<math.h>
void main()
{
float
a,b,x,y,rx,ry;
FILE *fx,*fy;
/*відкриття нового текстового файлу для запису */
fx=fopen("zn_x.txt","wt");
/*відкриття нового текстового файлу для запису */
fy=fopen("zn_y.txt","wt");
a=-5.0;
b=5;
x=a;
while
(x<=b)
{
y=x*x;
/*вивід у файл zn_x.txt значення x */
fprintf(fx,"
%f\n ",x);
/*вивід у файл zn_y.txt значення y */
fprintf(fy,"
%f\n ",y);
x+=0.2;
}
/*закриття файлу zn_x.txt */
fclose(fx);
/*закриття файлу zn_y.txt */
fclose(fy);
/*відкриття текстового файлу zn_x.txt для читання */
fx=fopen("zn_x.txt","rt");
/*відкриття текстового файлу zn_x.txt для читання */
fy=fopen("zn_y.txt","rt");
/* ПОКИ НЕ(КІНЕЦЬ(файлу zn_x.txt) */
while (!feof(fx))
{
/*читання з файлу zn_x.txt значення x */
fscanf(fx,"%f",&rx);
/*вивід на дисплей прочитаного значення x */
printf("x=%f",rx);
/*читання з файлу zn_y.txt значення y */
fscanf(fy,"%f",&ry);
/*вивід на дисплей прочитаного значення y */
printf(" y=%f\n",ry);
}
/*закриття файлу zn_x.txt */
fclose(fx);
/*закриття файлу zn_y.txt */
fclose(fy);
}
Для форматного виводу у потік stdout (на дисплей) використовують функцію
printf (див. Виведення значень на екран дисплею). Розглянемо функцію форматного
вводу з клавіатури, яка вибирає з вхідного потоку stdin потрібну кількість байтів
і перетворює їх відповідно до специфікацій, внесених у керуючий рядок
scanf (“керуючий рядок”, список вводу);
Специфікації перетворення потоку байтів у значення змінних описані у п.5. Розглянемо
приклад програми з читанням значень змінних із клавіатури
#include <stdio.h>
#include
<conio.h>
#include
<math.h>
#include
<stdlib.h>
void main()
{
float r,s;
int i,n;
printf("\n введи ціле значення ");
/*читання з stdin значення для i */
scanf("%d",&i);
printf("\n
введено %d", i);
printf("\n введи два цілі значення ");
/*читання з stdin значеннь для i та n */
scanf("%d
%d",&i,&n);
printf("\n
введено %d %d ",
i,n);
printf("\n введи дробове значення ");
/*читання з stdin значення для r */
scanf("%f",&r);
printf("\n
введено %f ", r);
printf("\n введи ціле і дробове значення ");
/*читання з stdin значеннь для i та s */
scanf("%d
%f",&i,&s);
printf("\n
введено %d %f ",
i,s);
}
Окрім специфікацій перетворень у керуючий рядок можна внести символи прогалини,
які вказують на те, що з вхідного потоку потрібно зчитувати і не враховувати всі
прогалини аж до появи байта, відмінного від символа прогалини (використовують для
розділення значень у вхідному потоці символами прогалини).
У специфікаціях перетворення можна задавати максимальну кількість символів
для перетворення за цією специфікацією, наприклад:
%4d — специфікація для введення чотирицифрового цілого значення;
%6f — специфікація для введення шестицифрового дробового значення.
Окрім значень для змінних, згідно із списком вводу функція:
scanf (“керуючий рядок”, список вводу);
повертає кількість уведених значень, якщо всі перетворення виконано успішно,
або ж -1 при виникненні помилок перетворення. Це означає, що у програмі мовою
Сі можна записати таку команду присвоєння:
kontr=scanf("%d
%f",&i,&s);
Після успішного виконання цієї команди змінна kontr матиме значення 2,
якщо ж уведені значення не відповідатимуть специфікаціям керуючого рядка,
то змінна kontr матиме значення -1.
Для читання інформації з вхідного потоку можна використовувати і такі функції:
ім’я змінної=getchar(); - ввід одного символа
gets(ім’я рядкової змінної); - ввід одного рядка символів
Для виводу інформації у вихідний потік можна використовувати такі функції:
putchar(змінна); - вивід значення змінної типу char;
puts(ім’я рядкової змінної); - вивід одного рядка символів.
Нижче подано приклад програми читання значень з клавіатури, в якій для виведення
запрошення до введення значень використано функцію puts
#include
<stdio.h>
#include
<conio.h>
/*потрібно для виконання перетворень значень типу float */
#include
<math.h>
#include
<stdlib.h>
void main()
{
float r,s;
int i,n;
puts(" введи ціле значення
");
/*читання з stdin значення для i */
scanf("%d",&i);
printf("введено %d\n
", i);
puts(" введи два цілі значення ");
/*читання з stdin значеннь для i та n */
scanf("%d
%d",&i,&n);
printf(" введено %d
%d\n ", i,n);
puts(" введи дробове значення ");
/*читання з stdin значення для r */
scanf("%f",&r);
printf(" введено %f\n
", r);
puts(" введи ціле і дробове значення ");
/*читання з stdin значеннь для i та s */
scanf("%d
%f",&i,&s);
printf(" введено %d %f
\n ", i,s);
}
Додавання до тексту програми текстів із файлів
Для додавання до тексту програми текстів із файлів на магнітних дисках використовують
команду #include. Ця команда має три форми:
#include
<ім’я файла.h>
#include ”ім’я файла.c”
#include ім’я макроса
Файли з розширенням .h називають заголовковими і використовують для означення
стандартних бібліотечних функцій. Перерахуємо призначення деяких заголовкових файлів:
stdio.h — засоби вводу/виводу;
stdlib.h — функції загального призначення;
math.h — функції для математичних обчислень;
graphics.h — графічні функції (для MS DOS);
conio.h — функції для роботи з клавіатурою і дисплеєм ( MS DOS);
dos.h — функції для роботи з системними засобами MS DOS.
Друга форма директиви #include ”ім’я файла.c” дає змогу „зібрати” текст програми
з окремих текстових файлів. ЇЇ використовують під час колективної розробки великих програм.
Наприклад, директиви
#include ”main.c”
#include ”count.c”
#include ”estimate.c”
#include ”compare.c”
#include ”gauss.c”
#include ”pseudo.c”
дозволяють створити текст програми, у яку ввійдуть тексти з файлів
main.c, count.c, estimate.c, compare.c, gauss.c, pseudo.c.
Такий підхід ви зможете використати під час виконання лабораторних робіт
з курсу „Чисельні методи”, який будете вивчати на третьому курсі.
Основні етапи створення і виконання програм на ЕОМ
Спрощену схему підготовки програм, дійсну для багатьох мов програмування, можна зобразити таким чином
Текст програми створюють за допомогою текстового редактора (у багатьох оболонках
текстовий редактор є складовою оболонки) і зберігають на магнітному диску. Для перекладу
(компіляції або трансляції) тексту програми, записаного мовою програмування високого рівня
(Паскаль, Сі, Фортран і ін.) використовують спеціальну програму-компілятор (транслятор).
Якщо текст програми не відповідає синтаксису мови програмування, яку використано для
написання програми, то компілятор видає повідомлення про помилки у програмі. Потрібно
виправити синтаксичні помилки і знову запустити процес компіляції програми. Якщо текст
програми повністю відповідає синтаксису мови програмування, то результат компіляції зберігають
на магнітному диску (або в оперативній пам'яті [залежно від налаштування компілятора]).
Для отримання виконуваної програми (програми у машинних командах) до результатів компіляції
додають (команда Link) програми вводу/виводу інформації, обчислення стандартних функцій
тощо з бібліотеки модулів. Отриману унаслідок об'єднання модулів програму зберігають
на магнітному диску або розташовують в оперативній пам'яті для подальшого її виконання
(команда Run). Після отримання результатів рахунку програми їх треба проаналізувати.
Якщо отримані результати не відповідають поставленій задачі (наприклад, після запуску
програми методу Ньютона корінь нелінійного рівняння не знайдено), потрібно проаналізувати
алгоритм розв'язування задачі і текст написаної програми. Якщо в алгоритмі або у тексті
програми виявлені помилки, потрібно виправити їх і повторити процеси компіляції, рахунку і
аналізу результатів.
Конструкція if
Розглянемо синтаксис цієї конструкції:
if (<Лог. Вираз>)
{ блок 1 ;}
else
{ блок 2 ;}
<Лог. Вираз> в дужках повертає значення true або false, тобто значення типу boolean.
Якщо вираз істинний(тобто має значення true або ≠0), то виконуються оператори, які стоять в блоці 1,
якщо вираз помилковий(тобто має значення false або =0), то виконуються оператори, що стоять в блоці 2.
Оператора if можна використовувати і без оператора else:
if (лог. вираз)
{ блок 1; }
В цьому випадку виконуються оператори, що стоять в блоці 1, якщо вираз істинний; якщо вираз помилковий,
то жоден з операторів блоку if не виконується.
Конструкція switch
Ця конструкція використовується для вибору з множини кількох альтернатив з перевіркою якогось виразу на різні значення.
Синтаксис цієї конструкції:
switch (вираз)
{
case значение1:
. . . .
break;
case значение2:
break;
case значениеЗ:
break;
default:
. . . .
break;
}
Під виразом розуміється будь-який вираз, який має цілий тип або тип даних char, або enum, або string.
Цього оператора обчислює значення виразу і починає проходити по всіх мітках case, порівнюючи значення що співпадає
із значенням виразу.
Якщо програма виявила таку мітку, то виконуються всі оператори, які знаходяться після цієї мітки до оператора break,
після якого здійснюється перехід в кінець оператора switch. У випадку, якщо мітка не знайдена, то перехід здійснюється на
мітку default. Мітка default може бути відсутня, тоді перехід здійснюється відразу в кінець оператора switch.
Конструкція goto
Використовується для переходів(передачі контролю) на певний рядок коду.
Синтаксис цієї конструкції:
goto <мітка>;
<мітка> -
вказує місце коду до якої потрібно передати контроль, при вказані мітки
потрібно поставити двокрапку після
неї.
Приклад:
label1:
. . . ;
. . . ;
. . . ;
goto label1;
Ця конструкція служить для відділення дій, в яких можуть бути незаплановані помилки, з подальшою можливістю перехоплення
виключень, які проводяться в секції catch, що згенерували.
В загальному вигляді оператор try... catch виглядає таким чином:
try
{
сумнівні дії
}
catch(помилка)
{
дії обробки помилки
}
final
{
завершальні дії
}
Отже, в тілі try знаходяться деякі "сумнівні дії", виконання яких може призвести
до помилки. У разі її виникнення буде проведений перехід в секцію catch для
її подальшої обробки. В секції final знаходяться дії, які повинні бути виконаний
незалежно від того чи виникло виключення чи ні.
За допомогою оператора throw можна генерувати свої власні виключення для їх подальшого
перехоплення в операторі try. .. catch. Виключення може бути числом, рядком або
навіть об'єктом власного класу. Викид виключення в загальному вигляді виглядає
таким чином: throw error;
Цей оператор використовується для дострокового виходу з циклів а також конструкцій вибору
Цей оператор використовується для дострокового переходу на новий виток циклу в операторах циклів.
Виконує негайний вихід з поточно виконуваної функції з можливістю передачі значення.
Оператор sizeof(<змінна чи тип>)
Цей оператор використовується для одержання розміру( в байтах ) змінної чи типу вказаного в дужках.
Життя повне складних речей, і один із способів рішення виникаючих складних проблем полягає в побудові спрощуючих абстракцій.
Кожний з нас являє собою якусь певну кількість атомів. Деякі дослідники інтелекту готові заявить, що і наш розум — це
сукупність напівавтономних агентів. Але набагато простіше думати про себе як про єдиний організм. В теорії обчислювальних
систем абстракція є вирішальним кроком в представленні інформації і її взаємодії з користувачем. Інакше кажучи, ви створюєте
абстрактне представлення найважливіших операційних особливостей проблеми і формулюєте рішення цих проблем, використовуючи одні
і ті ж терміни. Від абстракції всього один крок до типу, визначеного користувачем, котрим в C++ є проект класу, який реалізує
цей інтерфейс.
Одним словом, специфікація основного типу дозволяє визначити наступне:
• Який об'єм пам'яті необхідний для розміщення відповідного об'єкту даних.
• Які операції або методи можуть бути виконаний над об'єктом даних.
Для вбудованих типів даних ця інформація закладена в компілятор. Але коли в C++ задається тип, визначений користувачем, таку інформацію потрібно задавати самостійно. Нагорода за працю — виграш в продуктивності і гнучкості, тому ми і створюємо нові типи
даних, більшою мірою відповідаючі вимогам програми. В мові C++ клас є платформою для перекладу абстракції в тип, визначуваний користувачем. Він поєднує в собі представлення даних з методами впорядковування цих даних в компактні пакети.
Клас – це абстракція, тобто опис чого-небудь, причому цього «що-небудь» може і не існувати. Клас – це спосіб реалізації природного підходу до опису.
У програмуванні, коли ми описуємо клас, ми даємо лише опис характеристик і функцій. Сутність, яка побудована на основі цього опису, називається об'єктом або екземпляром класу. Навіть якщо ви створюєте два об'єкти одного і того ж класу, то це будуть різні об'єкти. Необхідно розуміти різницю між об'єктами, які реально існують, і їхнім описом.
ООП підтримує три основні принципи:
· інкапсуляція;
· поліморфізм;
· наслідування.
Розглянемо принцип інкапсуляції. До появи ООП програми містили багато даних і багато функцій по роботі з ними. Будь-яка функція могла дістати доступ до будь-яких даних, що існують в програмі, хоча більшості функцій немає необхідності мати доступ до всіх даних, а тільки до деяких. При зростанні програми наступав хаос. Програміст переставав розуміти, які дані використовуються тією або іншою функцією. Крім того, такий стиль програмування робив практично неможливим повторне використання програмного забезпечення і його підтримку. Поява ООП вирішила цю і багато інших проблем.
Інкапсуляція в ООП складається з двох аспектів:
· об'єднання даних і функцій по роботі з цими даними в єдину сутність;
· контроль доступу до елементів цієї сутності.
Оголошення класу
· використовуємо ключове слово class;
class <ім’я класу>[<:список батьківських класів>]
{
опис полів і методів;
}
· оголошуємо дані усередині класу;
Полями є будь-які змінні, пов'язані з класом. Якщо визначити змінну на рівні класу, то насправді це буде поле класу.
· оголошуємо методи усередині класу;
Методи є функціями, пов'язаними з конкретним класом. Це можуть бути або методи екземпляра, які працюють для конкретного екземпляра класу,
або статичні методи, які мають загальну функціональність, що не вимагає створення екземпляра класу.
static Метод не призначений для роботи з певним екземпляром класу.
virtual Метод може бути перевизначений в похідному класі.
abstract Віртуальний метод, який визначає сигнатуру методу, але не містить реалізацію.
override Метод перевизначає успадкований віртуальний або абстрактний метод.
extern Метод реалізований поза програмою на іншій мові.
· розставляємо модифікатори доступу для даних і методів.
Модифікатори доступу:
public доступний звідусіль, зокрема ззовні класу.
protected доступний всередині класу, до якого він належить, або з типу, похідного від даного класу.
private доступний тільки з класу, до якого він належить.
Воно містить посилання на той об'єкт, функцію якого ми викликали. Це посилання створиться в будь-якому об'єкті відразу
після виділення пам'яті під об'єкт.