ЛАБОРАТОРНА РОБОТА № 10
Тема: Вказівники і масиви
Мета: отримання практичних навичок в роботі із вказівниками і з адресною арифметикою в мові C++.
Завдання для виконання
Виконати завдання лабораторної роботи №8 з такими додатковими умовами:
розмір масиву визначається на початку виконання програми як випадкове число в діапазоні 50 - 200;
у тексті програми забороняється застосовувати операцію індексації.
Приклад рішення задачі
№ варіанту |
Розмірність масиву |
Діапазон значень |
Що треба зробити |
30 |
100 |
-50 - 50 |
У усіх послідовностях негативних чисел обмежити значення тих елементів, абсолютне значення яких перевищує абсолютне середнє для цієї послідовності |
Розробка алгоритму рішення.
На початку виконання, після ініціалізації датчика випадкових чисел, треба отримати випадкове число в діапазоні 50 - 200 (назвемо його size) і виділити пам'ять для масиву цілих чисел розміром size. Перед самим виходом з програми ми повинні звільнити виділену пам'ять.
Простіше за усе завдання могло б бути виконано простою заміною в усіх місцях операції індексації на операцію адресації, маючи на увазі тотожність:
Ar[i] *(Ar+i)
Це відповідало б букві завдання, але не духу мови C. Якщо ми переходимо від індексації до адресації, у нас усувається необхідність в індексах і навіть в змінних, які їх представляють. Це призводить до іншого способу реалізації усіх циклів. Якщо ім'я масиву Ar є покажчиком на його початок, то замість циклу, в якому індекс i міняється від 0 до size, ми можемо організувати цикл, в якому деякий поточний покажчик Cr міняється від Ar до Ar+size. Також, коли нам треба запам'ятати початок негативної послідовності, ми можемо запам'ятовувати не індекс відповідного елементу, а його адресу - покажчик на нього.
Визначення змінних програми
Пам'ять для масиву цілих чисел в нашій роботі не виділяється на етапі компіляції, так що нам досить оголосити в програмі тільки змінну - покажчик на початок масиву :
int *Ar;
Розмірність масиву визначається при виконанні програми, так що для її збереження потрібна окрема змінна:
int size;
Замість змінних, які є індексами елементів масиву, ми застосовуватимемо покажчики:
int *Cr; це буде покажчик на поточний елемент масиву при його повному переборі;
int *Ir; у цьому покажчику зберігатиметься адреса початку негативної послідовності, а потім - при обробці послідовності - адреса поточного її елементу.
Змінні для збереження суми елементів і середнього значення і кількості елементів в послідовності:
int av;
int nn;
Розробка тексту програми
Підключаємо заголовні файли:
# #include <stdio.h>
# #include <time.h>
# #include <stdlib.h>
включаємо також файл alloc.h, в якому знаходяться описи функцій динамічного виділення/звільнення пам'яті :
# #include <alloc.h>
Починаємо головну функцію і оголошуємо в ній змінні. Кодова частина програми починається з ініціалізації датчика випадкових чисел і отримання випадкового числа для розміру масиву :
randomize();
size=random(151)+50;
Функція rand повертає нам число в діапазоні 0 - 150, збільшенням до нього 50 ми переводимо його в діапазон 50 - 200. Отриманий розмір масиву відразу виводиться на екран:
printf("size =%d\n", size);
Звертаємося до функції виділення пам'яті :
Ar=(int far *) malloc(size*sizeof(int));
Функція malloc() вимагає параметр - розмір запитаної пам'яті в байтах. Змінна size - це кількість елементів в масиві; для завдання розміру пам'яті в байтах множимо її на розмір одного елементу. Функція malloc() повертає покажчик, що не типізується, ми перетворимо його в покажчик на int і записуємо в змінну Ar.
Далі організовуємо цикл перебору масиву. У одному циклі і отримуємо випадкові числа, і виводимо початковий масив на екран. Заголовок цього циклу :
for (Cr=Ar; Cr<Ar+size; Cr++){
У початкових установках циклу ми записуємо в змінну Cr адресу початку масиву, тобто Cr показує на елемент з індексом 0. У кінці кожної ітерації Cr збільшується на 1, тобто показує на наступний елемент масиву. Остання ітерація відбувається при значенні Cr=Ar+size - 1, тобто Cr показуватиме на останній елемент. У кожній ітерації ми звертаємося до поточного елементу масиву як *Cr, тобто звертаємося до того, на що показує покажчик Cr.
Далі йде заголовок циклу перебору масиву, який організовується та ж, як попередній, але в початкових установках ми ще привласнювано початкове значення лічильнику nn.
У тілі циклу до поточного елементу масиву ми звертаємося через покажчик на нього: *Cr. Там, де нам вимагається запам'ятати початок негативної послідовності, ми просто зберігаємо поточне значення покажчика Cr в змінній-покажчику Ir.
Внутрішній цикл, в якому обробляється негативна послідовність, :
for (av/=nn; Ir<Cr; Ir++)
if (*Ir<av) *Ir=av;
Початкові установки цього циклу - тільки усереднювання значення в av, змінна Ir вже містить в собі покажчик на перший елемент негативної послідовності. У кінці кожної ітерації Ir збільшується на 1, тобто показує на наступний елемент послідовності (звернення до цього елементу - *Ir). Остання ітерація відбувається при значенні Ir=Cr - 1, оскільки Cr показує на перший позитивний елемент за негативною послідовністю.
Передостанній оператор - звернення до функції free() для звільнення пам'яті, яка була виділена функцією malloc(), : free(Ar);
Повний текст програми приведений нижче.
/****************************************************/
/* /* Лабораторна робота ╧11 */
/* /* Покажчиків і масиви */
/* /* Приклад виконання. Варіант ╧30. */
/****************************************************/
##include <stdio.h>
##include <time.h>
##include <stdlib.h>
##include <alloc.h>
int main(void){
int size; /* розмір масиву */
int *Ar; /* покажчик на початок масиву */
int *Cr, *Ir; /* поточних покажчиків */
int av, nn; /* середнє значення і
кількість елементів в послідовності */
randomize(); /* ініціалізація rand */
size=random(151)+50;
printf("size =%d\n", size);
/* /* виділень пам'яті */
Ar=(int far *) malloc(size*sizeof(int));
/* /* заповнення масиву випадковими числами і
виведення початкового масиву */
printf("Початковий масив:\n");
for (Cr=Ar; Cr<Ar+size; Cr++){
* *Cr=random(101) - 50;
printf("%3d ",*Cr);
}
putchar('\n');
/* /* перебір масиву */
for (nn=0, Cr=Ar; Cr<Ar+size; Cr++){
if (*Cr<0)
/* /* обробка негативного елементу */
if (!nn){
/* /* початок послідовності : запам'ятати адресу
почала в Ir, встановити початкове значення
накопичувача суми і лічильнику елементів */
Ir=Cr; av=*Cr; nn=1;
}
else {
/* /* підрахунок суми і кількості елементів */
av+=*Cr; nn++;
}
/* /* кінець обробки негативного елементу */
else /* обробка позитивного елементу */
if (nn){
/* /* якщо є необроблена негативна послідовність:
усереднювання і перебір з обмеженням */
for (av/=nn; Ir<Cr; Ir++)
if (*Ir<av) *Ir=av;
nn=0; /* послідовність оброблена */
} /* кінець якщо необроблена.. */
} /* кінець перебору масиву */
if (nn) /* якщо не оброблена остання
негативна послідовність */
for (av/=nn; Ir<Cr; Ir++)
if (*Ir<av) *Ir=av;
/* /* виведення результатів */
printf("Масив-результат:\n");
for (Cr=Ar; Cr<Ar+size; printf("%3d ",*Cr++));
putchar('\n');
/* /* звільнення пам'яті */
free(Ar);
return 0;}