
C _Учебник_МОНУ
.pdf
Програмування базових алгоритмів |
159 |
Приклад 4.60 Написати програму обчислення факторіала введеного цілого числа за допомогою оператора while.
Розв‟язок. У порівнянні з обчисленням факторіала оператором for (див. п. 4.4.1) чи за допомогою рекурсивної функції (див. підрозд. 8.5) наведене розв‟язання є самим лаконічним і елегантним.
void __fastcall TForm1::Button1Click(TObject *Sender)
{int f = 1, n;
n = Edit1->Text.ToInt(); while ( n >= 1 ) f *= n--; Edit2-> Text = IntToStr(f);
}
4.4.5 Оператори переривання виконання
Для завчасного переривання повторювань операторів циклу будь-якого типу в тілі циклу можна застосовувати оператор break, який перериває виконування оператора, в якому розміщено цей break, і передає керування на наступний оператор.
Наведемо приклад застосування оператора break на програмному фрагменті обчислення у змінній k кількості різних (неоднакових) елементів для масиву a з m елементів. Кожен черговий елемент a[і] порівнюється з наступними елементами масиву. Якщо він не збігається з жодним із цих елементів, лічильник k збільшується на одиницю. Інакше, внутрішній цикл переривається оператором break і починається нова ітерація зовнішнього циклу.
int k=1;
for(int i=0;i<m-1;i++) { for(int j=i+1;j<m;j++)
if(a[i]==a[j]) break; if(j==m)k++;
}
Зауважимо, що всередині вкладених операторів do-while, for, while чи switch оператор break завершує лише самий внутрішній з цих операторів, тому break неможна використовувати для виходу з декількох вкладених циклів. Навіть повторення підряд двох операторів break не забезпечить вихід з вкладених циклів у такому фрагменті:
for (i=0; i<100; i++) for (j=0; j<100; j++) { . . .
if (a[i][j]<0) { break; break; }
. . .
}
Так після виконання умови a[i][j]<0 відбудеться вихід лише з внутрішнього циклу по змінній j, а виконання зовнішнього циклу по змінній i продовжиться, незважаючи на те, що оператор break записано двічі.
160 |
Розділ 4 |
По своій суті оператор break є оператором переходу і оператори записанні після нього виконуватись не будуть, якщо тільки їм не буде передано керування за допомогою інших операторів переходів.
Для виходу з обох циклів можна застосувати додаткову змінну, яка буде набувати ненульового значення лише за потреби виходу із зовнішьного циклу:
for (i=0; i<100; i++)
{for (br2=j=0; j<100; j++) { . . .
if ( a[i][j]<0 ) { br2=1; break;}
. . .
}
if (br2) break;
. . .
}
У наведеному прикладі відразу після завершення внутрішнього циклу перевірятиметься умова завершення зовнішнього циклу.
Крім того, передавати керування за межі вкладеної структури, можна використовуючи оператори return (вихід з поточної функції) (див. підрозд. 8.1) та goto (безумовний перехід) (див. п. 4.3.2).
Для переходу до наступної ітерації циклу можна застосовувати оператор continue. Цей оператор, подібно до оператора break, використовується лише всередині операторів циклу for, while, do-while, але, на відміну від останнього, оператор continue не припиняє подальше виконання циклу, а переходить до чергової ітерації того циклу, у тілі якого він виявився. Він як би імітує безумовний перехід на кінцевий оператор циклу, але не за межі самого циклу.
Оператор continue, так само як і оператор break, перериває найглибинний з циклів.
for(int a = 1, b = 0; a < 100; b += a, a++)
{if(b % 2) continue;
. . . |
// Опрацювання парних сум |
}
У вищенаведеному прикладі оператор continue передає керування на чергову ітерацію циклу for за умови, коли сума чисел від 1 до а є непарною, не виконуючи операторів опрацювання парних сум.
Наведемо ще один програмний фрагмент з застосуванням оператора continue для обчислення суми додатних елементів масиву a з m елементів:
int s=0;
for(int i=0; i<m; i++)
{if(a[i]<=0) continue; // Пропустити елемент s+=a[i];
}
У наведеному прикладі оператор continue використовується для пропускання від‟ємних елементів масиву, підсумовуючи лише додатні.
Програмування базових алгоритмів |
161 |
Питання та завдання для самоконтролю
1)Який процес називають лінійним?
2)Який процес називають розгалуженим?
3)Які оператори в С++ використовуються для організації розгалужень?
4)Перелічіть базові логічні операції.
5)Вкажіть послідовність дій при виконанні оператора
bool w=2*5<=17%3; .
6) Наведіть результат виконання логічного виразу (7+3 > 16–4*3). 7) Обчисліть логічний вираз (–3 >= 5) || (7 < 9) && (0 < 3).
8)Вкажіть значення w після виконання оператора bool w=2*5<=17%3; .
9)Засобами умовного оператора if скороченої і повної форми, а також умовної операції ?: запишіть три варіанти обчислення
sin x2 |
за |
x 0.5; |
|
|
|
|
|
y |
|
x 0.5. |
|
cos2 x |
за |
|
|
|
|
|
|
10) Назвіть оператор без помилок: |
|
||
а) if(x<=6)y=2*x; else y=cos(x); |
в) if(a<>0) if(b<>0) y=2*x; |
||
б) if y<=x then y:=exp(x*y); |
г) if(x>0)y=ln(x) else y=x; |
||
11) Вкажіть значення х після виконання фрагментів програми: |
|||
а) float х=1.5; |
б) float х=1.5; |
||
if(x<=0.5) х=7.7; |
if(x<=0.5) х=7.7; else x=3; |
12)Наведіть значення змінної z після виконання операторів: x=2.5;
if(x>=0.5) z=7.7; else z=5.5;
13)Вкажіть значення змінної f після виконання операторів f = 1; n = 3; i = 2;
M1: if (i > n) goto PP;
f = f * i; i++; goto M1; PP : ;
14)Вкажіть значення y після виконання фрагментів програми:
а) float y=0; int n=1; |
|
|
б) float y=0; int n=3; |
|
switch (n) |
|
|
switch (n) |
|
{case 1: { y=n/4.; break; } |
{case 1: { y=n/4.; } |
|||
case 2: { y=n*n; break; } |
case 3: { y=n*n; } |
|||
case 3: { y=n; break; |
}} |
case 5: { y=n+1; }} |
||
б) float y=0; int n=4; |
|
|
в) float y=0; int n=1; |
|
switch (n) |
|
|
switch (n) |
|
{case 2: { y=n/4.; break; } |
{case 1: { y=n/4; } |
|||
case 5: { y=n*n; break; } |
case 3: { y=n*n; } |
|||
case 9: { y=n; break; |
}} |
case 5: { y=n+1; }} |
||
15) У наведеному фрагменті програми |
|
|||
int nom = pow(2, 3); |
|
|
|
|
switch (nom) |
|
|
|
|
{ case |
2 : y=d; |
break; |
|
|
case |
8 : y=d*exp(x); break; |
|
||
case 10 : y=d*x; |
break; |
} |
оператор switch обчислюватиме вираз … (запишіть увесь вираз).
162 |
Розділ 4 |
16)Який процес називають циклічним?
17)Які оператори циклу використовуються e мові С++?
18)Скільки разів виконуватиметься оператор у циклі, тобто вкажіть зна-
чення s:
for(int k = -1, s=0; k <= 5; k++) s++;
19) Вкажіть помилки в таких фрагментах програм:
а) int k, m=2, n=3; |
б) int n=–7, m=2; |
for(k=1; k<=n; k++)n=n+m; |
for(int k=n; k<=m; k--)k++; |
20) Вкажіть значення m після виконання фрагментів програми: |
|
а) int k, m=1; |
б) int m=1, n=5; |
for(k=1; k<=5; k++)m++; |
for(int k=n; k>=1; k--)m*=k; |
21) Назвіть правильну, на Ваш погляд, послідовність номерів, для запису |
|
елементів оператора циклу while: |
|
а) логічний вираз умови; |
|
б) оператори тіла циклу; |
|
в) while. |
|
22) Вкажіть значення n після виконання фрагментів програми: |
|
а) int k=0, n=17; |
б) int m=1, n=1; |
while(k<7){ k++; n--; } |
while(m<5){ m+=2; n=n*m; } |
23)Якими є структура і порядок виконання оператора циклу do-while?
24)Вкажіть значення y після виконання фрагментів програми:
а) int i=1, y=1; |
б) int k=1; float y=0; |
do {y*=i++;} while(y<7); |
do{k+=2;y+=1./k;}while(k<5); |
25)Запишіть трьома операторами циклу варіанти обчислення S i2 .
i1
26)Вкажіть значення s після виконання операторів 6
s=0.5; i=0; |
|
|
|
while(i<5) i++; |
|
|
|
s+=1.0/i; |
|
|
|
27) Назвіть номер фрагмента програми з |
в к л а д е н и м ц и к л о м |
||
а) for(k=1;k<=10;k++) б) for(k=1;k<=10;k++) |
в) for(k=1;k<=10;k++) |
||
p=k; |
{ p=k; |
|
{ p=k; } |
for(j=1;j<=5;j++) |
for(j=1;j<=5;j++) |
for(j=1;j<=5;j++) |
|
s+= p*j; |
s+= p*j; |
} |
{ s+= p*j; } |
28)Якого значення набуде змінна s після виконання операторів for(s=0,k=1; k<=3; k++)
for(j=1; j<=k; j++) s+=j;
29)Вкажіть значення s після виконання операторів for(s=0,k=1; k<=2; k++)
{ m=k;
do { m++; s+=m; } while( m <= 2);
}
30) Назвіть оператори, використовувані для завчасного переривання повторювань циклу.
Розділ 5
Масиви в С++
5.1 Поняття масиву
Змінні, якими ми оперували до цих пір, могли зберігати лише одне значення одночасно. За присвоювання їм іншого значення попереднє втрачалося. Часто виникає потреба зберігати велику кількість однотипних значень, які мають опрацьовуватись однаково. Приміром, екзаменаційні оцінки студентів, які слід вводити, виводити, аналізувати (порівнювати з “2” чи “5”), змінювати за потреби тощо. Такі однотипні значення є сенс зберігати в одній змінній, перенумерувати їх усередині цієї змінної, надати доступ до цих значень за номером і опрацьовувати ці значення у циклі (номер значення збігатиметься з параметром циклу).
Масив у програмуванні – це упорядкована сукупність однотипних елементів. Масиви широко застосовуються для зберігання і опрацювання однорідної інформації, приміром таблиць, векторів, матриць, коефіцієнтів рівнянь тощо.
Кожен елемент масиву однозначно можна визначити за ім‟ям масиву та індексами. Ім‟я масиву (ідентифікатор) добирають за тими самими правилами, що й для змінних. Індекси визначають місцезнаходження елемента в масиві. Приміром, елементи вектора мають один індекс – номер по порядку; елементи матриць чи таблиць мають по два індекси: перший означає номер рядка, другий
– номер стовпчика. Кількість індексів визначає вимірність масиву. Приміром, вектори у програмах – це одновимірні масиви, матриці – двовимірні.
Індексами можуть бути лише змінні, константи чи вирази цілого типу. Значення індексів записують після імені масиву в квадратних дужках. При оголошенні масивів у квадратних дужках зазначається кількість елементів, а нумерація елементів завжди розпочинається з нуля.
Відмінності масиву від звичайних змінних:
спільне ім‟я для всіх значень;
доступ до конкретного значення за його номером (індексом);
можливість опрацювання у циклі.
5.2 Одновимірні масиви
5.2.1 Оголошення одновимірних масивів
Одновимірний масив (вектор) оголошується у програмі в такий спосіб:
<тип_даних> <ім‟я_масиву> [<розмір_масиву>];
Тип_даних задає тип елементів масиву. Елементами масиву не можуть бути функції й елементи типу void. Розмір_масиву у квадратних дужках задає кількість елементів масиву. На відміну від інших мов, у С++ не перевіряється вихід за межі масиву, тому, щоб уникнути помилок у програмі, слід стежити за

