- •Лабораторна робота №1. Тема: Побудова блок-схем алгоритмів засобами програми Word 2010.
- •Хід роботи
- •Лабораторна робота № 2. Тема: Робота та знайомство в середовищі програмування. Запуск програм на виконання. Редагування тексту.
- •Теоретичні відомості
- •Хід роботи
- •Лабораторна робота №3. Тема: Побудова алгоритмів за допомогою DiagramDesigner.
- •Теоретичні відомості
- •Хід роботи
- •Лабораторна робота №4. Тема:Створення лінійних програм. Процедури вводу та виводу в машинному коді. Описати кожний рядок програми в звіті рукописом!!!!!!!!!!!!!!!!!
- •Теоретичні положення
- •Лабораторна робота №5. Тема: Написання програм використовуючі математичні функції. Освоєння арифметичних операторів. Описати кожний рядок програми від руки.
- •Лабораторна робота №6. Тема: Написання програм використовуючи логічні значення Boolean.
- •Теоретичні відомості
- •Булеві значення.
- •Детальний розпис програми:
- •Лабораторна робота №7. Тема: Типи в програмах.
- •Теоретичні положення
- •Хід роботи
- •Лабораторна робота №8. Тема: Оператор вибору в циклах середовища пргограмування.
- •Хід роботи
- •Оператор вибору варiанту.
- •Циклiчнi алгоритми.
- •Циклiчнi алгоритми
- •Лабораторна робота №9. Тема: Використання процедур та функцiй. Звукові можливості Паскаля.
- •Теоретичні відомості
- •Хід роботи
- •Лабораторна робота №10. Тема: Використання перелiчуваного та обмеженого типу даних.
- •Теоретичні відомості
- •Хід роботи
- •Лабораторна робота №11. Тема: Одновимiрнi масиви.
- •Теоретичні відомості
- •1. Одновимірні масиви (рядки, вектори):
- •Можна і так:
- •Хід роботи
- •Двовимiрнi масиви.
- •Лабораторна робота №12. Тема: Використання множин.
- •Теоретичні відомості
- •Хід роботи
- •Лабораторна робота №13. Стандартн і модулі Crt, Dos, System, Graph, Printer. Робота з клавiатурою
- •Теоретичні відомості
- •Іі семестр. Мова програмування с Лабораторна робота №13. Тема: Проста програма на с: друк рядка тексту
- •Лабораторна робота №14. Тема: Арифметика в с. Використання операцій рівності і відношення
- •Лабораторна робота №15 . Тема: Структурна розробка програм. Структура вибору if. Структура вибору if/else. Структура повторення while
- •Операції інкремента і декремента
- •Лабораторна робота №16. Тема: Структурна розробка програм. Структура вибору if. Структура вибору if/else. Структура повторення while
- •Основи структур повторення while
- •Структура повторення for
- •8. Напишіть і запустіть програму на виконання що написана нижче. Потім напишіть програму що кінцевим числом виведе на екран ваш номер варіанту по списку.
- •Лабораторна робота №17. Тема: Програмні модулі в с. Функції математичної бібліотеки
- •Генерація випадкових чисел
- •Рекурсія
- •Обчислення факторіалів рекурсивною функцією
- •Лабораторна робота №18. Тема: Приклади роботи з масивами
- •Передача масивів у функції
- •Лабораторна робота №19. Тема: Сортування масивів
- •Пошук в масивах
- •Двійковий пошук в сортованому масиві
- •Ініціалізація багатовимірних масивів
- •Лабораторна робота №20. Тема: Покажчики
- •Лабораторна робота №21. Тема: Покажчики
- •Лабораторна робота №22. Тема: Форматоване введення/вивід
- •Лабораторна робота №23. Тема: Використання прапорів в рядку управління форматом printf
- •Лабораторна робота №24. Тема: Використання прапорів в рядку управління форматом printf
- •Лабораторна робота №25. Тема: Структури, об′єднання, операції з бітами і перечисленнями
- •10.18. Використання перечислення Лабораторна робота №26. Тема: Створення файлу послідовного доступу
10.18. Використання перечислення Лабораторна робота №26. Тема: Створення файлу послідовного доступу
Мета: Навчитися створювати файли послідовного доступу.
Хід роботи
1. Напишіть програму, на лістингу що нижче, проаналізуйте її.
У С не передбачено можливості завдання структури файлу. Іншими словами, не існує ніяких операцій із записами у файлі, реалізованих як частина мови С. Тому програміст повинен сам потурбуватися про створення структури файлу, що відповідає вимогам конкретного застосування.
У наступному прикладі ми побачимо, як програміст може задати подібну структуру запису.
Програма на лістингу 11.3 створює простий файл послідовного доступу, який можна використовувати в програмі обліку оплати рахунків, заборгованості клієнтів компанії, що допомагає стежити за сумами. Для кожного клієнта програма просить ввести номер рахунку, ім'я клієнта і баланс (тобто суму, яку клієнт повинен компанії за товари і послуги, отримані у минулому).
Дані на кожного з клієнтів утворюють "запис" для цього клієнта. У цьому застосуванні як ключ запису використовується номер рахунку. Іншими словами, файл створюватиметься і підтримуватиметься впорядкованим по номерах рахунків. Ця програма має на увазі, що користувачі вводять записи в порядку зростання номерів. У зручнішій для роботи системі реєстрації рахунків повинна забезпечуватися можливість сортування, щоб користувач міг вводити записи в довільному порядку. В цьому випадку записи повинні спочатку упорядковуватися, а потім вже записуватися у файл.
/* Створення послідовного файлу */
#include <stdio.h>
main ()
{
int account;
char name[30];
float balance;
FILE *cfPtr; /*cfPtr = указатель файла clients.dat */
if ((cfPtr = fopen("clients.dat", "w")) == NULL)
printf("File could not be opened\n");
else {
printf("Enter the account, name, and balance.\n");
printf ("Enter EOF to end input.\n");
printf("? ");
scanf("%d%s%f", &account, name, &balance);
while ( !feof(stdin)) {
fprintf(cfPtr, "%d %s %.2f\n",
account, name, balance);
printf("? ");
scanf("%d%s%f", &account, name, &balance);
}
fclose(cfPtr);
}
return 0;
}
Enter the account, name, and balance.
Enter EOF to end input.
? 100 Jones 24.98
? 200 Doe 345.67
? 300 White 0.00
? 400 Stone -42.16
? 500 Rich 224.62
?
Лістингу 11.3. Создание файла последовательного доступа
Тепер давайте подивимося, як влаштована ця програма. Оператор
FILE *cfPtr;
оголошує, що cfPtr є покажчиком на структуру FILE. Програма на мові С управляє кожним файлом за допомогою окремої структури FILE. Щоб працювати з файлами, програмістові немає необхідності знати, як влаштована ця структура. Скоро ми побачимо, як структура FILE побічно посилається на блок управління файлом (FCB) операційної системи для заданого файлу.
2. Напишіть програму, на лістингу що нижче, проаналізуйте її.
/* Читання і роздрук послідовного файлу */
#include <stdio.h>
main ()
{
int account;
char name[30];
float balance;
FILE *cfPtr; /* cfPtr = покажчик файлу clients.dat */
if ((cfPtr = fopen("clients.dat", "r")) == NULL)
printf ("File could not be opened\n");
else {
printf("%- 10s% - 13s% s\n", "Account", "Name", "Balance")
fscanf(cfPtr, "%d%s%f", &account, name, &balance);
while (!feof(cfPtr)){
printf("%- 10d% - 13s% 7.2f\n", account, name, balance)
fscanf(cfPtr, "%d%s%f", &account, name, &balance);
}
fclose (cfPrt);
}
return 0;
}
Account |
Name |
Balance |
100 |
Jones |
24.98 |
200 |
Doe |
345.67 |
300 |
White |
0.00 |
400 |
Stone |
-42.16 |
500 |
Rich |
224.62 |
Лістингу 11.7. Читання і вивід на друк даних з файлу послідовного доступу
3. Напишіть програму, на лістингу що нижче, проаналізуйте її.
Тепер можна представити програму (лістингу 11.8), яка дозволяє менеджерові по кредиту отримати список клієнтів з нульовим сальдо (клієнтів, які не повинні грошей), клієнтів з позитивним сальдо (яким компанія повинна якусь суму грошей) і клієнтів з негативним сальдо (які повинні компанії гроші за вже отримані товари і послуги).
Відмітимо, що дані в цьому файлі з послідовним доступом не можуть бути змінені без ризику зруйнувати що інші зберігаються у файлі дані. Наприклад, якщо ім'я "White" необхідно поміняти на "Worthington", то не можна просто узяти і переписати старе ім'я. Запис для White був введений у файл як
300 White 0.00
Якщо перезапис з новим ім'ям буде зроблений в тому ж місці файлу, то вона виглядатиме так:
300 Worthington 0.00
Новий запис більший, ніж первинна. Символи після другого "о" в "Worthington" будуть записані вже Поверх наступного запису у файлі. Проблема в даному випадку полягає в тому, що при форматованому введенні/виводі з використанням fprintf і fscanf поля - а отже, і записи - можуть мати змінну довжину. Наприклад, 7, 14, - 117, 2074 і 27383 являються цілими типу int і займають в пам'яті комп'ютера однаковий простір, проте при виведенні їх на екран або при записі на диск за допомогою fprintf вони будуть представлені полями різної довжини.
/*Программа для довідок по кредиту */
include <stdio.h>
main ()
{
int request, account;
float balance;
char name[30];
FILE *cfPtr;
if ((cfPtr = fopen("clients.dat", "r")) == NULL)
printf("File could not be opened\n");
else {
printf("Enter request\n"
" 1 - List accounts with zero balances\n"
" 2 - List accounts with credit balances\n"
" 3 - List accounts with debit balances\n"
" 4 - End of run\n? ");
scanf("%d", &request);
while (request != 4){
fscanf(cfPtr, "%d%s%f", &account, name, &balance);
switch (request){
case 1:
printf("\nAccounts with zero balances:\n");
while(!feof(cfPtr)){
if (balance ==0)
printf("%- 10d% - 13s% 7.2f\n"
account, name, balance);
fscanf(cfPtr, "%d%s%f"
&&account, name, &balance);
}
break;
case 2:
printf("\nAccounts with credit balances: \n");
while (!feof(cfPtr)){
if (balance < 0)
printf("%- 10d% 13s% 7.2f\n"
account, name, balance);
fscanf(cfPtr, "%d%s%f"
&account, name, &balance);
}
break;
case 3:
printf("\nAccounts with debit balances: \n");
while (!feof(cfPtr)){
if (balance >0)
printf("%- 10d% - 13s% 7.2f\n"
account, name, balance);
fscanf (cfPtr, "%d%s%f"
&account, name, &balance);
}
break;
}
rewind(cfPtr);
printf("\n? ");
scanf("%d", &request);
}
printf("End of run.\n");
folose(cfPtr);
}
return 0;
}
Лістингу 11.8. Програма для висновку довідки про кредит
Enter request
1- - List accounts with zero balances
2- - List accounts with credit balances
3- - List accounts with debit balances
4- - End of run
? 1
Accounts with zero balances:
300 White 0.00
? 2
Accounts with credit balances:
400 Stone - 42.16
? 3
Accounts with debit balances:
100 Jones 24.98
200 Doe 345.67
500 Rich 224.62
? 4
End of run
Лістинг 11.9. Приклад виводу довідки про кредит, виконаного програмою на лістингу 11.8
Тому послідовний доступ за допомогою fprintf і fscanf зазвичай не використовується для оновлення записів у файлі. Замість цього переписують увесь файл цілком. Щоб виконати згадувану вище зміну імені, необхідно скопіювати записи, передуючі 300 White 0.00, в новий файл, після чого ввести виправлений запис, а потім дописати в новий файл усі записи після 300 White 0.00. Таким чином, заради того, щоб змінити один запис, доведеться обробити усі записи файлу.
2. Створення файлу довільного доступу. Напишіть програму, на лістингу що нижче, проаналізуйте її.
/*Последовательное створення файлу, з, довільним доступом */
#include <stdio. h>
struct clientData {
int acctNum;
char lastName[15];
char firstName[10];
float balance;
} ;
main ()
{
int i;
struct clientData blankClient = {0, " ", " ", 0.0};
FILE *cfPtr;
if ( (cfPtr = fopenCcredit.dat", "w")) == NULL)
printf("File could not be opened.\n");
else {
for (i = 1; i <= 100; I++)
fwrite (&blankClient
sizeof (struct clientData), 1, cfPtr);
fclose(cfPtr);
}
return 0;
}
Лістинг 11.11. Створення файлу з довільним доступом
Функція fwrite записує блок (задане число байтів) даних у файл. У нашій програмі в результаті виконання оператора
fwrite(&blankClient, sizeof(struct clientData), 1, cfPtr);
структура blankClient розміром sizeof(struct clientData) буде записана у файл, вказаний cfPtr. Операція sizeof повертає розмір в байтах для об'єкту, що міститься в дужках (в даному випадку - це struct clientData). Операція sizeof є виконуваною під час компіляції одномісною операцією, що повертає ціле число без знаку. Операція sizeof може використовуватися для визначення розміру в байтах для будь-якого типу даних або вираження. Приміром, sizeof(int) використовується для того, щоб визначити, зберігається ціле в двох або в чотирьох байтах для цього конкретного комп'ютера.
3. Довільний запис даних у файл довільного доступу. Напишіть програму, на лістингу що нижче, проаналізуйте її.
Програма на рис 11.12 записує дані у файл "credit.dat". Для зберігання даних в спеціально певних місцях файлу використовується комбінація fseek і fwrite. Функція fseek встановлює покажчик позиції файлу в задане положення, після чого fwrite записує дані. Зразок виконання програми показаний на лістингу 11.13.
/* Запис у файл з довільним доступом */
#include <stdio.h>
struct clientData {
int acctNum;
char lastName[15];
char firstName[10];
float balance;
} ;
main ()
{
FILE *cfPtr;
struct clientData client;
if ((cfPtr = fopen("credit.dat", "r+")) == NULL)
printf("File could not be opened.\n");
else {
printf ( "Enter account number"
" (1 to 100, 0 to end input)\n? ");
scanf("%d", &client.acctNum);
while (client.acctNum !=0){
printf ("Enter lastname, firstname, balance\n? ");
scanf("%s%s%f", &client.lastName
&client.firstName, &client. balance);
fseek(cfPtr, (client.acctNum - 1) *
sizeof (struct clientData), SEEK_SET);
fwrite (&client, sizeof (struct clientData), 1, cfPtr);
printf("Enter account number\n? ");
scanf ("%d", &client.acctNum);
}
}
fclose(cfPtr);
return 0;
}
Enter account number (1 to 100, 0 to end input)
? 37
Enter lastname, firstname, balance
? Barker Doug 0.00
Enter account number
? 29
Enter lastname, firstname, balance
? Brown Nancy - 24.54
Enter account number
? 96
Enter lastname, firstname, balance
? Stone Sam 34.98
Enter account number
? 88
Enter lastname, firstname, balance
? Smith Dave 258.34
Enter account number
? 33
Enter lastname, firstname, balance
? Dunn Stacey 314.33
Enter account number
? 0
Лістингу 11.13. Приклад виконання програми на лістингу 11.12
Оператор
fseek(cfPtr, (accountNum - 1) * sizeof (struct clientData)
SEEK_SET);
встановлює покажчик позиції файлу, на який посилається cfPtr на байт, визначуваний вираженням (accountNum - 1) * sizeof(struct clientData); значення цього виразу називається зміщенням. Оскільки номер рахунку - число від 1 до 100, а байти у файлі починаються з нульового, то при знаходженні положення байта з номера рахунку віднімається 1. Таким чином, для першого запису покажчик позиції файлу встановлюється на байт 0 файлу. Символічна константа SEEK_SET показує, що покажчик позиції файлу встановлюється відносно початку файлу на величину зміщення. Розгляд приведеного вище оператора показує, що пошук у файлі рахунку з номером 1 встановлює покажчик позиції файлу на початок файлу, оскільки вичислене значення дорівнює 0. На лістингу 11.14 показаний покажчик файлу, що посилається на структуру FILE в пам'яті. Покажчик позиції файлу показує, що наступний байт, який буде лічений або записаний, це п'ятий байт від початку файлу.
4. Приклад: програма обробки транзакцій. Напишіть програму, на лістингу що нижче, проаналізуйте її.
У цьому розділі буде представлена досить складна програма обробки транзакцій, оброблювальна файли довільного доступу. Вона призначена для роботи з банківськими рахунками. Програма дозволяє оновлювати існуючі рахунки, додавати нові, знищувати рахунки і зберігати список усіх поточних рахунків у файлі текстового формату для виводу на друк. Передбачається, що була виконана програма на лістингу 11.11, що створює файл credit.dat.
/* Послідовне читання файлу з произввольным доступом */
#include <stdio.h>
struct clientData {
int acctNum;
char lastName[15];
char firstName[10];
float balance;
} ;
main ()
{
FILE *cfPtr;
struct clientData client;
if ((cfPtr = fopen("credit.dat", "r")) == NULL)
printf("File could not be opened.\n");
else {
printf("%- 6s% - 16s% - lls%10s\n", "Acct", "Last Name"
"First Name", "Balance");
while (!feof(cfPtr)){
fread(Sclient, sizeof(struct clientData), 1, cfPtr);
if (client.acctNum !=0)
printf("%- 6d% - 16s% - 11s% 10.2f\n"
client.acctNum, client.lastName,
client.firstName, client.balance);
}
}
fclose(cfPtr);
return 0;
}
Acct |
Last Name |
First Name |
Balance |
29 |
Brown |
Nancy |
-24.54 |
33 |
Dunn |
Stacey |
314.33 |
37 |
Barkey |
Doug |
0.00 |
88 |
Smith |
Dave |
258.34 |
96 |
Stone |
Sam |
34.98 |
Лістингу 11.15. Послідовне прочитування з файлу довільного доступу
Програма має п'ять опцій. Опція 1 викликає функцію textFile для збереження списку усіх рахунків, що відформатував, в текстовому файлі, з ім'ям accounts.txt, який пізніше можна вивести на друк. Функція використовує fread і метод послідовного доступу до файлу, який був використаний раніше в програмі, представленій на лістингу 11.15. Після вибору опції 1 створюється файл accounts.txt, що містить наступний текст, :
Acct |
Last Name |
First Name |
Balance |
29 |
Brown |
Nancy |
-24.54 |
33 |
Dunn |
Stacey |
314.33 |
37 |
Barkey |
Doug |
0.00 |
88 |
Smith |
Dave |
258.34 |
96 |
Stone |
Sam |
34.98 |
Опція 2 викликає функцію updateRecord для оновлення рахунку. Функція призначена для оновлення вже існуючих записів, тому спочатку вона перевіряє, чи не є вказаний користувачем запис порожнім. Запис прочитується в структуру client за допомогою функції fread, після чого елемент acctNum порівнюється з 0. Якщо він дорівнює 0, то запис не містить ніякої інформації, і видається повідомлення, що запис порожній. Після чого на екрані знову з'являється меню вибору. Якщо запис містить інформацію, функція updateRecord вводить суму транзакції, обчислює новий баланс і переписує відповідний запис у файлі. Типовий результат виконання опції 2 виглядає таким чином:
Enter account to update (1 - 100) : 37
37 Barker Doug 0.00
Enter charge (+) or payment (-) : +87.99
37 Barker Doug 87.99
Опція 3 викликає функцію newRecord для додавання у файл нового рахунку. Якщо користувач вводить вже існуючий номер рахунку, newRecord видає повідомлення про помилку, що цей запис вже містить інформацію, після чого на екран знову виводиться меню вибору. Ця функція використовує той же процес додавання нового рахунку, що і програма на лістингу 11.12. Типовий результат виконання опції 3 виглядає таким чином:
Enter new account number (1 - 100) : 22
Enter lastname, firstname, balance
? Johnson Sarah 247.45
Опція 4 викликає функцію deleteRecord для видалення запису з файлу. Користувача просять ввести номер рахунку, який необхідно видалити, після чого виконується повторна ініціалізація запису. Якщо рахунок не містить інформації, deleteRecord видає повідомлення про помилку, що вказаного рахунку не існує. Опція 5 перериває виконання програми. Повний текст програми представлений на лістингу 11.16. Помітимо, що файл "credit.dat" відкритий для оновлення (читання і записи) із специфікацією режиму "r+".
5. Приклад: програма обробки транзакцій. Напишіть програму, на лістингу що нижче, проаналізуйте її.
/* Програма послідовно читає файл довільного доступу, *
Лабораторна робота №1. Тема: Побудова блок-схем алгоритмів засобами програми Word 2010. 3
Лабораторна робота № 2. Тема: Робота та знайомство в середовищі програмування. Запуск програм на виконання. Редагування тексту. 5
Лабораторна робота №3. Тема: Побудова алгоритмів за допомогою DiagramDesigner. 6
Лабораторна робота №4. Тема:Створення лінійних програм. Процедури вводу та виводу в машинному коді. 8
Лабораторна робота №5. Тема: Написання програм використовуючі математичні функції. Освоєння арифметичних операторів. 10
Лабораторна робота №6. Тема: Написання програм використовуючи логічні значення Boolean. 12
Лабораторна робота №7. Тема: Типи в програмах. 15
Лабораторна робота №8. Тема: Оператор вибору в циклах середовища пргограмування. 17
Лабораторна робота №9. Тема: Використання процедур та функцiй. Звукові можливості Паскаля. 21
Лабораторна робота №10. Тема: Використання перелiчуваного та обмеженого типу даних. 25
Лабораторна робота №11. Тема: Одновимiрнi масиви. 27
Лабораторна робота №12. Тема: Використання множин. 30
ІІ семестр. Мова програмування С 34
Лабораторна робота №13. Тема: Проста програма на С: друк рядка тексту 34
Лабораторна робота №14. Тема: Арифметика в С. Використання операцій рівності і відношення 35
Лабораторна робота №15 . Тема: Структурна розробка програм. Структура вибору if. Структура вибору if/else. Структура повторення while 38
Лабораторна робота №16. Тема: Структурна розробка програм. Структура вибору if. Структура вибору if/else. Структура повторення while 41
Лабораторна робота №17. Тема: Програмні модулі в С. Функції математичної бібліотеки 47
Лабораторна робота №18. Тема: Приклади роботи з масивами 57
Лабораторна робота №19. Тема: Сортування масивів 67
Лабораторна робота №20. Тема: Покажчики 80
Лабораторна робота №21. Тема: Покажчики 97
Лабораторна робота №22. Тема: Форматоване введення/вивід 116
Лабораторна робота №23. Тема: Використання прапорів в рядку управління форматом printf 122
Лабораторна робота №24. Тема: Використання прапорів в рядку управління форматом printf 125
Лабораторна робота №25. Тема: Структури, об′єднання, операції з бітами і перечисленнями 128
Лабораторна робота №26. Тема: Створення файлу послідовного доступу 138
#include <stdio.h>
struct clientData {
int acctNum;
char lastName[15];
char firstName[10];
float balance;
} ;
int enterChoice(void);
void textFile(FILE *);
void updateRecord(FILE *);
void newRecord(FILE *);
void deleteRecord(FILE *);
main ()
{
FILE *cfPtr;
int choice;
if ((cfPtr = fopen("credit.dat", "r+")) == NULL)
printf("File could not be opened.\n");
else {
while ((choice = enterChoice()) != 5){
switch (choice){
case 1:
textFile (cfPtr);
break;
case 2 :
updateRecord(cfPtr);
break;
case 3:
newRecord(cfPtr);
break;
case 4:
deleteRecord(cfPtr);
break;
}
}
}
fclose(cfPtr);
return 0;
}
void textFile(FILE *readPtr)
{
FILE *writePtr;
struct clientData client;
if ((writePtr = fopen("accounts.txt", "w")) == NULL)
printf("File could not be opened.\n");
else {
rewind(readPtr);
fprintf(writePtr, "%- 6s% - 16s% - 11s% 10s\n"
"Acct", "Last Name", "First Name", "Balance");
while (!feof(readPtr)){
fread(&client, sizeof (struct clientData), 1, readPtr);
if (client.acctNum !=0)
fprintf(writePtr, "%- 6d% - 16s% - 11s% 10.2f\n",
client.acctNum, client.lastName,
client.firstName, client.balance);
}
}
fclose(writePtr);
}
void updateRecord(FILE *fPtr)
{
int account;
float transaction;
struct clientData client;
printf("Enter account to update (1 - 100) : ");
scanf("%d", &account);
fseek(fPtr, (account - 1) * sizeof (struct clientData),
SEEK_SET);
fread(&client, sizeof(struct clientData), 1, fPtr);
if (client.acctNum == 0)
printf("Acount #%d has no information.\n", account);
else {
printf("%- 6d% - 16s% - 11s% 10.2f\n\n"
client.acctNum, client.lastName,
client.firstName, client.balance);
printf("Enter chrge (+) or payment(-) : ");
scanf("%f", &transaction);
client.balance += transaction;
printf("%- 6d% - 16s% - 11s% 10.2f\n"
client.acctNum, client.lastName,
client.firstName, client.balance);
fseek(fPtr, (account - 1) * sizeof(struct clientData),
SEEK_SET);
fwrite(&client, sizeof(struct clientData), 1, fPtr);
}
}
void deleteRecord(FILE *fPtr)
{
struct clientData client, blankClient = {0, " ", " ", 0};
int accountNum;
printf("Enter account number to delete (1-100) : ");
scanf("%d", &accountNum);
fseek(fPtr, (accountNum - 1) * sizeof (struct clientData),
SEEK_SET);
fread(&client, sizeof(struct clientData), 1, fPtr);
if (client.acctNum == 0)
printf("Accout %d does not exist.\n", accountNum);
else {
fseek(fPtr, (accountNum - 1) * sizeof(struct clientData),
SEEK SET);
fwrite(&blankClient, sizeof (struct clientData), 1, fPtr);
}
}
void newRecord(FILE *fPtr)
{
struct clientData client;
int accountNum;
printf ("Enter new account number (1-100) : ");
scanf("%d", &accountNum);
fseek(fPtr, (accountNum - 1) * sizeof(struct clientData),
SEEK_SET);
fread(sclient, sizeof(struct clientData), 1, fPtr);
if (client.acctNum !=0)
printf("Account #%d already contains information.\n",
client.acctNum);
else {
printf("Enter lastname, firstname, balance\n? ");
scanf ("%s%s%f", sclient.lastName, sclient.firstName,
&client.balance);
client.acctNum = accountNum;
fseek(fPtr, (client.acctNum - 1) *
sizeof(struct clientData), SEEK_SET);
fwrite(&client, sizeof(struct clientData), 1, fPtr);
}
}
int enterChoice(void)
{
int menuChoice;
printf ("\nEnter your choice\n"
"1 - store a formatted text file of accounts called\n"
" \"accounts.txt\" for printing\n"
"2 - update an account\n"
"3 - add a new account\n"
"4 - delete an account\n"
"5 - end program\n? ");
scanf("%d", &menuChoice);
return menuChoice;
Лістингу 11.16. Програма роботи з банківськими рахунками
6. Напишіть програму, на лістингу що нижче, проаналізуйте її.
/* Операцій над списком */
#include <stdio.h>
#include <stdlib.h>
struct listNode { /* структура з посиланням на себе */
char data;
struct listNode *nextPtr;
};
typedef struct listNode LISTNODE;
typedef LISTNODE *LISTNODEPTR;
void insert(LISTNODEPTR *, char);
char delete(LISTNODEPTR *, char);
int isEmpty(LISTNODEPTR);
void printList(LISTNODEPTR);
void instructions(void);
main ( )
{
LISTNODEPTR startPtr = NULL;
int choice;
char item;
instructions(); /* вивести меню */
printf("? ");
scanf("%d", &choice);
while (choice !=3){
switch (choice){
case 1:
printf("Enter a character: ");
scanf("\n%c", &item);
insert(&startPtr, item);
printList(startPtr);
break; case 2:
if (!isEmpty(startPtr)){
printf ("Enter character to be deleted: ")
scanf ("\n%c", &item);
if (delete(&startPtr, item)){
printf("%c deleted.\n", item);
printList(startPtr);
}
else
printf("%c not found.\n\n", item)
}
else
printf("List is empty.\n\n");
break;
default:
printf("Invalid choice.\n\n");
instructions ();
break;
}
printf("? ");
scanf("%d", &choice);
}
printf("End of run.\n");
return 0;
}
/* Роздрук інструкції */
void instructions(void)
{
printf("Enter your choice:\n"
" 1 to insert an element into the list.\n"
" 2 to delete an element from the list.\n"
" 3 to end.\n");
}
/* Вставка нового значення у впорядкований список */
void insert(LISTNODEPTR *sPtr, char value)
{
LISTNODEPTR newPtr, previousPtr, currentPtr;
newPtr = malloc(sizeof(LISTNODE));
if (newPtr != NULL){ /* чи доступна пам'ять? */
newPtr ->data = value;
newPtr ->nextPtr = NULL;
previousPtr = NULL;
currentPtr = *sPtr;
while (currentPtr != NULL && value > currentPtr ->data){
previousPtr = currentPtr; /* перейти .. */
currentPtr = currentPtr ->nextPtr; /* .. до наступного */
}
if (previousPtr == NULL){
newPtr ->nextPtr = *sPtr;
*sPtr = newPtr;
}
else {
previousPtr ->nextPtr = newPtr;
newPtr ->nextPtr = currentPtr;
}
}
else{
printf("%c not inserted. No memory available.\n", value);
}
/* Видалення елементу списку */
char delete(LISTNODEPTR *sPtr, char value)
{
LISTNODEPTR previousPtr, currentPtr, tempPtr;
if (value == (*sPtr) ->data){
tempPtr = *sPtr;
**sPtr = (*sPtr) ->nextPtr; /* від'єднати вузол */
free(tempPtr); /* звільнити вузол */
return value;
}
else {
previousPtr = *sPtr;
currentPtr = ( *sPtr) ->nextPtr;
while (currentPtr != NULL && currentPtr ->data != value){
previousPtr = currentPtr; /* перейти .. */
currentPtr = currentPtr ->nextPtr; /* .. до наступного */
}
if (currentPtr != NULL){
tempPtr = currentPtr;
prevlousPtr ->nextPtr = currentPtr ->nextPtr;
free (tempPtr);
return value;
}
}
return '\0';
}
/* Повернути 1, якщо список порожній, інакше - 0 */
int isEmpty(LISTNODEPTR sPtr)
{
return sPtr == NULL;
}
/* Print the list */
void printList(LISTNODEPTR currentPtr)
{
if (currentPtr == NULL)
printf("List is empty.\n\n");
else {
printf("The list is:\n");
while (currentPtr != NULL){
printf("%c -> "currentPtr ->data);
currentPtr = currentPtr ->nextPtr;
}
printf ("NULL\n\n");
}
}
Enter your choice:
1 to insert an element into the list.
2 to delete an element from the list.
3 to end.
? 1
Enter a character :В
The list is:
B --> NOLL
? 1
Enter a character: A
The list is:
A --> В --> NOLL
? 1
Enter a character: C
The list is:
A --> В --> C --> NULL
? 2
Enter character to be deleted: D
D not found.
? 2
Enter character to be deleted: B
В deleted.
The list is:
A --> C -> NULL
? 2
Enter character to be deleted: C
C deleted.
The list is:
A --> NULL
? 2
Enter character to be deleted: A
A deleted.
List is empty.
? 4
Invalid choice.
Enter your choice:
1 to insert an element into the list.
2 to delete an element from the list.
3 to end.
? 3
End of run.
Лістингу 12.4. Приклад результату роботи програми на лістингу 12.3
Дві основні функції пов'язаних списків - insert і delete. Функція isEmpty називається предикативною функцією - вона ніяк не міняє список, а усього лише визначає, чи є список порожнім (тобто покажчик на перший вузол списку рівний NULL). Якщо список порожній, повертається значення 1, інакше 0. Функція printList роздруковує список.
Символи вставляються в список в алфавітному порядку. Функції insert передаються адреса списку і символ, який необхідно вставити. Адреса списку потрібна, коли значення має бути вставлене в початок списку. Передача адреси списку дозволяє модифікувати список (тобто покажчик на перший вузол списку) через виклик по посиланню. Оскільки список сам по собі є покажчиком (на свій перший елемент), при передачі адреси списку створюється покажчик на покажчик (іншими словами, це подвійна непряма адресація). Це складне поняття, що вимагає дуже акуратного програмування. Щоб вставити символ в список, необхідно виконати наступні кроки (див. лістингу 12.5) :
Зв'язці вузла стека не привласнюється NULL.
7. Напишіть програму, на лістингу що нижче, проаналізуйте її.
Основні функції, використовувані при роботі із стеками, - push і pop. Функція push створює новий вузол і поміщає його на вершину стека. Функція pop видаляє верхній вузол стека, звільняє пам'ять, яка була виділена вилученому вузлу, і повертає вилучене значення.
Програма на лістингу 12.8 (результат її виконання представлений на лістингу 12.9) працює з простим стеком цілих чисел. Програма виконує три дії на вибір: 1) поміщає значення в стек (функція push), 2) вилучає значення із стека (функція pop), і 3) завершує роботу.
/* Програма динамічного стека */
#include <stdio.h>
#include <stdlib.h>
struct stackNode { /* структура, що посилається на себе */
int data;
struct stackNode *nextPtr;
};
tupedef struct stackNode STACKNODE;
tupedef STACKNODE*STACKNODEPTR;
void push (STACKNODEPTR*, int);
int pop (STACKNODEPTR*);
int isEmpty (STACKNODEPTR);
void printStack (STACKNODEPTR);
void instructions (void);
main ()
{
STACKNODEPTR stackPtr = NULL; /* вказує на вершину */
int choice, value;
instructions();
printf ("? ");
scanf("%d", &choice);
while (choice !=3){
switch (choice){
case 1: /* заштовхує значення в стек */
printf("Enter an integer: ");
scanf("%d", &value);
push(&stackPtr, value);
printStack(stackPtr);
break;
case 2: /* виштовхує значення із стека */
if (!isEmpty(stackPtr))
printf("The popped value is %d.\n"
pop(&stackPtr));
printStack(stackPtr);
break;
default:
printf("Invalid choice.\n\n");
instructions ();
break;
}
printf ("? ");
scanf("%d", &choice);
}
printf("End of run.\n");
return 0;
}
/* Роздрук інструкцій */
void instructions(void)
{
printf("Enter choice:\n"
"1 to push a value on the stack\n"
"2 to pop a value off the stack\n"
"3 to end program\n");
}
/* Приміщення нового значення на вершину стека */
void push (STACKNODEPTR *topPtr, int info)
{
STACKNODEPTR newPtr;
newPtr = malloc(sizeof(STACKNODE));
if (newPtr != NULL){
newPtr ->data = info;
newPtr ->nextPtr = *topPtr;
**topPtr = newPtr;
}
else
printf("%d not inserted. No memory available.\n", info);
}
/* Видалення вузла на вершині стека */
int pop(STACKNODEPTR *topPtr)
{
STACKNODEPTR tempPtr;
int popValue;
tempPtr = *topPtr;
popValue = (*topPtr) ->data;
*topPtr = (*topPtr) ->nextPtr;
free(tempPtr);
return popValue;
}
/* Роздрук стека */
void printStack(STACKNODEPTR currentPtr)
{
if (currentPtr == NULL)
printf ("The stack is empty.\n\n");
else {
printf("The stack is:\n");
while (currentPtr != NULL){
printf("%d ->"currentPtr ->data);
currentPtr = currentPtr ->nextPtr;
}
printf("NULL\n\n");
}
}
/* Стек порожній? */
int isEmpty(STACKNODEPTR topPtr)
{
return topPtr == NULL;
}
Лістингу 12.8. Проста програма, що ілюструє роботу із стеком
Enter choice:
1 to push a value on the stack
2 to pop a value off the stack
3 to end program
? 1
Enter an integer: 5
The stack is:
5----> NULL
? 1
Enter an integer: 6
The stack is:
6----> 5 ---> NULL
? 1
Enter an integer: 4
The stack is:
4---> 6 --> 5 --> NULL
? 2
The popped value is 4.
The Stack is:
6----> 5 --> NULL
? 2
The popped value is 6.
The Stack is:
5--> NULL
? 2
The popped value is 5,
The stack is empty.
? 2
The stack is empty.
? 4
Invalid choice.
Enter choice.:
1 to push a value on the stack
2 to pop a value off the stack
3 to end program
? 3
End of run.
Лістингу 12.9. Результат виконання програми на лістингу 12.8
Функція push поміщає новий вузол на вершину стека. У виконанні функції можна виділити три етапи:
1) Створення нового вузла за допомогою виклику malloc, при цьому покажчику newPtr привласнюється адреса блоку виділеної пам'яті, змінній newPtr ->data привласнюється значення, яке необхідно помістити в стек, і покажчику newPtr ->nextPtr привласнюється NULL.
2) Покажчику newPtr ->nextPtr привласнюється *topPtr (покажчик на вершину стека); зв'язуючий елемент newPtr тепер вказує на вузол, який був верхнім до цього.
3) *topPtr привласнюється значення newPtr; *topPtr тепер вказує на нову вершину стека.
8. Черга.Напишіть програму, на лістингу що нижче, проаналізуйте її.
Програма на лістингу 12.13 (результат її виконання показаний на лістингу 12.14) - приклад роботи з чергою. Програма пропонує виконати наступні дії на вибір: поставити вузол в чергу (функція enqueue), видалити вузол з черги (функція dequeue), і вийти з програми.
/* Підтримка черги */
#include <stdio.h>
#include <stdlib.h>
struct queueNode { /* структура, що посилається на себе */
char data;
struct queueNode *nextPtr;
} ;
typedef struct queueNode QUEUENODE;
typedef QUEUENODE *QUEUENODEPTR;
/* function prototypes */
void printQueue(QUEUENODEPTR);
int isEmpty(QUEUENODEPTR);
char dequeue(QUEUENODEPTR *, QUEUENODEPTR *);
void enqueue(QUEUENODEPTR *, QUEUENODEPTR *, char);
void instructions (void);
main ()
{
QUEUENODEPTR headPtr = NULL, tailPtr = NULL;
int choice;
char item;
instructions ();
printf ("? ");
scanf("%d", &choice);
while (choice !=3){
switch(choice){
case 1 :
printf("Enter a character: ");
scanf("\n%c", &item);
enqueue (&headPtr, &tailPtr, item);
printQueue(headPtr);
break;
case 2 :
if (! isEmpty(headPtr)){
item = dequeue(&headPtr, &tailPtr);
printf("%c has been dequeued.\n", item);
}
printQueue(headPtr);
break;
default:
printf ("Invalid choice.\n\n");
instructions();
break;
}
printf ("? "); scanf("%d", &choice);
}
printf("End of run.\n");
return' 0;
}
void instructions(void)
}
printf ("Enter your choice:\n"
" 1 to add an item to the queue\n"
" 2 to remove an item from the queue\n"
" 3 to end\n");
}
void enqueue(QUEUENODEPTR *neadPtr, QUEUENODEPTR *tailPtr,
char value)
{
QUEUENODEPTR newPtr;
newPtr =malloc(sizeof(QUEUENODE));
if (newPtr != NULL){
newPtr ->data = value;
newPtr ->nextPtr = NULL;
if (isEmpty(*headPtr))
*headPtr = newPtr;
else
(*tailPtr) ->nextPtr = newPtr;
*tailPtr = newPtr;
}
else
printf("%c not inserted. No memory available.\n"value);
{
char dequeue(QUEUENODEPTR *headPtr, QUEUENODEPTR *tailPtr)
{
char value;
QUEUENODEPTR tempPtr;
value = (*headPtr) ->data;
tempPtr = *headPtr;
*headPtr = (*headPtr) ->nextPtr;
if (*headPtr == NULL)
*tailPtr = NULL;
free(tempPtr);
return value;
}
int isEmpty(QUEUENODEPTR headPtr){
return headPtr == NULL;
void printQueue(QUEUENODEPTR currentPtr)
{
if (currentPtr == NULL)
printf("Queue is empty.\n\n");
else {
printf("The queue is ;\n");
while (currentPtr != NULL){
printf("%c --> ", currentPtr ->data)
currentPtr = currentPtr ->nextPtr;
}
printf("NULL\n\n");
}
}
Лістингу 12.13. Робота з чергою
Enter your choice:
1 to add an item to the queue
2 to remove an item from the queue
3 to end
? 1
Enter a character: A
The queue is:
A -> NULL
? 1
Enter a character: В
The queue is:
A --> В --> NULL
? 1
Enter a character: C
The queue is:
A -> B -> C ->NULL
? 2
A has been dequeued.
The queue is:
B -> C -> NULL
? 2
B has been dequeued.
The queue is:
C --> NULL
? 2
C has been dequeued.
Queue is empty.
? 2
Queue is empty.
? 4
Invalid choice.
Enter your choice:
1 to add an item to the queue
2 to remove an item from the queue
3 to end
? 3
End of run.
Лістингу 12.14. Приклад виконання програми, представленої на лістингу 12.13
Функція enqueue отримує від main три аргументи: адреса покажчика на голову черги, адресу покажчика на хвіст черги і значення, яке необхідно поставити в чергу. Виконання функції складається з трьох кроків:
1) Створення нового вузла : викликати malloc, присвоїти адресу виділеного блоку пам'яті newPtr, присвоїти newPtr ->data значення, яке необхідно поставити в чергу, a newPtr ->nextPtr присвоїти NULL.
2) Якщо черга порожня, присвоїти *headPtr покажчик newPtr; інакше присвоїти цей покажчик (*tailPtr) ->nextPtr.
3) І нарешті, присвоїти *tailPtr покажчик newPtr.
9. Дерева. Напишіть програму, на лістингу що нижче, проаналізуйте її.
/* Створення двійкового дерева і його обхід
з порядковою, попередньою і відкладеною вибіркою*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct treeNode {
struct treeNode *leftPtr;
int data;
struct treeNode *rightPtr;
} ;
typedef struct treeNode TREENODE;
typedef TREENODE *TREENODEPTR;
void insertNode(TREENODEPTR *, int);
void inOrder(TREENODEPTR);
void preOrder(TREENODEPTR);
void postOrder(TREENODEPTR);
main ()
{
int i, item;
TREENODEPTR rootPtr = NULL;
srand(time(NULL));
/* спробувати розмістити в дереві 10 випадкових чисел в діапазоні від 0 до 14 */
printf("The numbers being placed in the tree are:\n");
for (i = 1; i <= 10; i ++.){
item = rand() % 15;
printf("%3d", item);
insertNode(&rootPtr, item);
}
/* обійти дерево з попередньою вибіркою */
printf("\n\nThe preOrder traversal is:\n");
preOrder(rootPtr);
/* обійти дерево з порядковою вибіркою */
printf("\n\nThe inOrder traversal is:\n");
inOrder(rootPtr);
/* обійти дерево з відкладеною вибіркою */
printf("\n\nThe postOrder traversal is:\n");
postOrder(rootPtr);
return 0;
}
void insertNode(TREENODEPTR *treePtr, int value)
{
if (*treePtr == NULL){ /* *treePtr рівний NULL */
*treePtr = malloc(sizeof(TREENODE));
if (*treePtr != NULL){
(*treePtr) ->data = value;
(*treePtr) ->leftPtr = NULL;
(*treePtr) ->rightPtr = NULL;
}
else
printf("%d not inserted. No memory available.\n",
value);
}
else
if (value < (*treePtr) ->data)
insertNode(&((*treePtr)->leftPtr)value);
else
if (value > (*treePtr) ->data)
insertNode(&((*treePtr)->rightPtr)value);
else
if (value > (*treePtr) ->data)
insertNode (&((*treePtr)->rightPtr), value);
else
printf ("dup");
}
void inOrder(TREENODEPTR treePtr)
{
if (treePtr != NULL){
inOrder(treePtr ->leftPtr);
printf("%3d", treePtr ->data);
inOrder(treePtr ->rightPtr);
}
}
void preOrder(TREENODEPTR treePtr)
{
if (treePtr != NULL){
printf("%3d", treePtr ->data);
preOrder(treePtr ->leftPtr);
preOrder(treePtr ->rightPtr);
}
}
void postOrder(TREENODEPTR treePtr)
{
if (treePtr != NULL){
postOrder(treePtr ->leftPtr);
postOrder(treePtr ->rightPtr);
printf("%3d", treePtr ->data);
}
}
Лістингу 12.19. Створення і обхід двійкового дерева
1) Якщо *treePtr рівний NULL, створити новий вузол. Викликати malloc, присвоїти виділену пам'ять *treePtr, присвоїти (*treePtr) ->data ціле значення, яке необхідно зберегти, присвоїти (*treePtr), ->leftPtr і (*treePtr) ->rightPtr значення NULL, і повернути управління зухвалої функції (або main, або попередньому виклику insertNode).
2) Якщо значення *treePtr не NULL і значення, яке необхідно вставити менше, ніж (*treePtr), ->data, функція insertNode викликається з адресою (*treePtr) ->leftPtr. Інакше функція insertNode викликається з адресою (*treePtr) ->rightPtr. Рекурсивні кроки тривають до тих пір, поки не буде виявлений покажчик NULL, після чого виконується пункт 1) - вставка нового вузла.
The numbers being placed in the tree are:
7 8 0 6 14 1 Odup 13 Odup 7dup
The preOrder traversal is:
7 0 6 1 8 14 13
The inOrder traversal is:
0 1 6 7 8 13 14
The postOrder traversal is:
1 6 0 13 14 8 7
Лістинг 12.20. Приклад вихідних даних при виконанні програми лістингу 12.19
Функції inOrder, preOrder і postOrder отримують дерево (тобто покажчик на кореневий вузол) і проходять по ньому.
У функції inOrder (порядкова вибірка) виконуються наступні кроки:
Обійти за допомогою inOrder ліве поддерево.
Обробити значення у вузлі.
Обійти за допомогою inOrder праве поддерево.
Значення у вузлі не обробляється до тих пір, поки не будуть оброблені значення в його лівому поддереве. Прохід за допомогою inOrder по дереву, зображеному на мал. 12.21, виглядає таким чином:
6 13 17 27 33 42 48
6 17 33 48
Мал. 12.21. Двійкове дерево пошуку.
