Первая страница
Наша команда
Контакты
О нас

    Головна сторінка



Та програмування

Та програмування




Сторінка8/11
Дата конвертації10.03.2017
Розмір2.35 Mb.
1   2   3   4   5   6   7   8   9   10   11

Синтаксис: int strcmpi(const char *s1, const char*s2)


Параметри:

- const char *s1 – вказівник на перший порівнюваний рядок;

- const char *s2 – вказівник на другий порівнюваний рядок.

Функція аналогічна strchr(), strcmp(), strcoll(), stricmp(), strncmp(), strnicmp()



Приклад 6.5.


/*strcmpi.cpp*/

#include

#include

#include

main(int argc, char *argv[])

{

char *p;



if (argv <= 2)

{

puts("Введіть два рядки, що порівнюються без урахування різниці між малими та великими літерами");



puts("Наприклад, STRCMPI рядока рядокб");

exit(1);


}

int result = strcmpi(argv[1], argv[2]);

if (result < 0)

p = "менше";

else if (result > 0)

p = "більше";

else

p = "дорівнює";



printf("%s %s %s", argv[1], p, argv[2]);

return 0;

}

Функція strcpy() копіює вихідний рядок src і нульовий символ, який його завершує, у рядок результату dst, перезаписуючи символи підсумкового рядка, розташовані в місці копіювання. Повертає dest. (string.h)



Синтаксис: char *strcpy(char *dest,const char *src);

char far * far _fstrcpy(char far *dest, const char far *src);

Параметри:

- char *dest – вказівник на рядок результату, що перезаписується вихідним рядком. Підсумковий рядок не обов'язково повинен бути ініціалізованим;

- const char *srcвказівник на вихідний рядок, що завершується нульовим символом.

Функція аналогічна stpcpy(), strncpy()


Приклад 6.6.

/*strcpy.cpp*/

#include

#include

main()

{

char src[80] = "abcdefghij";



char dst[80] = "1234567890";

puts("Викликаємо strcpy(приймач, джерело)");

strcpy(dst, src);

printf("Після: джерело==%s приймач==%s\n", src, dst);

return 0;

}
Функція strdate()запам'ятовує поточну дату у вигляді рядка у форматі mm/dd/yy (mm – місяць, dd – день, yy – рік. Повертає datestr, (time.h)

Синтаксис: char *_strdate(cha *datestr);

Параметри:

- char *datestr – вказівник на підсумковий рядок довжиною, принаймні, 9 байтів.

Функція аналогічна asctime(), ctime(), strtime(), time()


Приклад 6.7.

/*_strdate.cpp*/

#include

#include

main()

{

char sdate[9];



_strdate(sdate);

printf(": %s\n", sdate);

return 0;

}

Функція strerror() створює з рядка s рядок повідомлення про помилку, додаючи двокрапку, пропуск і опис поточної системної помилки (string.h чи stdio.h).



Синтаксис: char *_strerror(const char *s);

Параметри:

- const char *s – повідомлення користувача про помилку довжиною не більше 94 символів, до якого додається повідомлення про системну помилку. Якщо цей вказівник дорівнює нулю, _strerror() повертає вказівник на рядок повідомлення про помилку з найостаннішим кодом помилки.

Функція аналогічна perror(), strerror()


Приклад 6.8.

#include

#include

main()


{

char *p = _strerror("Перевірне повідомлення про помилку");

printf("Повідомлення про помилку == %s\n", p);

p = _strerror(NULL);

printf("Найостанніша помилка == %s\n", p);

return 0;

}

Функція strftime()форматує дату і час у вигляді текстового рядка, використовуючи систему правил перетворення, аналогічну системі printf(). Форматний рядок fmt містить одне чи декілька правил, що заміняються компонентами дати і часу. Крім того, форматний рядок може також містити й інші символи, що не належать до правил перетворення. Повертає число символів, записаних у підсумковий рядок (time.h). Правило перетворення складається зі знака відсотка (%) і символу.



Синтаксис: size_t strftime(char *s, size_t maxsize, const char *fmt, const struct tm *t);

Параметри:

- char *s – вказівник на підсумковий рядок, в який запам'ятовується результат функції;

- size_t maxsize – максимальне число символів, записуваних у підсумковий рядок. Звичайно встановлюється рівним розміру рядка мінус одиниця;

- const char *fmt – вказівник на форматний рядок, що містить звичайний текст і правила перетворення;

- const struct tm *t – вказівник на структуру типу tm, що містить дату і час, форматуємо у рядок.

Функція аналогічна asctime(), ctime(), localtime(), mktime(), time().

Таблиця 6.2 – Правила перетворення для strftime()



Правила перетворення

Компоненти дати і часу

%

Вставити знак відсотка (%)

A

День тижня (абревіатура: Sun, Mon і т. д.)

A

Повна назва дня тижня

B

Місяць (абревіатура: Jan, Feb і т. д.)

B

Повна назва місяця

С

Дата і час у форматі asctime()

D

День місяця (від 01 до 31)

H

Час в 24-годинному форматі (від 00 до 23)

I

Час в 12-годинному форматі (від 00 до 12)

J

День року (від 001 до 366)

M

Номер місяця (від 1 до 12)

M

Хвилина (від 00 до 59)

P

Букви АМ чи РМ (що позначають час до чи після півдня відповідно)

S

Секунда (від 00 до 59)

U

Номер тижня (від 00 до 53) (тиждень починається з неділі)

w

День тижня (від 0 до 6) (неділя == 0)

W

Номер тижня (від 00 до 53) (тиждень починається з понеділка)

X

Дата

X

Час

Y

Рік мінус сторіччя (наприклад, 68 для 1968)

Y

Повний рік (наприклад, 1968)

Z

Найменування часової зони (EST чи EDT)

Приклад 6.9.

#include

#include

#define SIZE 80

main()


{

time_t t;

struct tm *tp;

char s[SIZE];

time(&t);

tp = localtime(&t);

puts("");

strftime(s, SIZE, "Дата: %x\n", tp);

puts(s);

strftime(s, SIZE, "Час: %x\n", tp);

puts(s);

strftime(s, SIZE, "Сьогодні %A\n", tp);

puts(s);

return 0;

}