164 |
Розділ 5 |
розмірністю оголошених масивів. Значення розмір_масиву при оголошенні масиву може бути не вказано в таких випадках:
при оголошенні масив ініціалізується;
масив оголошено як формальний параметр функції (докладніше див.
розд. 8);
масив оголошено як посилання на масив, явно визначений в іншому
модулі.
Використовуючи ім‟я масиву та індекс, можна звертатися до елементів масиву:
<ім‟я_масиву> [<значення_ індексу>]
Значення індексів мають перебувати в діапазоні від нуля до величини, на одиницю меншу за розмір масиву, визначений при його оголошенні, оскільки в С++ нумерація індексів розпочинається з нуля.
Наприклад, int A[10];
оголошує масив з ім‟ям А, який містить 10 цілих чисел; при цьому виділяє і закріплює за цим масивом оперативну пам‟ять для усіх 10-ти елементів відповідного типу (int – 4 байти), тобто 40 байтів, у такий спосіб:
А[0] А[1] А[2] А[3] А[4] А[5] А[6] А[7] А[8] А[9]
Отже, при оголошенні масиву виділяється пам‟ять, потрібна для розташування усіх його елементів. Елементи масиву з першого до останнього запам‟ятовуються у послідовно зростаючих адресах пам‟яті. Поміж елементами масиву в пам‟яті проміжків немає. Елементи масиву запам‟ятовуються один за одним поелементно.
Зауважте на звертання у програмі до елементів масиву: елемент, А[1] – другий, А[9] – останній.
Так, для розміщення елементів одновимірного масиву int В[5] виділяється по 4 байти під кожен з 5-ти елементів масиву – тобто усього 20 байт:
Елементи |
|
В[0] |
|
|
В[1] |
|
|
В[2] |
|
|
В[3] |
|
|
В[4] |
|
|||||
Байти |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
Для отримання доступу до i-го елемента масиву В, можна написати В[i], де і – змінна циклу, яка може набувати значення від 0 до 3. При цьому величина i перемножується на розмір типу int і являє собою адресу i-го елемента масиву В від його початку, після чого здійснюється вибір елемента масиву В за сформованою адресою.
Змінна (ідентифікатор), оголошена як масив, по суті є вказівником на перший елемент масиву (див. розд. 6). Слід зауважити, що у перебігу виконування програми адресу масиву не може бути змінено, хоча значення його елементів можуть змінюватись.
Ось кілька прикладів оголошення масивів:
char N[20];
int grades[125];
Масиви в С++ |
165 |
float mass[30]; double v[1500];
Перший з масивів N містить 20 символів. Звертання до елементів масиву може бути таким: N[0], N[1], ..., N[19].
Другий масив grades містить 125 цілих чисел. Звертання до елементів та-
кого масиву може бути таким: grades[0], grades[1], ..., grades[124].
Третій масив mass містить 30 дійсних чисел. Звертання до елементів ма-
сиву може бути таким: mass[0], mass[1], ..., mass[29].
Четвертий масив v містить 1500 дійсних чисел з подвійною точністю. Звертання до елементів такого масиву може бути таким: v[0], v[1], ..., v[1499].
При оголошуванні масивів можна елементам масиву (необов‟язково всім) присвоювати початкові значення, які у подальшому в програмі може бути змінено. Якщо реальна кількість ініціалізованих значень є менше за розмірність масиву, то решта елементів масиву набуває значення 0.
Наприклад,
int a[5]={9,33,–23,8,1}; |
//а[0]=9, а[1]=33, а[2]=–23, а[3]=8, а[4]=1 |
|
float b[10] = {1.5, -3.8, 10}; |
||
|
// b[0]=1.5, b[1]=-3.8, b[2]=10, b[3]=b[4]=…=b[9]=0 |
|
char s[5]="Фото"; |
// s[0]= 'Ф', s[1]='о', s[2]='т', s[3]= 'о', s[4]= '\0' |
|
char code[]="abc"; |
//code[0]='a', code[1]= 'b', code[2]= 'c', code[3]='\0' |
В останньому прикладі ініціалізується code як масив символів з чотирьох елементів. Четвертим елементом є символ '\0', який завершує усі рядки символів. Якщо рядок є коротше за оголошений розмір масиву символів, то решта елементів масиву ініціалізується нулем (символом '\0').
Масиви в програмах можна оголошувати також зі створенням типу користувача (докладніше див. розд. 11):
typedef <тип_даних> <ім‟я_типу> [<розмір_масиву>]; <ім‟я_типу> <ім‟я_масиву>;
Наприклад, створимо тип з ім‟ям чисел і оголосимо два масиви – a та b
typedef unsigned short mass[10]; mass a, b;
Для оголошування масивів можна використовувати типізовані конс- тант-масиви, які дозволяють водночас і оголосити масив, і задати його значення як константи:
сonst <тип_даних> <ім‟я_масиву> [<розмір_масиву>] = {<значення_елементів_масиву>};
Слід пам‟ятати, що змінювати значення елементів констант-масивів не припустимо.
Приклади створювання констант-масивів:
const int arr[5]={9,3,–7,0,123}; //масив з 5-ти цілих чисел
const float f[5]={1.5,6,8,7.4,–1.125}; //масив з 5-ти дійсних чисел const С[5]={15,–6,546}; //масив з 5-ти цілих чисел типу int,
// де С[0]=15, С[1]= –6, С[2]=546, С[3]=0 і С[4]=0
166 |
Розділ 5 |
5.2.2 Введення-виведення одновимірних масивів
Виведення елементів одновимірних масивів до різних компонентів
Виводити значення одновимірних масивів можна до файла чи на форму, використовуючи різноманітні компоненти С++ Builder. При цьому виводити значення елементів масивів можна лише поелементно, для чого слід організовувати цикли зі зміненням значень індексу зазначеного масиву. Організацію виведення масивів до файла буде розглянуто у розд. 11. Тут розглянемо організацію виведення одновимірних масивів на форму за допомогою компонентів
Edit, Label, Memo, ListBox та функції ShowMessage().
У подальших прикладах буде використано такі змінні:
float A[10];
int i; AnsiString st;
Виведення до компонента Edit елементів одновимірних масивів можна організовувати, відокремлюючи елементи пробілами (" ") чи іншими символами.
Приклад фрагмента програми виведення масиву А:
st = "" ; // Очищення рядка st
for(i=0; i<=9; i++) // Початок циклу за індексами масиву
//для накопичення в рядку значень масиву
{st += FormatFloat("0.00", A[i])+" "; }
Edit1->Text=st; // Виведення до компонента Edit1 сформованого рядка
Ще один спосіб виведення масиву А до Edit1 (кожний елемент виводиться до Edit1 послідовно):
for(i=0; i<=9; i++)
Edit1->Text = Edit1->Tex+FormatFloat("0.00", A[i])+" ";
Виводити до компонента Label можна одновимірний масив, відокремлюючи його елементи пробілами (" ") чи символами переходу до нового рядка ('\n'). Виведення одновимірного масиву у рядок організовують за тими самими правилами, що і до компонента Edit, лише в програмі замість Edit1->Text
слід записати Label1->Caption (наприклад Label1->Caption=st;). Для виве-
дення одновимірного масиву у стовпчик слід властивість WordWrap компонента Label встановити в true замість false, що встановлено за замовчуванням.
Виведення одновимірного масиву у вікно повідомлень за допомогою функ-
ції ShowMessage() організовують так само, як і в попередніх прикладах, лише замість оператора присвоювання слід записати оператор виклику функції. Наприклад, замість оператора
Edit1->Text = st;
слід записати
ShowMessage(st);
Виводити до багаторядкового компонента Memo можна одновимірні ма-
сиви з якою завгодно кількістю елементів. В такому разі є доцільним використання смуги прокручування (надати властивості ScrollBars значення ssBoth
чи ssVertical).
Масиви в С++ |
167 |
Приклад фрагмента програми виведення масиву А (у стовпчик):
Memo1.Clear(); |
// Очищення компонента. |
for(i=0; i<=9; i++) |
// Початок циклу за індексами масиву |
|
// для почергового виведення елементів масиву. |
Memo1->Lines->Add(FormatFloat("0.00", A[i]));
Виведення масивів до компонента ListBox організовують так само, як і для компонента Memo, лише замість Memo слід записати компонент ListBox.
Наприклад, замість оператора
Memo1->Lines->Add(FormatFloat("0.00",A[i]));
слід записати
ListBox1->Items->Add(FormatFloat("0.00",A[i]));
Як і при виведенні масивів, при їхньому введенні слід організовувати цикли змінювання зі зміною значення індексу. Розглянемо введення елементів масивів, використовуючи компоненти Memo та ListBox.
Введення елементів одновимірних масивів з різних компонентів
За допомогою компонента Memo можна вводити масиви як при виконуванні програми, так і при конструюванні форми проекту програми через вікно властивості Lines (для переходу до нового рядка при введенні значень треба натиснути клавішу <Enter>).
Приклад фрагмента програми введення значень елементів одновимірного масиву А (в кожному рядку по одному числу):
for(i=0;i<=9;i++) A[i]=StrToFloat(Memo1->Lines->Strings[i]);
За допомогою компонента ListBox можна вводити масиви так само, як і з компонентом Memo, лише замість властивості Lines використовувати властивість Items.
Компонент StringGrid, який також можна використовувати для введеннявиведення одновимірних масивів, буде розглянуто в підрозд. 5.3.
Введення-виведення масиву у консолі
Виведення масиву у консолі за допомогою cout у стовпчик:
for(int i=0; i<n; i++) cout << a[i] << endl;
у рядок через пробіл:
for(int i=0; i<n; i++) cout << a[i] << " "; cout << endl;
Введення масиву за допомогою cin:
for (int i=0; i<n; i++) cin >> a[i];
При цьому числа при введенні можуть бути написані як у стовпчик, так і у рядок через пробіл.
Для введення-виведення символьних масивів у консолі використовуються функції gets() i puts():
char s[50];
168 |
Розділ 5 |
gets(s); |
// Введення символьного масиву s |
puts(s); |
// Виведення символьного масиву s |
Ще раз звернімося до питання стосовно доцільності використання у програмах масивів замість окремих змінних. Порівняймо застосування масиву з 7- ми цілих чисел і 7-ми окремих змінних:
Масив з 7-ми цілих чисел |
7 окремих цілих змінних |
|
|
Оголошення |
|
int a[7]; |
int a, b, c, d, e, f, g; |
|
|
Введення до Memo1 |
|
for(int i=0; i<7; i++) |
a = StrToInt(Memo1->Lines->Strings[0]); |
a[i]=StrToInt(Memo1->Lines-> |
b = StrToInt(Memo1->Lines->Strings[1]); |
Strings[i]); |
c = StrToInt(Memo1->Lines->Strings[2]); |
|
d = StrToInt(Memo1->Lines->Strings[3]); |
|
e = StrToInt(Memo1->Lines->Strings[4]); |
|
f = StrToInt(Memo1->Lines->Strings[5]); |
|
g = StrToInt(Memo1->Lines->Strings[6]); |
|
|
Обчислення суми додатних елементів |
|
|
|
float s=0; |
if (a>0) s=a; |
for(int i=0; i<7; i++) |
if (b>0) s+=b; |
if (a[i]>0) s+=a[i]; |
if (c>0) s+=c; |
|
if (d>0) s+=d; |
|
if (e>0) s+=e; |
|
if (f>0) s+=f; |
|
if (g>0) s+=g; |
|
|
На практиці зазвичай у масивах зберігається набагато більше за 7 елементів і використовування окремих змінних стає, м‟яко кажучи, недоцільним.
5.2.3Програмування базових алгоритмів опрацювання одновимірних масивів
Опрацювання масиву полягає у виконанні операцій над його елементами. Окрім введення-виведення масивів існує перелік найпоширеніших базових алгоритмів опрацювання масивів:
обчислення узагальнювальних характеристик (сум, добутків і кількості елементів);
пошук максимального чи мінімального елемента;
пошук заданих елементів;
переставляння елементів;
упорядкування масивів.
Базові алгоритми опрацювання масивів можуть бути складовими блоками при розв‟язуванні більш складних задач. А тому організовувати їх доцільно у вигляді окремих функцій (див. п. 5.2.4 та розд. 8).