Риклад зґ списком роззсилки
™об показати, Як можна легко записувати великґ об'№ми даних, користуючись функцґЯми fread () ґ fwrite (), ми розглЯнемо програму роботи зґ списком розсилки. Џрограма зможе зберґгати адреси у файлґ. Ђдреси будуть зберґгатисЯ в масивґ структур наступного типу:
struct addr {
char name [30];
char street [40];
char city [20];
char state [3];
unsigned long int zip;
} Addr_list [MAX];
‡наченнЯ MAX визнача№ максимальну кґлькґсть адрес, що може бути у списку.
Џри виконаннґ програми поле name кожно» структури ґнґцґалґзу№тьсЯ порожнґм вказґвником (NULL). “ програмґ вґльною вважа№тьсЯ та структура, поле name Яко» мґстить рЯдок нульово» довжини, тобто ґм'Я адресата ЯвлЯ№ собою порожнґм рЯдком.
„алґ наведенґ функцґ» save () ґ load (), Якґ використовуютьсЯ вґдповґдно длЯ збереженнЯ ґ завантаженнЯ бази даних (списку розсилки). ‡вернґть увагу, наскґльки коротко вдалосЯ закодувати кожну з функцґй, а адже цЯ стислґсть досЯгнута завдЯки потужностґ fread () ґ fwrite ()! § ше звернґть увагу на те, Як цґ функцґ» перевґрЯють значеннЯ, що повертаютьсЯ функцґЯми fread () ґ fwrite (), щоб виЯвити таким чином можливґ помилки.
/* ‡береженнЯ списку. */
void save (void) {
FILE *fp;
register int i;
if ((fp = fopen ("maillist", "wb")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \n");
return;
}
for (i = 0; i <MAX; i++)
if (*addr_list[i].name)
if (fwrite (&addr_list[i], sizeof (struct addr), 1, fp) != 1)
printf ("Џомилка при записi файлу. \n");
fclose (fp);
}
/* ‡авантажити файл. */
void load (void) {
FILE *fp;
register int i;
if ((fp = fopen ("maillist", "rb")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \ n");
return;
}
init_list ();
for (i = 0; i <MAX; i++)
if (fread (&addr_list[i], sizeof (struct addr), 1, fp) != 1) {
if (feof (fp)) break;
printf ("Џомилка при читаннi файлу. \n");
}
fclose (fp);
}
Ћбидвґ функцґ», save () ґ load (), пґдтверджують (або не пґдтверджують) успґшнґсть виконаннЯ функцґЯми fread () ґ fwrite () операцґй з файлом, перевґрЯючи значеннЯ, що повертаютьсЯ функцґЯми fread () ґ fwrite (). Љрґм того, функцґЯ load () Явно перевґрЯ№, чи не досЯгнуто кґнець файлу. ђобить вона це за допомогою виклику функцґ» feof (). –е доводитьсЯ робити тому, що fread () ґ в разґ помилки, ґ при досЯгненнґ кґнцЯ файлу поверта№ одне ґ те ж значеннЯ.
„алґ показана всЯ програма, що оброблЯ№ списки розсилки. є» можна використовувати Як Ядро длЯ подальших розширень, в не», наприклад, можна додати засоби пошуку адрес.
/* Џроста програма обробки списку розсилки,
в Якґй використову№тьсЯ масив структур. */
# include <windows.h>
# include <locale.h>
# include <stdio.h>
# include <stdlib.h>
# define MAX 100
struct addr {
char name [30];
char street [40];
char city [20];
char state [20];
unsigned long int zip;
} addr_list [MAX];
void init_list (), enter ();
void delete1 (), list ();
void load (), save ();
int menu_select (), find_free ();
int main() {
setlocale(LC_CTYPE, "Russian");
char choice;
init_list (); /* ґнґцґалґзацґЯ масиву структур */
for (; ;) {
choice = menu_select ();
switch (choice)
{
case 1: enter (); break;
case 2: delete1 (); break;
case 3: list (); break;
case 4: save (); break;
case 5: load (); break;
case 6: exit (0);
}
}
system ("pause");
return 0;
}
/* §нґцґалґзацґЯ списку. */
void init_list () {
register int t;
for (t = 0; t <MAX; ++t) addr_list [t].name[0] = '\0';
}
/* ЋтриманнЯ значеннЯ, вибраного в меню. */
int menu_select () {
char s [80];
int c;
printf ("1. ‚вести iм'Я \n");
printf ("2. ‚идалити iм'Я \n");
printf ("3. ‚ивести список \n");
printf ("4. ‡берегти файл \n");
printf ("5. ‡авантажити файл \n");
printf ("6. ‚ихiд \n");
do {
printf ("\n ‚ведiть номер потрiбного пункту: ");
gets (s);
c = atoi (s);
} while (c <0 || c> 6);
return c;
}
/* „одаваннЯ адреси в список. */
void enter () {
int slot;
char s [80];
slot = find_free ();
if (slot == -1) {
printf ("\n ‘писок заповнений");
return;
}
printf ("‚ведiть iм'Я: ");
gets (addr_list [slot].name);
printf ("‚ведiть вулицю: ");
gets (addr_list [slot].street);
printf ("‚ведiть мiсто: ");
gets (addr_list [slot].city);
printf ("‚ведiть Ћбласть: ");
gets (addr_list [slot].state);
printf ("‚ведiть поштовий iндекс: ");
gets (s);
addr_list [slot].zip = strtoul (s, '\0', 10);
}
/* Џошук вґльно» структури. */
int find_free () {
register int t;
for (t = 0; addr_list[t].name [0] && t <MAX; ++t);
if (t == MAX) return -1; /* вґльних структур нема№ */
return t;
}
/* ‚идаленнЯ адреси. */
void delete1 () {
register int slot;
char s [80];
printf ("‚ведiть Ь запису: ");
gets (s);
slot = atoi (s);
if (slot >= 0 && slot <MAX)
addr_list [slot].name [0] = '\0';
}
/* ‚ивґд списку на екран. */
void list () {
register int t;
for (t = 0; t <MAX; ++t) {
if (addr_list[t].name [0])
{
printf ("%s \n", addr_list[t].name);
printf ("%s \n", addr_list[t].street);
printf ("%s \n", addr_list[t].city);
printf ("%s \n", addr_list[t].state);
printf ("%lu \n \n", addr_list[t].zip);
}
}
printf ("\n \n");
}
/* ‡береженнЯ списку. */
void save () {
FILE *fp;
register int i;
if ((fp = fopen ("maillist", "wb")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \n");
return;
}
for (i = 0; i <MAX; i++)
if (*addr_list[i].name)
if (fwrite (&addr_list[i], sizeof (struct addr), 1, fp) != 1)
printf ("Џомилка при записi файлу. \n");
fclose (fp);
}
/* ‡авантажити файл. */
void load () {
FILE *fp;
register int i;
if ((fp = fopen ("maillist", "rb")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \ n");
return;
}
init_list ();
for (i = 0; i <MAX; i++)
if (fread (&addr_list[i], sizeof (struct addr), 1, fp) != 1) {
if (feof (fp)) break;
printf ("Џомилка при читаннi файлу. \n");
}
fclose (fp);
}
”ункциЯ fseek()
”ормат функцґ»:
fseek(fp, n, m);
–Я функцґЯ встановлю№ вказґвник у файлґ fp в позицґю, що вґдсто»ть на n байт вґд поточно», а напрЯмок перемґщеннЯ (вперед або назад) визнача№тьсЯ параметром m, Який може бути заданий одним з трьох значень: 0, 1, 2 або однґ№ю з трьох символьних констант, визначених у файлґ stdio.h:
- SEEK_SET = 0 С до початку файлу;
- SEEK_CUR = 1 С вказґвник на поточну позицґю у файлґ;
- SEEK_END = 2 С до кґнцЯ файлу.
”ункцґЯ fseek () використову№тьсЯ длЯ введеннЯ/виведеннЯ потоком. „лЯ роботи не з потоковими даними слґд використовувати функцґю lseek (). ЏґслЯ функцґ» fseek () можна виконувати операцґ» оновленнЯ у файлах, вґдкритих длЯ поновленнЯ. Џри вдалому завершеннґ роботи fseek () поверта№ нуль, в ґншому випадку функцґЯ поверта№ код помилки. ’одґ глобальна змґнна errno прийма№ одне з наступних значень:
- EBADF - невґрний вказґвник файлу;
- EINVAL - невґрний аргумент функцґ»;
- ESPIPE - пошук на пристро» заборонений.
Џри прЯмому доступґ можна виконувати операцґ» веденнЯ/виведеннЯ, використовуючи систему введеннЯ/виведеннЯ мови ‘ ґ функцґю fseek (), Яка встановлю№ вказґвник поточно» позицґ» у файлґ. Ћсь прототип цґ№» функцґ»:
int fseek (FILE <вказґвник файлу>, long int <кґлькґсть_байт>, <початок_вґдлґку>);
кґлькґсть_байт - кґлькґсть байтґв, рахуючи вґд початок_вґдлґку, воно визнача№ нове значеннЯ вказґвника поточно» позицґ», а початок вґдлґку - це один з наступних макросґв:
Џочаток вґдлґку - Њакрос
Џочаток файлу - SEEK_SET
Џоточна позицґЯ - SEEK_CUR
Љґнець файлу - SEEK_END
’ому, щоб отримати у файлґ доступ на вґдстанґ кґлькґсть_байт байтґв вґд початку файлу, початок_вґдлґку повинен дорґвнювати SEEK_SET. ™об при доступґ вґдстань вґдраховуваласЯ вґд поточно» позицґ», використовуйте макрос SEEK_CUR, а щоб при доступґ вґдстань вґдраховуваласЯ вґд кґнцЯ файлу, потрґбно вказувати макрос SEEK_END. Џри успґшному завершеннґ сво№» роботи функцґЯ fseek () поверта№ нуль, а в разґ помилки - ненульове значеннЯ.
“ наступнґй програмґ показано, Як використову№тьсЯ fseek (). „ана програма в певному файлґ вґдшуку№ деЯкий байт, а потґм вґдобража№ його. “ командному рЯдку потрґбно вказати ґм'Я файлу, а потґм потрґбний байт, тобто його вґдстань в байтах вґд початку файлу.
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
int main () {
setlocale(LC_CTYPE, "Russian");
FILE * fp;
char ch;
if ((fp = fopen ("testr", "r")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \ n");
system ("pause");
exit (1);
}
fseek (fp, 6, SEEK_SET);
ch=fgetc (fp);
printf ("“ 6-му байтi мiститьсЯ ");
putchar (ch);
printf ("\n");
fclose (fp);
system ("pause");
return 0;
}
”ункцґю fseek () можна використовувати длЯ доступу всерединґ багатьох значень одного типу, просто множачи розмґр даних на номер елемента, Який вам потрґбен. Ќаприклад, припустимо, № список розсилки, Який склада№тьсЯ з структур типу addr (визначених ранґше). ™об отримати доступ до десЯто» адреси у файлґ, в Якому зберґгаютьсЯ адреси, використовуйте наступний оператор:
fseek (fp, 9 * sizeof (struct addr), SEEK_SET);
Џоточне значеннЯ вказґвника поточно» позицґ» у файлґ можна визначити за допомогою функцґ» ftell (). Ћсь »» прототип:
long int ftell (FILE <вказґвником файлу>);
”ункцґЯ поверта№ поточне значеннЯ вказґвника поточно» позицґ» у файлґ, пов'Язаному з вказґвником файлу вф. Џри невдалому результатґ вона поверта№ -1.
‡азвичай прЯмий доступ може знадобитисЯ лише длЯ двґйкових файлґв. Џричина тут проста - тому що в текстових файлах можуть виконуватисЯ перетвореннЯ символґв, то може ґ не бути прЯмо» вґдповґдностґ мґж тим, що знаходитьсЯ в файлґ ґ тим байтом, до Якого потрґбен доступ. ёдиний випадок, коли треба використовувати fseek () длЯ текстового файлу - це доступ до тґ№» позицґ», Яка була вже знайдена за допомогою ftell (); такий доступ викону№тьсЯ за допомогою макросу SEEK_SET, використовуваного в Якостґ початку вґдлґку.
„обре пам'Ятайте наступне: навґть Якщо в файлґ знаходитьсЯ один тґльки текст, все одно цей файл при необхґдностґ можна вґдкрити ґ в двґйковому режимґ. ЌґЯкґ обмеженнЯ, пов'Язанґ з тим, що файли мґстЯть текст, до операцґй прЯмого доступу не вґдносЯтьсЯ. –ґ обмеженнЯ стосуютьсЯ лише до файлґв, вґдкритих в текстовому режимґ.
”ункциЯ ftell()
”ормат функцґ»:
long int i = ftell(fp);
Џоверта№ поточне значеннЯ вказґвника файлу fp (тобто номер поточно» позицґ») у виглЯдґ значеннЯ типу long int. ‚ґдлґк йде в байтах вґд початку файлу.
Џовернене значеннЯ може бути використане потґм у функцґ» fseek ().
џкщо виЯвленґ помилки, то функцґЯ поверта№ значеннЯ -1L ґ привласню№ глобальнґй змґннґй errno додатне значеннЯ.
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
# include <string.h>
int main() {
setlocale(LC_CTYPE, "Russian");
char str [80];
int i=0;
long int l;
FILE *fp;
if ((fp = fopen ("test", "r")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \n");
system ("pause");
exit(1);
}
while (! feof (fp)) {
l = ftell(fp);
printf ("Ќомер поточно» позицi» %d перед зчитуваннЯм ", l);
fgets (str, 79, fp);
printf (str);
}
l = ftell(fp);
printf ("\n Ќомер поточно» позицi» %d пiслЯ зчитуваннЯ ", l);
printf ("\n");
fclose (fp);
system ("pause");
return 0;
}
”ункциЯ fscanf()
”ормат функцґ»:
fscanf(fp, Control, arg1, arg2, ... , argn);
”ункцґЯ чита№ данґ з файлу з вказґвником fp, перетворю№ »х за форматами, записаними у керуючому рЯдку Control, ґ вґдформатованґ данґ запису№ в аргументи arg1, ... , аrgn. „окладнґ вґдомостґ про роботу цґ№» функцґ» можна отримати, ознайомившись з роботою функцґ» scanf () (функцґю scanf ()).
”ункциЯ fprintf()
”ормат функцґ»:
fprinf(fp, Control, arg1, arg2, ... , argn);
‚иводить данґ в файл з вказґвником fp, перетворю№ аргументи arg1, ... , аrgn до форматґв, Якґ записанґ в керуючому рЯдку Control, ґ вґдформатованґ данґ запису№ в файл. „окладнґ вґдомостґ про роботу цґ№» функцґ» можна отримати, ознайомившись з роботою функцґ» printf ().
Љрґм основних функцґй введеннЯ/виведеннЯ, про Якґ йшла мова, в системґ введеннЯ/виведеннЯ мови ‘ також № функцґ» fprintf () ґ fscanf (). –ґ двґ функцґ», за винЯтком того, що призначенґ длЯ роботи з файлами, ведуть себе точно так само, Як ґ printf () та scanf (). Џрототипи функцґй fprintf () ґ fscanf () наступнґ:
int fprintf (FILE * вф, const char * керуючий_рЯдок, ...);
int fscanf (FILE * вф, const char * керуючий_рЯдок, ...);
де вф - вказґвник файлу, що поверта№тьсЯ в результатґ виклику fopen (). Ћперацґ» введеннЯ/виведеннЯ функцґ» fprintf () ґ fscanf () виконують з тим файлом, на Який вказу№ вф.
‚ Якостґ прикладу пропону№тьсЯ розглЯнути наступну програму, Яка чита№ з клавґатури рЯдок ґ цґле значеннЯ, а потґм запису№ »х у файл на диску; ґм'Я цього файлу Р test1. ЏґслЯ цього програма чита№ цей файл ґ виводить ґнформацґю на екран. ЏґслЯ запуску програми перевґрте, Яким вийде файл test1. џк ви ґ побачите, в ньому буде цґлком легкий длЯ читаннЯ текст.
/* Џриклад використаннЯ fscanf () ґ fprintf () */
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
int main () {
setlocale(LC_CTYPE, "Russian");
FILE *fp;
char s [80];
int t;
if ((fp = fopen ("test1", "w")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \ n");
system ("pause");
exit (1);
}
printf ("‚ведiть рЯдок i число: ");
fscanf (stdin, "%s %d", s, &t); /* читати з клавґатури */
fprintf (fp, "%s %d", s, t); /* писати в файл */
fclose (fp);
if ((fp = fopen ("test1", "r")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \n");
system ("pause");
exit (1);
}
printf("\n");
fscanf (fp, "%s %d", s, &t); /* читаннЯ з файлу */
fprintf (stdout, "%s %d", s, t); /* виведеннЯ на екран */
printf("\n");
fclose (fp);
system ("pause");
return 0;
}
Њаленьке попередженнЯ. •оча читати рґзносортнґ данґ з файлґв на дисках ґ писати »х у файли, розташованґ також на дисках, часто легше всього саме за допомогою функцґй fprintf () ґ fscanf (), але це не завжди найефективнґший спосґб виконаннЯ операцґй читаннЯ ґ запису. ’ак Як данґ в форматґ ASCII записуютьсЯ так, Як вони повиннґ з'ЯвитисЯ на екранґ (а не в двґйковому виглЯдґ), то кожен виклик цих функцґй пов'Язаний з певними накладними витратами. ’ому, Якщо треба пґклуватисЯ про розмґр файлу або швидкостґ, то, швидше за все, доведетьсЯ використовувати fread () ґ fwrite ().
”ункциЯ rewind()
”ормат функцґ»:
rewind(<вказґвник_на_файл>);
‚становлю№ вказґвник поточно» позицґ» у файлґ на початок файлу. ‚иклик функцґ» rewind (<вказґвник_на_файл>) вґдповґда№ виклику функцґ» fseek (<вказґвник_на_файл>, 0L, SEEK_SET) за винЯтком того, що rewind () скида№ ґндикатор кґнцЯ файлу ґ ґндикатори помилок, а fseek () скида№ тґльки ґндикатор кґнцЯ файлу. ЏґслЯ функцґ» rewind () можна виконувати операцґ» оновленнЯ длЯ файлґв, вґдкритих длЯ поновленнЯ. ”ункцґЯ не поверта№ нґЯкого значеннЯ.
™об познайомитисЯ з rewind (), змґнимо програму, розглЯнуту ранґше, таким чином, щоб вона вґдображала вмґст файлу вґдразу пґслЯ його створеннЯ. ™об виконати вґдображеннЯ, програма пґслЯ завершеннЯ введеннЯ "перемоту№" файл, а потґм чита№ його з самого початку. ‡вернґть увагу, що зараз файл необхґдно вґдкрити в режимґ читаннЯ/запису, використовуючи Як аргумент режим, що зада№ рЯдок "w+".
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
# include <string.h>
int main() {
setlocale(LC_CTYPE, "Russian");
char str [80];
FILE *fp;
if ((fp = fopen ("TEST", "w+")) == NULL) {
printf ("Џомилка при вiдкриттi файлу. \ n");
system ("pause");
exit(1);
}
do {
printf ("‚ведiть рЯдок (порожнiй рЯдок - длЯ виходу): \n");
gets (str);
strcat (str, "\n"); // додаваннЯ роздґльника рЯдкґв
fputs (str, fp);
} while (strcmp("\n", str)); // strcmp() - порґвнЯннЯ рЯдкґв
/* ’епер викону№тьсЯ читаннЯ ґ вґдображеннЯ файлу */
rewind (fp); /* встановити вказґвник поточно» позицґ» на початок файлу. */
while (! feof (fp)) {
fgets (str, 79, fp);
printf (str);
}
fclose (fp);
system ("pause");
return 0;
}
”ункциЯ remove()
”ормат функцґ»:
int remove (< ґм'Я_файлу>);
”ункцґЯ видалЯ№ файл з ґм'Ям FILENameString. Џеред видаленнЯм файл повинен бути закритий. ђЯдок FILENameString повинен мґстити повний шлЯх до файлу. Џри нормальному завершеннґ завданнЯ функцґЯ поверта№ нуль, а в разґ помилки Р 1 (ненульове значеннЯ). Џри цьому глобальна змґнна errno прийма№ наступнґ значеннЯ:
- EACCES - заборонено видалЯти;
- ENOENT - нема№ такого файлу або директорґ».
Ќаступна програма вилуча№ файл. Ћднак спочатку вона да№ можливґсть передумати. “тилґта, подґбна цґй, може стати в нагодґ комп'ютерним користувачам-новачкам.
/* Џодвґйна перевґрка перед вилученнЯм. */
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
# include <ctype.h>
int main() {
setlocale(LC_CTYPE, "Russian");
char str [80];
char filename[20]={"test"};
printf ("‚илучити файл test? (y/n):");
gets (str);
if (toupper (*str) == 'y')
remove (filename);
if (remove (filename)) {
printf ("Ќе можна вилучити файл. \n");
system ("pause");
exit (1);
}
system ("pause");
return 0;
}
”ункциЯ FILElength()
”ормат функции:
long FILElength(fp);
”ункцґЯ поверта№ довжину файлу з вказґвником fp в байтах. „лЯ роботи функцґ» потрґбно пґдключити файл io.h. “ випадку помилки функцґЯ поверта№ - 1, та глобальна змґнна errno набува№ значеннЯ EBADF - невґрний вказґвник файлу.
”ункциЯ ferror()
”ормат функцґ»:
ferror(fp);
”ункцґЯ ferror() визнача№, чи вґдбуласЯ помилка пґд час виконаннЯ операцґ» з файлом. Џрототип цґ№» функцґ» наступний:
int ferror(FILE < вказґвник_файлу >);
”ункцґЯ поверта№ значеннЯ true (ґстина), Якщо при останнґй операцґ» з файлом сталасЯ помилка, в ґншому ж випадку вона поверта№ false (неправда). ’ак Як при будь-Якґй операцґ» з файлом встановлю№тьсЯ своЯ умова помилки, то пґслЯ кожно» тако» операцґ» слґд одразу викликати ferror (), а ґнакше данґ про помилцґ можуть бути втраченґ.
“ наступнґй програмґ показано застосуваннЯ ferror (). Џрограма видалЯ№ табулЯцґ» з файлу, замґнюючи »х пробґлами. ђозмґр табулЯцґ» визнача№тьсЯ макросом TAB_SIZE. ‡вернґть увагу, що ferror () виклика№тьсЯ пґслЯ кожно» операцґ» з файлом.
/* Џрограма замґню№ в текстовому файлґ символи табулЯцґ» пробґлами ґ вґдслґдкову№ помилки. */
# include <stdlib.h>
# include <stdio.h>
# include <windows.h>
# include <locale.h>
# define IN 0
# define OUT 1
void err (int e);
int main() {
setlocale(LC_CTYPE, "Russian");
FILE *in, *out;
int i;
char ch;
if ((in = fopen ("testr", "rb")) == NULL) {
printf ("Ќе можна вiдкрити файл testr. \n");
system ("pause");
exit(1);
}
if ((out = fopen ("testw", "wb")) == NULL) {
printf ("Ќе можна вiдкрити файл testw. \n");
system ("pause");
exit(1);
}
do {
ch = fgetc (in);
if (ferror (in)) err (IN);
/* џкщо знайдена табулЯцґЯ, виводитьсЯ пробґл */
if (ch == '\t')
{
putc (' ', out);
if (ferror (out)) err (OUT);
}
else
{
putc (ch, out);
if (ferror (out)) err (OUT);
}
} while (!feof (in));
fclose (in);
fclose (out);
system ("pause");
return 0;
}
void err (int e) {
if (e == IN) printf ("Џомилка при введеннi. \n");
if (e == OUT) printf ("Џомилка при виведеннi. \n");
system ("pause");
exit (1);
}
”ункциЯ freopen()
”ормат функцґ»:
FILE *freopen(const char *FILEname, const char *mode, FILE *stream);
”ункцґЯ пґдставлЯ№ файл, заданий в першому параметрґ, замґсть уже вґдкритого потоку. ‚она закрива№ потґк незалежно вґд того, чи вґдкритий вґн. –Я функцґЯ корисна длЯ замґни файлу, пов'Язаного зґ стандартними пристроЯми введеннЯ/виведеннЯ stdin, stdout або stderr. ‘пособи вґдкриттЯ файлу аналогґчнґ функцґ» fopen (). Џри успґшному завершеннґ функцґЯ поверта№ вказґвник типу FILE (Як ґ функцґЯ fopen ()), при неуспґшному - NULL.
Џриклад перенаправленнЯ потоку за допомогою функцґ» freopen () наведено в лґстингу 1.
Истинг 1
/* ЏеренаправленнЯ стандартного виводу у файл */
if (freopen ("OUTPUT.FIL", "w", stdout) == NULL)
fprintf (stderr, "error redirecting stdout \n");
/* –ей висновок пґде вже в файл */
printf ("This will go into a FILE.");
/* ‡акриттЯ стандартного потоку */
fclose (stdout);
”ункциЯ ferror()
”ормат функцґ»:
ferror(FILE *fp);
”ункцґЯ вида№ ненульове значеннЯ, Якщо операцґЯ з файловим потоком завершу№тьсЯ з помилкою (наприклад, виника№ помилка читаннЯ файлу). „лЯ обробки помилок введеннЯ/виведеннЯ слґд записати цю функцґю перед блоком роботи з файлом у виглЯдґ:
if (ferror(fp)) { команди обробки помилок введеннЯ/виведеннЯ }
џк тґльки вґдбудетьсЯ помилка, викона№тьсЯ цЯ функцґЯ, ґ почнуть працювати команди обробки помилок.
”ункциЯ exit()
”ормат функцґ»:
exit(int status);
–Я функцґЯ використову№тьсЯ длЯ термґнового завершеннЯ роботи програми при обробцґ помилок вґдкриттЯ файлу, а також длЯ перериваннґ роботи програми з Якихось причин. Џеред завершеннЯм всґ файли закриваютьсЯ, залишки даних, що знаходЯтьсЯ в буферґ виведеннЯ, записуютьсЯ в пам'Ять ґ викликаютьсЯ функцґ» обробки помилок, попередньо заре№строванґ спецґальною функцґ№ю atexit (). –ґ функцґ» обробки помилок потрґбно написати самим ґ заре№струвати »х за допомогою виклику функцґ» atexit ().
„лЯ виклику функцґ» atexit () потрґбно пґдключити файл stdlib.h. Љожен виклик atexit () ре№стру№ нову функцґю exit (). Њожна заре№струвати до 32-х функцґй exit (). ‚они виконуватимутьсЯ за принципом роботи стеково» пам'Ятґ: "останнґй увґйшов - перший вийшов". ’обто останнЯ заре№стрована функцґЯ буде виконана першою. ЏоЯснимо сказане на прикладґ програми, наведено» в лґстингу 2.
Истинг 2
# include <stdio.h>
# include <stdlib.h>
/* –е перша функцґЯ exit () */
void exit_fn1 (void) {
printf ("Exit function # 1 called \ n");
}
/* –е друга функцґЯ exit () */
void exit_fn2 (void) {
printf ("Exit function # 2 called \ n");
}
/* ‚ основнґй програмґ вґдбува№тьсЯ ре№страцґЯ заданих ранґше функцґй exit (). ’ут же застосову№тьсЯ ґ сама функцґЯ exit (), Яка перед завершеннЯм роботи програми стане викликати цґ заре№строванґ ранґше функцґ» */
int main (void) {
/* ђе№страцґЯ першо» функцґ» */
atexit (exit_fn1);
/* ђе№страцґЯ друго» функцґ» */
atexit (exit_fn2);
/* Exit () спочатку викличе другу функцґю, тому що вона булла заре№стрована останньо», а потґм - першу функцґю. ЏґслЯ цього програма завершитьсЯ. */
exit (0);
return 0;
}
џке б числове значеннЯ ви не пґдставили замґсть аргументу функцґ», виклик заре№строваних функцґй exit () все одно вґдбудетьсЯ. џкщо ж не була заре№стрована жодна функцґЯ, то вґдбудетьсЯ завершеннЯ програми. ђе№страцґЯ функцґй exit () дґйсна тґльки в межах однґ№» програми.