Функція strncpy(), fstrncpy()копіює максимум maxlen символів із вихідного рядка src у підсумковий рядок dest, перезаписуючи символи підсумкового рядка. Якщо maxlen дорівнює розміру в байтах підсумкового рядка (і вихідний рядок має не меншу довжину), то підсумковий рядок не завершується нульовим символом. Якщо maxlen і довжина вихідного рядка перевищують розмір підсумкового рядка, кінець підсумкового рядка перезаписується, що, можливо, зруйнує інші дані чи код у цьому місці пам'яті. Щоб уникнути подібних помилок, ніколи не встановлюйте maxlen більше максимального числа символів, що їх може містити підсумковий рядок (string.h)



Функція аналогічна strcat(), strcpy()

Приклад 6.10.


#include

#include

main ( )

{

char src[80] = "abcdefghij";



char dst[80] = "1234567890";

printf ("До: src = =%s dst = =%s \n", src, dst);

puts ("Викликаємо strncpy (dst, src, 5)");

strncpy (dst, src, 5);

printf ("Після: src == %s dst = = %s \n", src, dst);

return 0;

}
Функція strstr(), fstrstr()шукає рядок (s2) в іншому рядку (s1). Повертає адресу першого символу входження рядка або, якщо підрядок s2 не знайдений в рядку s1, – повертає нуль (string.h)

Синтаксис:

char *strstr (const char *s1, const char *s2);

char far *far _ fstrstr (const char far *s1, const char far *s2);


Параметри:

- const char *s1 – вказівник на рядок, у якому відбувається пошук підрядка, адресуємо s2;

- const char *s2вказівник на підрядок, що шукається в рядку, який адресується s1.

Функція аналогічна strchr(), strcmp(), strspn()


Приклад 6.11.

/*strstr.cpp*/

#include

#include

main ()

{

char *s1= "filename.cpp";



char *s2=".cpp";

printf ("s1= = %s \n", s1 );

printf ("s2= = %s \n", s2);

puts ("Викликаємо char *s3 = strstr (s1, s2) ");

char *s3= strstr (s1, s2);

printf ("s3== %s \n", s3);

return 0;

}
Функція strtod()перетворить символьне подання числа з плаваючою крапкою, що міститься в рядку, у його двійкове подання типу double чи long double. У випадку успіху повертає отриманий при перетворенні результат, а у випадку помилки повертає HUGE_VAL (strtod ()) чи LHUGE _VAL помилки повертає HUGE_VAL (strtod ()) чи LHUGE _VA (stdlib.h)

Синтаксис:

double strtod (const char *s, char **endptr);

long double strtold (const char *s, char ** endptr);
Параметри:

- const char *s – вказівник на рядок, що містить символьне подання числа з плаваючою крапкою або в десятковій нотації (наприклад, “123.45”), або в науковій нотації (наприклад, “4.5е-3”);

- char **endptr – якщо цей параметр не дорівнює нулю, то він повинен бути рівним адресі символу, розташованого безпосередньо після останнього символу в рядку s, що бере участь у перетворенні. Цей необов'язковий вказівник використовується при аналізі рядків, що містять кілька значень з плаваючою комою, можливо, розділених символами пропуску, комами.

Функція аналогічна atof(), printf(), sprintf(), strtol()


Приклад 6.12.

#include

#include

#include

main (int argc, char *argv [ ])

{

if (argc <= 1)



{

puts ("Введіть значення типу double");

puts ("наприклад, STRTOD 3.14159");

exit (1);

}
char *endptr;

double d = strtod (argv[1], &endptr);

printf ("Значення у двійковому поданні = = %lf \n", d);
if (strlen (endptr)>0)

printf ("Перегляд зупинено на: %s \n", endptr);

return 0;

}
Функція strtol() – перетворить символьне подання значення типу long у його двійкове подання. Значення в рядку може бути подано в десятковому, вісімковому чи шістнадцятковому вигляді, що використовує стандартні правила форматування мови С (що діють для printf( ), scanf( ) та інших аналогічних функцій). Розпізнаються також інші основи системи числення, від 2 до 36.

Системою числення, або нумерацією, називається сукупність правил і знаків, за допомогою яких можна відобразити (кодувати) будь-яке невід'ємне число. До систем числення висуваються певні вимоги, серед яких найбільш важливими є вимоги однозначного кодування невід'ємних чисел 0, 1,… з деякої їх скінченної множини - діапазону Р за скінченне число кроків і можливості виконання щодо чисел арифметичних і логічних операцій. Крім того, системи числення розв'язують задачу нумерації, тобто ефективного переходу від зображень чисел до номерів, які в даному випадку повинні мати мінімальну кількість цифр. Від вдалого чи невдалого вибору системи числення залежить ефективність розв'язання зазначених задач і її використання на практиці.
У випадку успіху функція повертає перетворений результат і встановлює ненульовий вказівник endptr, рівним адресі, що слідує за останнім символом, який входить у символьне подання числа. У випадку помилки функція повертає нуль і встановлює ненульовий вказівник endptr, рівним s.

Синтаксис:

long strtol (const char *s, char **endptr, int radix);


Параметри:

- const char *s – вказівник на рядок, що містить ціле значення типу long у текстовому вигляді. Цій рядок може також містити й інші символи;

- char ** endptr – якщо цей параметр не дорівнює нулю, то він повинен бути рівним адресі символу, розташованого безпосередньо після останнього символу в рядку s, що бере участь у перетворенні. Цей необов'язковий вказівник використовується при аналізі рядків, що містять кілька значень типу long, можливо, поділених символами пропуску, комами і т. п.;

- int radix – задає основу системи числення, яка використовується при перетворенні і може приймати значення від 2 до 36. Наприклад, 2 – для двійкових значень, 10 – для десяткових значень, 16 – для шістнадцяткових значень і т. д. Літери від A до Z розпізнаються як числові символи для основ, що перевищують 10. (При основі 16 для подання числа використовуються цифри від 0 до 9 і букви від А до F, при основі 17 – цифри від 0 до 9 і букви від А до G і т. п.) Якщо параметр radix встановлений рівним нулю, функція буде автоматично розпізнавати і перетворювати числа, використовуючи стандартні правила форматування мови С, тобто десяткові числа повинні починатися з цифри, вісімкові – з літери О, а шістнадцяткові – з префікса Ох чи ОХ.

