- •Київський національний університет імені Тараса Шевченка
- •Гриф надано Міністерством освіти і науки України (лист № 1.4/18-г-1523 від 20.09.07)
- •Основи алгоритмізації
- •1.1. Поняття алгоритму
- •1.2. Класифікація внутрішніх структур алгоритмів
- •1. Ввести а,b.
- •3. Вивести значення s.
- •4. Кінець.
- •6. Закінчити роботу.
- •1. Ввести число n.
- •6. Перехід до п.3.
- •7. Друк к.
- •8. Кінець.
- •1.3. Складність алгоритмів
- •1.4. Складність задач
- •Завдання для самостійної роботи
- •Форма Бекуса – Наура
- •Завдання для самостійної роботи
- •Void main(){
- •3.2. Структура с-програми
- •3.3. Описувачі
- •3.4. Основні операції мови с
- •If(!inword)
- •Void main()
- •Int rozmir;
- •3.5. Оператори мови с
- •3.5.1. Прості оператори
- •3.5.2. Умовний оператор
- •3.5.3. Оператор циклу for
- •3.5.4. Оператори do-while, while
- •3.5.5. Оператор continue
- •3.5.6. Оператор-перемикач switch
- •3.5.7. Оператор break
- •3.5.8. Оператор goto
- •If(error(I,j,k)) goto exit;
- •3.5.9. Оператор return
- •3.6. Директиви препроцесору та вказівки компілятору
- •3.6.1. Директива препроцесору #define
- •1. Макровизначення:
- •3.6.3. Директива #include
- •3.6.4. Директиви умовної компіляції #if, #elif, #else, #endif
- •3.6.5. Директива #line
- •If(!cond)
- •3.7. Описувачі з модифікаторами
- •3.7.1. Моделі пам'яті
- •3.7.2. Модифікатори типу доступу в пам'яті
- •Int huge*near X;
- •3.7.3. Модифікатори const, volatile, cdecl, pascal, interrupt
- •Volatile int t;
- •Void interrupt timer()
- •Void wait(int interval)
- •Завдання для самостійної роботи
- •Принципи типізації даних
- •4.1. Прості типи даних
- •4.2. Похідні типи
- •4.3. Еквівалентність типів
- •4.4. Успадкування атрибутів
- •4.5. Перераховні типи
- •4.6. Логічні типи
- •4.7. Символьні типи
- •4.8. Числові типи
- •4.9. Структурні типи даних
- •4.9.1. Масиви
- •4.9.2. Структури
- •Int year;
- •4.10. Деякі особливості типів даних c
- •4.10.1. Базові типи даних
- •4.10.2. Перетворення типів
- •Int atoi(char s[]) /*char* s*/
- •4.10.3. Засіб typedef
- •Int curs;
- •4.10.4. Покажчики та масиви
- •Void * p;
- •Int array[12];
- •Void f(int a[])
- •Int f(char * s)
- •Наведемо деякі приклади розв'язання задач.
- •Int shift; /*відступ*/
- •Int count[n]; /*кількість монет даного типу (коефіцієнти ai)*/
- •Int coin;
- •Int sum; /*монета, яку міняємо*/
- •Int maxcoin; /*індекс по масиву cost[] монети максимальної вартості, допустимої при даному розміні.*/
- •If(count[I])
- •If(maxcoin)
- •Int* ctranspon (int *a,int n,int m)
- •Void dobutok(int* a, int* b, int** c, int n, int m)
- •Int n,m,I,size;
- •Int main()
- •4.10.5. Структури та об'єднання
- •Розглянемо деякі приклади розв'язання задач.
- •Int hashfunc(key); int eqkey(key, key);
- •Void freeval(val); void setval(val, val);
- •Void freekey(key); void setkey(key, key);
- •Int hashfunc(key key){
- •Val val; /*значення*/
- •Void set(key key, val val){
- •Void printcell(struct cell *ptr){
- •Void main(void)
- •Завдання для самостійної роботи
- •Зображення чисел у комп'ютері
- •Int main(void)
- •5.1. Системи числення
- •5.2. Правила переведення чисел з однієї системи числення в іншу
- •5.3. Правило визначення точності зображення
- •5.4. Двійкова арифметика
- •5.4.1. Додавання двійкових чисел
- •5.4.2. Зображення від'ємних чисел
- •XXXXXXXX 00000001 00000000.
- •5.4.3. Віднімання двійкових чисел
- •5.4.4. Множення двійкових чисел
- •5.4.5. Ділення двійкових чисел
- •5.5. Ознака переповнення розрядної сітки при арифметичних операціях
- •5.6. Зображення цілих чисел
- •5.7. Зображення дійсних чисел
- •5.8. Керування машинним зображенням чисел та особливості виконання арифметичних операцій
- •Завдання для самостійної роботи
- •Реалізація концепції структурного програмування
- •6.1. Оголошення та визначення функцій
- •Int d;} people;
- •6.2. Формальні та фактичні параметри
- •Void swap(int a,int b)
- •Void swap(int a,int*b)
- •6.3. Функції зі змінною кількістю параметрів
- •Void sum(char *msg,...)
- •6.5. Параметри функції main
- •6.6. Лiтернi покажчики та функцiї
- •Void strcpy(char*s,char*t)
- •Void f(void)
- •6.8. Класи пам'яті
- •Розглянемо деякі приклади розв'язання задач.
- •I, power(2,I),power(-3,I));
- •Void main() { choturukyt b; tochka *a; float s; long n,in; srand(time(null));
- •6.9. Введення–виведення с. Файли та потоки
- •6.9.1. Функції введення–виведення верхнього рівня
- •6.9.2. Функції введення–виведення консольного термінала та порту
- •Int main(void)
- •6.9.3. Функції введення–виведення нижнього рівня
- •Int main(void)
- •Int handle;
- •Розглянемо приклади розв'язання задач.
- •Void main(void)
- •Void main(argc,argv)
- •If(c& masks[I])
- •If (цей рядок довший за найдовший з попередніх)
- •Int max; /*максимальна довжина*/
- •Int len; /*довжиною цього рядка*/
- •Int nwords; /*кількість слів у рядку*/
- •If(!*s) /*рядок закінчився*/
- •Int ctr; /*кількість входжень слова*/
- •If(!strcmp(word,w[I].Wrd)){
- •If(alert){
- •Void main() { float X,y,z,t,s; int I,j,flag,n,k; m1: clrscr();
- •InitBase (void){
- •Int key, /*новий ключ*/
- •InitBase();
- •Завдання для самостійної роботи
- •7.1. Елементи концепції обєктно-орієнтованого програмування
- •Int year;
- •Int year;
- •7.3. Опис протоколу класу
- •7.4.1. Коментарі
- •7.4.2. Прототипи функцій
- •Void f();
- •7.4.5. Перевантаження функцій
- •Int Name (int first)
- •Int Name (unsigned first)
- •Int Name (int first,char*second)
- •7.4.6. Значення формальних параметрів за умовчанням
- •7.4.7. Посилання й покажчики
- •Void increment(int& X)
- •Int anotherint;
- •7.4.10. Покажчик на void
- •Void*void_ptr;
- •Void swap(void*&item1,void*&item2)
- •7.4.11. Зв'язування зі збереженням типів
- •7.4.12. Про структури та об'єднання
- •7.5. Функції-члени класу
- •X *this;
- •Int year;
- •7.6. Конструктори та деструктори
- •7.6.1. Поняття про конструктори
- •Int*data;
- •Int size;
- •7.6.3. Конструктор копіювання
- •Int data[large];
- •Inline Large1 Large1::fast(const Large1 & b)
- •7.7. Глобальні та локальні об'єкти
- •Void main(void)
- •7.8. Статична пам'ять і класи
- •Int statpol::I;
- •Vоid draw()
- •Int large;
- •Int bigwant;
- •Void f() {
- •Void g(int a)
- •7.9. Успадкування
- •7.9.1. Синтаксична реалізація успадкування
- •7.9.2. Правила доступу до полів даних
- •Void f(void)
- •Void g(void){}//...}
- •7.9.3. Конструктори та деструктори в похідних класах
- •7.9.4. Використання заміщуючих функцій-членів
- •Void Display (void); //замiщувальна функцiя
- •Void Region::Display(void)
- •Void Display(void);};
- •Void Population::Display(void)
- •7.9.5. Похідні класи й покажчики
- •7.9.6. Ієрархія типів
- •XyValue(int_x,int_y):X(_x),y(_y)
- •XyData(int_x,int_y)
- •7.9.7. Множинне успадкування
- •Void SetLoc(int_x,int_y);};
- •Int data;
- •7.10. Віртуальні функції та класи
- •7.10.1. Віртуальні функції
- •Int value;
- •Virtual int GetValue();
- •Int Value::GetValue(){return value;}
- •7.10.2. Чисті віртуальні функції. Абстрактні класи
- •Virtual void f1(void);
- •Virtual void f2(void);//...}
- •Int index;
- •7.10.3. Віртуальні деструктори
- •7.10.4. Посилання як засіб для реалізації поліморфізму
- •7.10.5. Дещо про механізм віртуальних функцій
- •Virtual int method1(float r);
- •Int data;
- •Void func(void){//тіло}};
- •Virtual public CocaCola {
- •Int size;
- •Void ShowValue(void)
- •Void ShowValues(void);};
- •Void Two::ShowValues(void)
- •7.11.2. Дружні функції
- •Void Show(One &c1,Two &c2)
- •Void Show(One &c1);
- •Void Two::Show(One &c1)
- •7.12. Перевантаження операцій
- •7.12.1. Загальний підхід
- •Void main()
- •7.12.2. Перетворення типів
- •X::operator т();
- •7.12.3. Перевантаження операції індексування масиву
- •Int znach;
- •7.12.4. Перевантаження операції виклику функції
- •Int operator()(void);
- •Int FuncClass::operator()(void)
- •Vidnosh*vec;
- •7.12.5. Перевантаження операції доступу до члена класу
- •7.12.6. Перевантаження операцій інкремента й декремента
- •Int index;
- •Void*operator new(size_t)
- •Void*operator new(size_t);
- •8.1. Функціональні шаблони
- •8.1.1. Визначення й використання шаблонів функцій
- •Void func(t t)
- •Int main(void)
- •8.1.2. Перевантаження шаблонів функції
- •Int main(void)
- •8.1.3. Cпецiалiзованi функцiї шаблона
- •Int main(void){
- •8.2. Шаблони класів
- •8.2.1. Визначення шаблонів класу
- •Void push(t t);
- •Int numitems;
- •8.2.2. Константи й типи як параметри шаблона
- •8.2.3. Використання шаблонних класів
- •Int main(void)
- •8.2.4. Спеціалізація шаблонів класу
- •Void add(t item);
- •Int main(void)
- •IArray.Add(i1);
- •Int main(void)
- •IList.Add(i1);
- •Завдання для самостійної роботи
- •Автоматна технологія програмування
- •If(!stop)printf("не входити");
- •Завдання для самостійної роботи
- •Список літератури
- •Передмова 3
Int f(char * s)
{int i;
for (i=0;*s='\0';i++;s++);
return i;}
/*функція обраховує кількість елементів рядка*/
char s[10];
Можемо викликати функцію
f(&s[i]); або f(s+i).
Допускається існування масиву покажчикiв:
int * a[20];
Покажчики на масив і багатовимірні масиви. Визначення int(*a)[20]задає покажчик на масив. У цьому випадку ім'я а також задає адресу першого елемента масиву, але додавання до такого покажчика, наприклад, одиниці приведе до збільшення адреси на всю довжину масиву – у даному випадку – 20 елементів типу int.
Для розуміння механізму інтерпретації багатовимірних масивів можемо навести такі міркування. Одновимірний масив int a[10] може бути розглянутий через покажчик (а містить адресу першого елемента):
int * pa;
pa=a;
pa++==a[1];
Двовимірний масив int a[5][10] інтерпретується як покажчик на масив із 10 елементів:
int (*pa)[10];
pa=a;
Тоді
*(pa++)==a[1][0];
*(*(pa)+1)==a[1][1];
Аналогічно, якщо розглянути, наприклад, тривимірний масив
int b[10][20][30];
то він інтерпретується як покажчик на двовимірний масив розмірністю 20 30:
int (*pb)[20][30];
pb=b;
Тоді ***(pb++)==b[1][0][0], *(**(pb++)+1)==b[1][0][1].
Ім'я b міститиме адресу тривимірного масиву (першого його елемента). Тоді b[0],b[1],…,b[9] – адреси відповідних двовимірних масивів, b[i][j] – одновимірних. Наприклад:
int d[1][3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int d1[1][3][4]={111,2,3,4,5,6,7,8,9,10,11,12};
main()
{
printf("%d',***(d+1));
}
Буде надруковане значення 111 – першого елемента масиву d1.
У загальному випадку доступ до елемента n-вимірного масиву a[N][N]…[N] здійснюється за таким правилом:
a[m1][m2]…[mn]=*(a[0][0]…[0]+m1*Nn-1 +m2*Nn-2+…+mn)
n-1 нульових індексів
При роботі з динамічними масивами необхідно звернути особливу увагу на виділення пам'яті за допомогою функцій malloc чи calloc.
Наведемо деякі приклади розв'язання задач.
1. Розглянемо алгоритм сортування методом "бульбашки". Розсортируємо літери в рядку у порядку зростання їх кодів. Причому розглянемо два варіанти програми: із застосуванням операції індексації до елементів рядка та без нього, лише через покажчики. Ідея сортування методом "бульбашки" досить проста. Розглядаючи масив зліва направо, перевіряємо, чи менший перший елемент за наступний. Якщо ця умова виконується, то розглядається другий елемент масиву і т. д. Якщо ж виявиться, що поточний елемент більший за наступний, то ці елементи міняються місцями, і перегляд масиву починається спочатку.
Перший варіант програми:
#define YES 1
#define NO 0
bsort(char *s)
{
register int i; /*індекс літери, що порівнюється*/
register int need=YES; /*чи потрібно продовжувати сортування*/
while(need){
need=NO; /*не потрібно*/
for(i=0; s[i+1]; i++)
/*умова циклу: ми порівнюємо i-ту та i+1-шу літери,
*тому перевіряємо наявність i+1-ї літери*/
if(s[i]>s[i+1]){/*у неправильному порядку*/
swap(&s[i], &s[i+1]); /*переставити*/
need=YES; /*щось змінилось: потрібно
*повторити перегляд масиву літер*/
}
}
}
Другий варіант програми:
bpsort(char *s)
{
register char *p; register need=YES;
while(need){
need=NO;
for(p=s; p[1] !='\0'; p++)
if(*p>*(p+1)){
swap(p, p+1); need=YES;
}
}
}
/*обмін двох літер, що знаходяться за адресами s1 і s2*/
swap(s1, s2) register char *s1, *s2;
{
char tmp; /*temporary*/
tmp=*s1; *s1=*s2; *s2=tmp;
}
char sample1[]="Homo homini lupus est – ergo bibamus!";
char sample2[sizeof(sample1)]; /*масив такого самого обсягу*/
main(){
strcpy(sample2, sample1); /*скопіювати*/
bsort (sample1); printf("%s\n", sample1);
bpsort(sample2); printf("%s\n", sample2);
}
Специфікацію пам'яті register у даному прикладі використано з метою збільшення швидкодії програми, що не принципово. Слід звернути увагу на використання функції swap ().
2. Переформатуємо матрицю так, щоб її стовпчики розміщувались за спаданням їх поелементних сум.
Матрицю запишемо в динамічному масиві. При цьому слід звернути увагу на специфіку виділення пам'яті за допомогою функції malloc:
sum=(int *)malloc(m*sizeof(int));arr=(int *)malloc(n*m*sizeof(int));
При такому виділенні пам'ять має бути коректно звільнена за допомогою функції free():
free(sum);free(arr);
Текст програми:
#include <stdio.h> #include <conio.h> #include <stdlib.h> void main() {int i,j,k,n,m,t,*sum,*arr; clrscr(); puts("Введи n");
scanf("%d%d",&n,&m); sum=(int *)malloc(m*sizeof(int)); arr=(int *)malloc(n*m*sizeof(int)); for(i=0;i<n;i++) for(printf("\n"),j=0;j<m;j++) {*(arr+i*m+j)=rand()%21;printf("%4d",*(arr+i*m+j));} printf("\n\n"); for(j=0;j<m;j++) {for(i=0,sum[j]=0;i<n;i++) sum[j]+=*(arr+i*m+j); printf("%4d",sum[j]); } for(i=1;i<m;i++) for(j=0;j<m-i;j++) {if(sum[j]>=sum[j+1]) continue; t=sum[j];sum[j]=sum[j+1];sum[j+1]=t; for(k=0;k<n;k++) {t=*(arr+k*m+j);*(arr+k*m+j)=*(arr+k*m+j+1);*(arr+k*m+j+1)=t;} } printf("\n\n"); for(i=0;i<n;i++) for(printf("\n"),j=0;j<m;j++) printf("%4d",*(arr+i*m+j)); printf("\n\n"); for(j=0;j<m;j++) printf("%4d",sum[j]);
free(sum);free(arr); getch(); }
3. Нехай у масиві записано деякий текст. Обчислимо середню кількість слів у реченні та середню довжину речення:
#include <stdio.h> #include <conio.h> #include <string.h> void main() { char text[128], //вихідний текст copy[128], //копія вихідного тексту *p, //початок чергового речення *s, //початок чергового слова raz1[]="!?.", //роздільники речень raz2[]=".?!,;: ";//роздільники слів intl, //довжина тексту k, //кількість речень u; do { clrscr(); puts("Введіть вхідний текст"); gets(text); l=strlen(text); strcpy(copy,text); for(p=strtok(text,raz1),k=0;p!=NULL;p=sttok(NULL,raz1)) k++; for(s=strtok(copy,raz2),u=0;s!=NULL;s=strtok(NULL,raz2)) u++; puts("Середня довжина речень:"); printf("%5d",l/k); puts("\nСередня кількість слів у реченні"); printf("%5d",u/k); puts("\nДля продовження натисніть ENTER, для виходу – ESC"); }while(getch()!=27); }
4. Нехай задано цілочисельний арифметичний вираз, записаний як рядок у десятковій системі числення. Перевіримо правильність його запису й обчислимо значення. Вираз записано без дужок, операції виконуються в порядку їх наступності.
#include <stdio.h> #include <string.h> #include <conio.h> #include <stdlib.h>
void main() { char a_v[80], a_v1[80], *p, c[40]; char *oper="+-*/%", *cifr="0123456789", *c_o="0123456789+-*/%"; int a[40], l_a_v, l, i, j, jk, ac; textmode(1); textcolor(YELLOW); textbackground(BLUE); m1:clrscr(); puts("Введіть арифметичний вираз: "); gets(a_v); strcpy(a_v1, a_v); l_a_v=strlen(a_v); l=strspn(a_v,c_o); if(l!=l_a_v) {puts("\n Помилка у виразі"); goto end;} p=strtok(a_v, oper); i=0; do { a[i++]=atoi(p); } while(p=strtok(NULL, oper)); strcpy(a_v, a_v1); p=strtok(a_v, cifr); j=0; do { c[j++]=*p; } while(p=strtok(NULL, cifr)); if(i!=j+1) {puts("\n Помилка у виразі"); goto end;} jk=j; ac=a[0]; i=j=0; while(j<jk) { switch(c[j++]) { case '+' : ac+=a[++i]; break; case '-' : ac-=a[++i]; break; case '*' : ac*=a[++i]; break; case '/' : ac/=a[++i]; break; case '%' : ac%=a[++i]; } } strcpy(a_v, a_v1); printf("\n%s=%d", a_v, ac); end: printf("\n\n Для продовження натисніть 7:"); scanf("%d", &l); getchar(); if(l==7) goto m1;}
5. Зашифруємо текст методом Гронсфельда. Ключем у цьому методі є скінченна послідовність цифр, яку записують підряд над символами тексту, що шифрується так: замість кожної літери у вихідному тексті друкується символ, віддалений від цієї літери (у вибраній системі кодування, напр., ascii) на величину відповідного елемента ключа, що стоїть над цією літерою.
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <string.h> void main() { int n,*arr,i; char str[301],ch;
srand(time(NULL)); m1: clrscr(); printf("Введіть текст(не більше 300 символів), що закінчується <Enter>:\n"); gets(str); n=strlen(str);
arr=NULL; arr=(int*) calloc(n,sizeof(int));//виділення пам’яті
clrscr();
puts("Введений текст:"); printf("\"%s\"",str);
putchar('\n'); puts("\nСформований ключ:"); for(i=0;i<n;i++) { /*заповнення масиву випадковими числами з діапазону [0...99] та друк*/ arr[i]=rand()%100; printf("%4d",arr[i]); }
for(i=0;i<n;i++) str[i]-=arr[i]; printf("\n\nЗашифрований текст:\n"); putchar('"'); for(i=0;i<n;i++) printf("%c",str[i]); putchar('"');
puts("\n\nРозшифровка:"); putchar('"'); for(i=0;i<n;i++) printf("%c",str[i]+arr[i]); putchar('"');
free(arr); //очищення пам’яті printf("\n\nПродовжуємо? (7 - так):"); if(getch()=='7') goto m1; }
6. Відцентруємо рядки тексту. Вхідні рядки не мають містити табуляцій.
#include <stdio.h>
extern char *gets();
#define WIDTH 60 /*ширина аркуша*/
main(){
char rd[81]; register char *s;
char *head, /*початок тексту*/
*tail; /*кінець тексту*/
register int len, i;