Функція аналогічна atoi(), atof(), atol(), printf(), sprintf(), strtoul().

Алгоритм розв’язання задачі наведено на рис. 6.1.


Рисунок 6.1Логічна схема програми визначення кількості слів у тексті


Розробка тексту програми

#include

#include

#include

#include

#include

#include

int main()

{

char dod[1],s1[80];



int i,n,k=0;

char choice,vihid;

float bac;

clrscr();bac=0;

{ clrscr();



printf(" MENU\n");

printf("1.- Vvedennya danih\n");

printf("2.- Rishennya zadachi\n");

printf("3.- vivedennya danih\n");

printf("4.- Zavershennya roboti\n");

scanf("%d",&choice);

switch(choice)

{

case 1:



{

clrscr();

printf("Vi vibrali punkt -vvedennya danih\n");

printf("vveditye recennya:\n");

gets(dod);

gets(s1);

bac ;

}

break;



case 2:

{ clrscr();

if (!(bac>0))

{

printf("viberity pershiy punkt i vvedit zminni\n");



getch();

break;


}

printf("znahodgennya kilkosti sliv\n");

if (s1[0] != ' '&&s1[0] != '\0') k=1;

n=strlen(s1);

for(i=0;i

if (s1[i]==' '&&s1[i 1]!=' ')

k ;

printf("Virishuyu zadachu ");



for(i=0;i<10;i )

{

printf(«O»);



delay(500);

}

printf("\n zadachu uspishno virisheno!!!\n");



getch();

k=k;


break;

}

case 3:



{

clrscr();

printf("vivod danih\n");

printf("string s=%s\n",s1); k=k;

printf("dovgina l=%d\n",strlen(s1)); k=k;

printf("kilkisty sliv k=%d\n",k);

break;

}

case 4:



printf(«vi vibrali vihid\n»);

break;


default:

printf("\n\n Illegal choice!!!/n");

}

if (choice==1)



printf("Chi bagayete rozvyazati zadachu?\n");

else


printf("chi bagayete dali prachuvati?\n");

printf("1-Tak 2-Ni\n");

scanf("%d",&vihid);

}

while(vihid==1);



if (vihid==2)

printf("Bagayemo uspihu!\n");

else

printf("\n\n Illegal choice!!!\n");



getch();

return choice;

}

На рис. 6.2 наведено алгоритм другого способу розв’язання задачі визначення кількості слів у тексті.


Рисунок 6.2 Логічна схема програми визначення кількості слів у тексті

Текст такої програми має вигляд, наведений нижче.

#include

#include

#include

#include

#include

#include

int main()

{

char dod[1],s1[80];



int i,n,k=0;

char choice,vihid;

float bac;

clrscr();bac=0;

{ clrscr();



printf(" MENU\n");

printf("1.- Vvedennya danih\n");

printf("2.- Rishennya zadachi\n");

printf("3.- vivedennya danih\n");

printf("4.- Zavershennya roboti\n");

scanf("%d",&choice);

switch(choice)

{

case 1:



{

clrscr();

printf("Vi vibrali punkt -vvedennya danih\n");

printf("vveditye recennya:\n");

gets(dod);

gets(s1);

bac ;

}

break;



case 2:

{ clrscr();

if (!(bac>0))

{

printf("viberity pershiy punkt i vvedit zminni\n");



getch();

break;


}

printf("znahodgennya kilkosti sliv\n");

if (s1[0] != ' '&&s1[0] != '\0') k=1;

n=strlen(s1);

for(i=0;i

if (s1[i]==' '&&s1[i 1]!=' ')

k ;

printf("Virishuyu zadachu -->");



for(i=0;i<10;i )

{ printf("O");

delay(500);

}

printf("\n zadachu uspishno virisheno!!!\n");



getch();

k=k;


break;

}

case 3:



{

clrscr();

printf("vivod danih\n");

printf("string s=%s\n",s1); k=k;

printf("dovgina l=%d\n",strlen(s1)); k=k;

printf("kilkisty sliv k=%d\n",k);

break;

}

case 4:



printf("vi vibrali vihid\n");

break;


default:

printf("\n\n Illegal choice!!!/n");

}

if (choice==1)



printf("Chi bagayete rozvyazati zadachu?\n");

else


printf("chi bagayete dali prachuvati?\n");

printf("1-Tak 2-Ni\n");

scanf("%d",&vihid);

}

while(vihid==1);



if (vihid==2)

printf("Bagayemo uspihu!\n");

else

printf("\n\n Illegal choice!!!\n");



getch();

return choice;

}
6.5 Функції для обробки текстової інформації
Приклади розробки функцій для обробки текстової інформації
Приклад 6.13.

Функція обчислення довжини рядка. Наведена нижче функція має старомодну форму, що не рекомендується стандартом заголовка (у стандартній бібліотеці їй відповідає функція strlen( )):

int len(e)

char e[ ] ;

{

int m;


for (m=0; e[m]!='\0'; m ) ;

return m;

}

Відповідно до ANSI-стандарту та стандарту ISO заголовок повинен мати, наприклад, такий вигляд:



int len (char e[ ])

У цьому прикладі й у заголовку, і в тілі функції немає навіть згадувань про споріднення масивів і вказівників. Однак компілятор завжди сприймає масив як вказівник на його початок, а індекс – як зсув відносно початку масиву. Наступний варіант тієї ж функції (тепер заголовок відповідає стандартам мови) явно реалізує механізм роботи з вказівниками:

int len (char *s)

{

int m;

Механі́зм (грец. μηχανή mechané - машина) - система тіл, що призначена для перетворення руху одного або декількох тіл у потрібний рух інших тіл. Механізм складає основу більшості машин і застосовується в різноманітних технічних об'єктах.



for (m=0; *s ! = '\0' ; m )

return m;

}

Для формального параметра-вказівника s всередині функції виділяється ділянка пам'яті, куди записується значення фактичного параметра. Оскільки s не константа, то значення цього вказівника може змінюватися. Саме тому припустимо вираз s


Приклад 6.14.

Функція інвертування рядка-аргументу з параметром-масивом (заголовок відповідає стандарту):

void invert(char e[ ])

{

char s;



int і, j , m;

/*m – номер позиції символу '\0' у рядку е */

for (m=0; e[m]!='\0'; m ) ;

for (i=0, j=m-l; i

{

s=e[i];


e[i]=e[j];

e[j]=s;


}

}

У визначенні функції invert() за допомогою ключового слова void зазначено, що функція не повертає значення.



Як вправу можна переписати функцію invert(), замінивши параметр-масив параметром-вказівником типу char*.

При виконанні функції invert() рядок – фактичний параметр функції, наприклад, «сироп» перетвориться в рядок «порис». При цьому символ '\0' залишається на своєму місці в кінці рядка. Приклад використання функції invert():

#include

void main( )

{

char ct[ ]="0123456789";



/* Прототип функції: */

void invert(char [ ]);



/* Виклик функції: */

invert(ct)/

printf ("\n%s",ct) ;

}

Результат виконання програми:



9876543210
Приклад 6.15.

Функція пошуку в рядку найближчого зліва входження іншого рядка (у стандартній бібліотеці є подібна функція strstr())

/*Пошук рядка СТ2 у рядку СТ1 */

int index (char * СТ1, char * CT2)

{

int і, j , ml, m2;



/* Обчислюються m1 і m2 – довжини рядків */

for (m1=0; CT1[m1] !='\0'; m1 );

for (m2=0; CT2[m2] !='\0'; m2 );

if (m2>m1)

return -1;

for (i=0; i<=m1-m2; i )

{

for (j=0; j

if (СT2[j] !=СT1[i j])

break;


if (j==m2)

return i;

} /* Кінець циклу за і */

return -1;

}

Функція index() повертає номер позиції, починаючи з якої СТ2 цілком збігається з частиною рядка СТ1. Якщо рядок СТ2 не входить у СТ1, то повертається значення -1.


Приклад звертання до функції index( ):

#include

void main( )

{

char C1[ ]="сума мас";



/* Прототип функції: */

int index(char [], char []);

char C2[]="ма"/

char C3[]="ам";

printf("\nДля %s індекс=%d",C2,index(C1,C2) );

printf("\nДля %s індекс=%d",C3,index(C1,C3));


}
Результат виконання програми:

Для ма індекс=3 Для ам індекс=-1

У функції index() параметри специфіковані як вказівники на тип char, а в тілі функції звертання до символів рядків виконується за допомогою індексованих змінних. Замість параметрів-вказівників підставляють як фактичні параметри імена символьних масивів С1[ ], С2[], С3[]. Ніякої неточності тут немає: для масивів припустимі обидві форми звертання – і за допомогою індексованих змінних, і з використанням розіменованих вказівників.
Приклад 6.16.

Функція порівняння рядків. Для порівняння двох рядків можна написати нижченаведену функцію (у стандартній бібліотеці є близька до цієї функція strcmp()):

int row(char C1[], char C2[])

{

int і,m1,m2; /* m1,m2 - довжини рядків С1,С2 */



for (m1=0;*(C1 m1)= '\0'; m1 ) ;

for (m2=0;*(C2 m2)= '\0'; m2 );

if (m1!=m2) return -1;

for (i=0; i

if (*C1 != *C2 ) return (i 1);

return 0;

}
У тілі функції звертання до елементів масивів-рядків реалізовано через розіменування вказівників. Функція row() повертає: значення -1, якщо довжини рядків-аргументів С1, С2 різні; 0 – якщо всі символи рядків збігаються. Якщо довжини рядків однакові, але символи не збігаються, то повертається порядковий номер (ліворуч) перших незбіжних символів.

Особливість функції row() – специфікація параметрів як масивів і звертання до елементів масивів всередині тіла функції за допомогою розіменування. При цьому за рахунок операцій С1 і С2 змінюються початкові «настроювання» вказівників на масиви. Одночасно в тій же функції до тих же масивів-параметрів виконується звертання і за допомогою виразів *(Cl m1) і *(С2 m2), при обчисленні яких значення С1 і С2 не змінюються.


Приклад 6.17.

Функція з'єднання рядків. Подана нижче функція дозволяє «приєднати» до першого рядка-аргументу другий рядок-аргумент (у стандартній бібліотеці є подібна функція : strncat()):



/* З'єднання (конкатенація) двох рядків: */

void cone(char *C1, char *C2)

{

int i,m; /* m - довжина 1-го рядка */



for (m=0; *(C1 m)!='\0'; m );

for (i=0; *(C2 i)!='\0'; i )

*(C1 m i)=*(C2 i);

*(C1 m і)='\0';

}

Результат повертається як значення першого аргументу C1. Другий аргумент C2 не змінюється. Зверніть увагу на те, що при використанні функції соnс() довжина рядка, що заміняє параметр C1, повинна бути достатньої для прийому підсумкового рядка.


Приклад 6.18.

Функція виділення підрядка. Для виділення з рядка С1 фрагмента заданої довжини (підрядка) можна запропонувати таку функцію:

void substr(char *C1, char *C2, int n, int k)

/* Cl – вихідний рядок */

/* C2 – підрядок, що виділяється */

/* n – початок підрядка, що виділяється */

/* k – довжина підрядка, що виділяється*/

{

int і,m; /* m - довжина вихідного рядка */



for (m=0; C1 [m] ! =' \0 ' ; m ) ;

if (n<0 || n>m || k<0 || k>m-n)

{

C2[0]='\0';



return;

}

for (i=n; i

C2[i-n]=C1[i-1];

C2[i-n]='\0';

return;

}

Результат виконання функції – рядок C2[ ] з k символів, виділених з рядка C1[ ], починаючи з символу, що має номер n. При неправильному поєднанні значень параметрів повертається порожній рядок, використаний як параметр С2.


Приклад 6.19.

Функція копіювання вмісту рядка. Оскільки в мові С відсутній оператор присвоювання для рядків, то корисно мати спеціальну функцію, що дозволяє «переносити» вміст рядка в інший рядок (така функція strcpy() є в стандартній бібліотеці, але вона має інше значення, що повертається):

/* Копіювання вмісту рядка С2 в С1 */

void copy(char *С1, char *C2) /* С2 – оригінал, С1 – копія */

{

int і;


for (i=0; C2[i]!='\0'; i )

C1[i]=C2[i];

C1[i]='\0';

}

Розробка алгоритму розв’язання


Рисунок 6.3 Логічна схема програми, яка міняє і-й рядок з і 1

Текст такої програми має вигляд, наведений нижче.

#include

#include

#include

#include

#include

void ChangeStr(char **,int);

int main()

{

char s[1],**str;



int n,i;

clrscr();

while (1)

{

printf("\n vveditye kilkisty strichok n=");



scanf("%d",&n);

if (n>=1&&n<=10)

break;

printf("\n ERRORS!!! 1<=n<=10 \n");



}

str=(char**)malloc(n*sizeof(char*));

for(i=0;i

str[i]=(char*)malloc(80*sizeof(char));

printf("vvedity %d strok \n",n);

gets(s);


for(i=0;i{printf("string[%d]=",i 1);

gets(str[i]);

}

printf("\n-----------pislya zminu strichok mayemo takuy masiv----------\n");



ChangeStr(str,n);

for(i=0;i

{

printf("string[%d]=",i 1);



puts(str[i]);

}

free(str);



getch();

return 0;

}

void ChangeStr(char **s1,int m)



{

char ss[80];

int j;

for (j=0;j

{

strcpy(ss,s1[j]);

// puts(ss);

strcpy(s1[j],s1[j 1]);

strcpy(s1[j 1],ss); } }
6.6 Контрольні запитання


  1. Які бібліотеки необхідно підключати для роботи з рядками?

  2. Які є способи ініціалізації рядків?

  3. За допомогою яких функцій відбувається введення символів?

  4. Як відбувається введення рядків, які функції бібліотеки string.h при цьому використовуються?

  5. За допомогою яких стандартних функцій відбувається введення рядків?

  6. За допомогою яких стандартних функцій відбувається виведення рядків?

  7. Які стандартні функції використовуються для визначення довжини рядків?

  8. Як відбувається пошук в рядку входження підрядків?

  9. Напишіть, які ви знаєте стандартні функції для роботи з рядками?

  10. Яка стандартна функція з бібліотеки string.h призначена для копіювання рядків? Навести приклад.

  11. За допомогою якої стандартної функції відбувається інвертування рядка?

  12. Як використати рядок як параметри функцій? Навести приклад.

  13. Яка різниця між функцією strcmpi() і функцією strcmp()?

6.7 Практикум з програмування



  1. Написати фрагмент програми для визначення кількості цифр в рядку, введеному з клавіатури.

  2. Написати фрагмент програми для інвертування заданого рядка.

  3. Написати фрагмент програми для визначення кількості слів у тексті, що вводиться з клавіатури.

  4. Написати фрагмент програми для поділу рядка на підрядки, довжиною 5 символів кожен, не враховуючи пропуск.

  5. Написати фрагмент програми для копіювання з заданого тексту даної частини в рядок.

  6. Написати фрагмент програми для злиття заданих рядків з тексту, що вводиться з клавіатури.

  7. Написати фрагмент програми для визначення рядка максимальної довжини в тексті, що вводиться з клавіатури.

  8. Написати фрагмент програми для пошуку в рядку STR кількості входжень підрядка STR1.

  9. Написати фрагмент програми для знаходження кількості однакових символів у слові, що вводиться з клавіатури.

  10. Написати фрагмент програми, яка визначає максимальну і мінімальну довжини рядків в масиві і міняє їх місцями.

7 РОБОТА З БАЗАМИ ДАНИХ

7.1 Загальні відомості


Відомі два підходи до організації інформаційних масивів: файлова організація та організація у вигляді бази даних. Файлова організація передбачає спеціалізацію та збереження інформації, орієнтованої, як правило, на одну прикладну задачу, та забезпечується прикладним програмістом. Така організація дозволяє досягнути високої швидкості обробки інформації, але характеризується рядом недоліків.
Спеціаліза́ція (від лат. specialis - особливий) - конкретизація, деталізація фаху, набуття особою здатностей виконувати окремі завдання та обов'язки, які мають особливості, в межах спеціальності тощо. Логічна дія - класифікація.
Обробка інформації́ - вся сукупність операцій (збирання, введення, записування, перетворення, зчитування, зберігання, знищення, реєстрація), що здійснюються за допомогою технічних і програмних засобів, включаючи обмін по каналах передачі даних [6.

Характерна риса файлового підходу – вузька спеціалізація як обробних програм, так і файлів даних, що служить причиною великої надлишковості, тому що одні й ті самі елементи даних зберігаються в різних системах. Оскільки керування здійснюється різними особами (групами осіб), відсутня можливість виявлення порушення суперечливості збережуваної інформації. Розроблені файли для спеціалізованих прикладних програм не можна використовувати для задоволення запитів користувачів, які перекривають дві і більше ділянки.

Задово́лення - позитивно забарвлена емоція, що супроводжує вдоволення однієї або кількох потреб. Антонімом задоволення є страждання й біль. Поняття задоволення в філософії Епікура ототожнене зі щастям.
Крім того, файлова організація даних внаслідок відмінностей структури записів і форматів передання даних не забезпечує виконання багатьох інформаційних запитів навіть у тих випадках, коли всі необхідні елементи даних містяться в наявних файлах. Тому виникає необхідність відокремити дані від їхнього опису, визначити таку організацію збереження даних з урахуванням існуючих зв'язків між ними, яка б дозволила використовувати ці дані одночасно для багатьох застосувань. Вказані причини зумовили появу баз даних.

База даних може бути визначена як структурна сукупність даних, що підтримуються в активному стані та відображають властивості об'єктів зовнішнього (реального) світу. В базі даних містяться не тільки дані, але й описи даних, і тому інформація про форму зберігання вже не прихована в сполученні «файл-програма», вона явним чином декларується в базі.

Сполу́чення - особливе розташування об'єкта Сонячної системи (здебільшого, планети) відносно Сонця так, що їх екліптичні довготи для земного спостерігача рівні. У сполученні об'єкт візуально розташований на небі поряд із Сонцем.

База даних орієнтована на інтегровані запити, а не на одну програму, як у випадку файлового підходу, і використовується для інформаційних потреб багатьох користувачів. В зв'язку з цим бази даних дозволяють значною мірою скоротити надлишковість інформації. Перехід від структури БД до потрібної структури в програмі користувача відбувається автоматично за допомогою систем управління базами даних (СУБД).

Основними та невід'ємними властивостями БД є такі:

- для даних допускається така мінімальна надлишковість, яка сприяє їх оптимальному використанню в одному чи кількох застосуваннях;

- незалежність даних від програм;

- для пошуку та зміни даних використовуються спільні механізми;

- як правило, у складі БД існують засоби для підтримки її цілісності та захисту від неавторизованого доступу.

Основні принципи створення БД: цілісність, вірогідність, контроль, захист від несанкціонованого доступу, єдність і гнучкість, стандартизація та уніфікація, адаптивність, мінімізація введення і виведення інформації (однократність введення інформації, принцип введення – виведення тільки змін).


7.2 Особливості розробки програм для роботи з базами даних
Програми для роботи з базами даних (DB – data base
) є частиною програмних комплексів автоматизованих систем керування технологічними процесами, підприємствами, деякими складними об'єктами.
Підприє́мство - самостійний суб'єкт господарювання, зареєстрований компетентним органом державної влади або органом місцевого самоврядування, для задоволення суспільних та особистих потреб шляхом систематичного здійснення виробничої, науково-дослідної, торговельної, іншої господарської діяльності в порядку, передбаченому Господарським кодексом України та іншими законами.
Вірогі́дність - властивість знання, істинність якого твердо встановлена суб'єктом.
Комплексний (рос. комплексный, англ. complex, нім. komplex) - з'єднаний з будь-чим, складний; той, що являє собою комплекс будь-чого; комплексний розвиток економічних районів - планомірний, пропорційний розвиток господарства районів на основі оптимального поєднання галузей виробничої спеціалізації з галузями, що обслуговують виробництво й населення; комплексні сполуки - речовини, які утворенні сполученням двох або більше атомів, молекул або іонів.
Стандартиза́ція - діяльність, що полягає в установленні положень для загального та неодноразового використання щодо наявних чи потенційних завдань і спрямована на досягнення оптимального ступеня впорядкованості в певній сфері.
Технологі́чний проце́с - це впорядкована послідовність взаємопов'язаних дій та операцій, що виконуються над початковими даними до отримання необхідного результату.
Автоматизо́вана систе́ма керува́ння (АСК), Автоматизована система управління (АСУ), Комп'ютерна система управління (КСУ) - автоматизована система, що ґрунтується на комплексному використанні технічних, математичних, інформаційних та організаційних засобів для управління складними технічними й економічними об'єктами.
Однією з головних особливостей таких програм є організація збереження, відновлення, обробки великих обсягів інформації, тому при розробці таких програм необхідно розв’язати певне коло задач.
Особливість, або сингулярність в математиці - це точка, в якій математичний об'єкт (зазвичай функція) не визначений або має нерегулярну поведінку (наприклад, точка, в якій функція недиференційована).
До них належать:

  1. Визначити кінцеву мету, тобто які задачі необхідно розв’язувати за допомогою цих програм, а так само – яку інформацію й у якому вигляді можна одержати з їх допомогою;

  2. Визначити набір функцій, які повинна виконувати програма. Наприклад, за допомогою програми необхідно:

    • створити файли бази даних (тобто інформаційне сховище),

    • «накачати» даними файли бази даних,

    • дозаписувати дані в файли бази даних,

    • видаляти деякі дані з файлу бази даних,

    • редагувати дані в файлі бази даних (корегування даних),

    • сортувати дані в файлах бази даних за заданими критеріями;

  3. Визначити набір вихідної інформації (вхідні дані), необхідний для роз’язання поставлених задач;

  4. Визначити кількість файлів у базі даних, об’єднавши інформацію в групи за обраними критеріями і спроектувати базу даних;

  5. Розробити структуру програми керування, помістивши до неї основний клас задач, що їх необхідно розв'язати;

  6. Розробити ієрархічну структуру підзадач, деталізувавши її до рівня програмних функцій.
    Крите́рій (від лат. critērium, яке зводиться до грец. χριτήριον - здатність розрізнення; засіб судження, мірило, пов'язаного з грец. χρινω - розділяю, розрізняю) - мірило, вимоги, випробування для визначення або оцінки людини, предмета, явища; ознака, взята за основу класифікації.
    Ієра́рхія (грец. ίεράρχίά, від ίερσς - священний, та άρχή - влада) - поділ на вищі й нижчі посади, чини; суворий порядок підлеглості нижчих щодо посади або чину осіб вищим. В ієрархії між її членами діють вертикальні зв'язки - відносини субординації.


Наприклад, найпростіша програма для роботи з базою даних може працювати з такими задачами:

  • Задача «Робота з базою даних»;

  • Задача «Формування звітних документів за заданими критеріями».
    Докуме́нт - базова теоретична конструкція, яка відноситься до всього, що може бути збережене або представлене, щоб служити як доказ для певної мети.


Задача «Робота з базою даних» може містити такі підзадачі:

    • створення бази даних;

    • дозапис у базу даних;

    • «накачування» даних в файли бази даних;

    • редагування записів в файлах бази даних;

    • видалення запису з файлу бази даних.

7.3 Приклад проектування бази даних
У мові С компоненти файлу бази даних зручно представляти у вигляді структур (struct). Тобто кожен запис є елементом структурного типу даних із членами, що є рядками полів фіксованого розміру, цілі, дійсні значення й ін. Усе, що можна записати в структурі, можна записати в двійковий файл із довільним доступом і прочитати з нього.
Проектування баз даних

Першим кроком у написанні програми створення, обробки, ведення бази даних є розробка структури запису файлу. Наприклад, для задачі «Телефонний абонент» структура запису основного файлу може мати вигляд:
Typedef struct

{ char name [NAMELEN];

char addr [ADDRLEN];

char csz [CSZLEN];

char phone [PHONELEN];

double balance;

} Record;
Другим кроком є планування набору функцій з ведення бази даних і розробка їх прототипів. З прототипів функцій зручно створити заголовний файл, наприклад, db.h (database), а потім у файлі db.с скомпонувати всі ці функції, що будуть викликатися функцією main()
/* Заголовний файл для роботи з базою даних db.h */

#include

#include
#define FALSE 0

#define TRUE 1

#define NAMELEN 30

#define ADDRLEN 30

#define CSZLEN 30

#define PHONELEN 13


typedef struct record{

union{


long numrecs; /* Заголовок==число записів */

long custnum; /*Запис==номер клієнта */

}info;


char name[NAMELEN]; /* ПІБ клієнта */

char addr[ADDRLEN]; /*Адреса клієнта */

char csz[CSZLEN]; /* Місто, штат клієнта */

char phone[PHONELEN]; /*Телефон клієнта */

double balance; /* Поточний залишок */

}Record;


#define MAXREC (LONG_MAX / sizeof(Record))

// Створення нової бази даних з ім'ям path. Повертає FILE чи NULL і


// header

int CreateDB(const char *path);

// Відкриває базу даних з ім'ям path. Повертає FILE чи NULL і header

FILE *OpenDB(const char *path, Record *header);

// Читає запис з номером recnum у rec. Повертає TRUE/FALSE

int ReadRecord(FILE *f, long recnum, Record *recp);

// Записує запис з номером recnum з rec. Повертає TRUE/FALSE

int WriteRecord(FILE *f, long recnum, Record *recp);

// Додає запис у кінець файлу. Повертає TRUE/FALSE

int AppendRecord(FILE *f, long recnum, Record *recp);

// Відображає мітку і вводить символьний рядок

void InputLong(const char *label, long *lp);

// Відображає мітку і вводить значення типу double

void InputDouble(const char *label, double *dp);

void Іnрutсhаr(const char *label, char *cp, int len);
У структурі Record використовується об'єднання union, що допомагає організувати базу даних. Поля об'єднання запам'ятовуються одне поверх іншого, тобто не зважаючи на те, що оголошено в union два елементи типу long, в один і той же час може використовуватися тільки одне з них. Призначення об'єднання полягає в реєстрації номерів записів у файлі бази даних.

Реєстра́ція - запис, фіксація фактів або явищ з метою обліку та надання їм статусу офіційно визнаних актів (реєстрація народження або шлюбу); внесення в список, в книгу обліку.
Запис з нульовим номером запам'ятовує цю інформацію, використовуючи в структурі поле numrecs (і ніяке інше).

Записи з номерами 1 і вище містять значущу інформацію – у даному випадку, номер клієнта, його ім'я, адреса й інші дані.

Розглянемо організацію цього файлу.

Рисунок 7.1 – Приклад структури запису файла бази даних і запис інформаційного заголовка


//Файл db.c, що містить опис функцій, описаних у db.h

#include

#include

#include

#include "db.h"
// ***********************

//

int CreateDB(const char *path)



{

FILE *f;


Record rec;

int result;



f=fopen(path,"wb"); //створення нового файлу БД

if (!f)


return FALSE;

memset(&rec,0,sizeof(Record));



rec.info.numrecs=0; //початкове значення запису numrec=0, тому що поки що БД ще не містить ніяких записів

result=WriteRecord(f,0,&rec);

fclose(f);

return result;

}

FILE *OpenDB(const char *path, Record *header)



{

FILE *f=fopen(path,"r b"); //відкриття файлу f

if (f)


ReadRecord(f,0, header); //читання інформаційного запису файлу, визначаючи кількість записів, що містяться у файлі

return f;

}

//Читання запису з номером recnum з файлу f у рядок Record, що адресується вказівником *recp.



int ReadRecord(FILE *f, long recnum, Record *recp) //

{

if(recnum>MAXREC)



return FALSE;

if(fseek(f,recnum * sizeof(Record),SEEK_SET)!=0) //переміщення вказівника в позицію

return FALSE;

return(fread(recp,sizeof(Record),1,f)==1);

}

//передає на диск структуру запису, що адресується вказівником recp.



{

int WriteRecord(FILE *f, long recnum, Record *recp)

if (recnum > MAXREC)

return FALSE;



if(fseek(f,recnum* sizeof(Record),SEEK_SET)!=0) //позиціювання вказівника

return FALSE;

return(fwrite(recp,sizeof(Record),1,f)==1);

}

int AppendRecord(FILE *f, long *recnum, Record *recp)



{

if (fseek(f,0, SEEK_END)!=0) // встановлення файлового вказівника в кінець файлу

return FALSE;



*recnum = ftell(f) / sizeof(Record); // ftell(f) повертає значення вказівника у середині файлу

//визначення номера запису, що додається

return WriteRecord(f, *recnum, recp); //дозапис у кінець файлу

}
void InputLong(const char *label, long *lp)

{

char buffer[128];



printf(label);

gets(buffer);

*lp=atol(buffer);

}
void InputChar(const char *label, char *cp, int len)

{

char buffer[128];



printf(label);

gets(buffer);

strncpy(cp,buffer,len-1);

}
void InputDouble(const char*label, double *dp)

{

char buffer[128];



printf(label);

gets(buffer);

*dp=atof(buffer);

}




Створення файлів обробки бази даних
Після розробки структури файлу бази даних і функцій запису даних у файл, необхідно розробити програму створення бази даних (тобто створити порожній файл бази даних).

Розглянемо приклад програми для розв’язання цієї задачі. Оформимо її в окремий файл MAKEDB.C. Така програма обов'язково повинна містити заголовний файл db.h, що повідомляє про структуру файлу бази даних і містить прототипи функцій, описаних у модулі db.с. Щоб створити закінчену програму, необхідно:

1) скомпілювати MAKEDB.C. і db.с;

2) скомпонувати об'єктні файли програм MAKEDB.C і db.с у закінчений виконуваний файл MAKEDB.ЕХЕ


// Програма MAKEDB.C

#include

#include

#include "db.h"

// Створення порожнього файлу бази даних

int FileExists(const char *path);

int main()

{

char path[128];



puts("Create new database file");

printf("Filename= ");

gets(path);

if (strlen(path)==0)

exit(0);

if (FileExists(path))

{

printf("%s **** already exists. \n", path);



puts("Delete file and try again");

exit(1);


}

if (!CreateDB(path)) //якщо файл існує, то програма не перезаписує його

perror(path);

else

printf("%s *** created. \n",path);



return 0;

}
int FileExists(const char path) //допоміжна функція, що повертає «істину», якщо заданий файл, обумовлений вказівником path типу сhаr*, існує

{

FILE *f = fopen(path, "r");



if (!f)

return FALSE;

else

{

fclose(f);



return TRUE;

}

}


// Програма додавання записів у БД

// файл ADDREC.c

#include

#include

#include

#include "db.h"


void GetNewRecord(Record *recp);

int main()

{

char path[128];



FILE *dbf;

Record rec;

long numrecs;

//

printf(" ********* Database name = ");



gets(path);

dbf= OpenDB(path,&rec);

if (!dbf)

{

printf(" ********* Can't open %s file \n", path);



exit(1);

}

numrecs= rec.info.numrecs;



printf("********** Number of records ==%lu\n",numrecs);

GetNewRecord(&rec);

if (AppendRecord(dbf, &numrecs, &rec))

printf(" *********** Record #%lu added no database \n", numrecs);

memset(&rec,0,sizeof(Record));

rec.info.numrecs = numrecs;

WriteRecord(dbf,0,&rec);

fclose(dbf);

return 0;

}
void GetNewRecord(Record *recp);

{

memset(recp,0,sizeof(Record));



InputLong("Customer # : ", &recp->info.custnum);

InputChar("Name :", recp->name, NAMELEN);

InputChar("Address :", recp->addr, ADDRLEN);

InputChar("Sity, State, Zip :", recp->csz, CSZLEN);

InputChar("Telephone :", recp->phone, PHONELEN);

InputDouble("ACCOUNT balance :", recp->balance);

}
Дана програма додає тільки 1 запис у файл. Якщо необхідно дозаписати певну кількість записів, то створюється цикл за кількістю записів, наприклад, після введення кожного запису запитувати користувача, чи не хоче він додати ще один запис.

Більшість програм роботи з базами даних охоплює крім введення нових записів, процедури редагування (коректування, змінювання) вже існуючих у файлі певних записів, не змінюючи інші. Алгоритм такої програми наведений на рисунку 7.1.

Рисунок 7.1 – Алгоритм програми роботи з базою даних


У запропонованому нижче прикладі програми використовуються методи довільного доступу після введення номера запису для редагування і після цього відбувається відновлення інформації, змушуючи користувача повторно вводити всі поля обраного запису. Більшість програмістів таке редагування називають недружелюбним.
Більшість - велика частина чого-небудь, або кількісне переважання прихильників якоїсь ідеї чи рішення над їхніми противниками. Вважається найпершою засадою демократичного способу прийняття спільних рішень, головною й необхідною умовою обрання кандидата на виборну посаду.

// Приклад програми редагування записів у файлі БД

// файл EDIREC.c

#include

#include

#include "db.h"

void EditRecord(FILE *f,long recnum, Record *recp);

int main()

{

char path[128];



FILE *dbf;

Record rec;

long numrecs, recnum;

printf("************ Database file name =");

gets(path);

dbf = OpenDB(path,&rec);

if (!dbf)

{

printf(" ******** Can't open %s file \n", path);



exit(1);

}

numrecs = rec.info.numrecs;



printf(" ****** Number of records == %lu \n",numrecs);

InputLong("*** Record number ?",&recnum);

if ((recnum<=0) || (recnum>numrecs))

{

puts("**** Record number out of range");



fclose(dbf);

exit(1);


}

EditRecord(dbf, recnum, &rec);

if (WriteRecord(dbf, recnum, &rec))

printf("**** Record namber #%lu writted to &s\n", recnum, path);

else

perror("Write record");



fclose(dbf);

return 0;

}
void EditRecord(FILE *f, long recnum, Record *recp)

{

if (!ReadRecord(f,recnum, recp))



{

perror("Reading record");

exit(1);

}

printf("***** Cstomer # : %lu\n",recp->info.custnum);



InputLong("Customer # : ",&recp->info.custnum);

printf("**** Name : %s\n",recp->name);

InputChar("Name : ", recp->name, NAMELEN);

printf("**** Address : %s\n", recp->addr);

InputChar("Adderss : ", recp->addr, ADDRLEN);

printf("**** City, State, Zip :", recp->csz);

InputChar(" City, State, Zip :", recp->csz, CSZLEN);

printf("**** Telephone : %s\n", recp->phone);

InputChar("Telephone :", recp->phone, PHONELEN);

printf(" ** Account balance : %8.2f\n", recp->balance);

InputDouble(" Account balance : " , &recp->balance);

Для роботи з базами даних можна використовувати програмне забезпечення, що характеризується певними структурами та функціями.

В першу чергу необхідно визначити типи файлів для збереження в них інформації та структури цих файлів, оскільки це спрощує та полегшує роботу з ними.

На прикладі розглянемо особливості створення структур файлів, що складають базу даних для програми автоматизації роботи диспетчера торгової фірми з отримання та виконання замовлень від клієнтів.

Автома́тика (грец. αύτόματος - самодіючий) - галузь науки і техніки, яка розробляє технічні засоби і методи для здійснення технологічних процесів без безпосередньої участі людини.
В даному випадку необхідно розробити бази даних, які будуть містити такі таблиці:



  • «Товари»;

  • «Клієнти»;

  • «Виконані замовлення».

Таблиця 7.1 – Опис файлів бази даних



База

Тип файлу

Назва

Товари

Бінарний

Prodbase.dat

Клієнти

Бінарний

Klntbase.dat

Виконані замовлення

Бінарний

Cmplbase.dat
1   2   3   4   5   6   7   8   9   10   11



  • Приклад 6.5.
  • Приклад 6.10.