Вход-изход на числа, знаци и низове към конзолата
Вход-изход на числа, знаци и низове към конзолата. Превключване на вход-изход, работа с файлове - раздел Обучение, Общи характеристики на езика C в сравнение с други процедурни езици Под входно-изходни функции имам предвид функции, които извършват транспо.
I/O функциите се отнасят до функции, които извършват транспортиране на данни към и от програма. Вече сме използвали две такива функции: printf() и scanf(). Сега нека разгледаме няколко други функции, предоставени от езика C.
I/O функциите не са част от дефиницията на езика C. Разработката им е поверена на програмисти, внедряващи компилатор от езика C. От друга страна, ползата от използването на стандартен набор от I/O функции във всички системи е очевидна. Това прави възможно писането на преносими програми, които могат лесно да се използват на различни машини. Езикът C има много I/O функции от този тип, като printf() и scanf(). По-долу ще разгледаме функциите getchar() и putchar().
Функцията getchar() взема един знак от терминалната конзола (и следователно има име) и го предава на текущо изпълняващата се програма. Функцията putchar() взема един символ от програмата и го изпраща на екрана. Помислете за примерна програма, която взема един знак от клавиатурата и го отпечатва на екрана:
За повечето системи спецификациите за функциите getchar и putchar се съдържат в системния файл stdio.h, така че сме посочили този файл в програмата. Функцията getchar() няма аргументи, т.е. когато се извиква, в скоби не се поставя стойност. Тя просто получава следващия входящ знак исам връща стойността си на изпълнимата програма. Изявлението на ред 1 присвоява стойността на функцията getchar() на променливата ch. Функцията putchar() има един аргумент. Когато го извиквате, трябва да посочите в скоби знака, който искате да отпечатате. Аргументът може да бъде единичен знак (включително знаци, представени от екраниращи последователности), променлива или функция, чиято стойност е единичен знак. Правилното извикване на putchar() е да посочите някой от тези аргументи, когато го извиквате:
putchar(ch); /* променлива от тип char */
Нека променим нашата програма:
Такава нотация е много компактна и не изисква въвеждането на спомагателни променливи. В резултат на компилация, такава програма е по-ефективна.
Когато тази програма (която и да е от двете й версии) се изпълни, въведеният знак в някои изчислителни системи веднага ще се появи на екрана (ехо печат), докато в други изчислителни системи нищо не се случва, докато не натиснем клавиша Enter. Първият случай се отнася до небуфериран (директен) вход, което означава, че изходният знак е незабавно достъпен за чакащата програма. Вторият случай е пример за буфериран вход, при който входните знаци се събират и поставят в някаква област от временната памет, наречена буфер. Натискането на клавиша Enter кара блок от знаци или единичен знак да бъде достъпен за програмата. В нашата програма се използва само първият знак, тъй като функцията getchar() се извиква веднъж в нея.
Защо са необходими буфери? Първо, оказва се, че предаването на няколко символа под формата на единичен блок може да се извърши много по-бързо, отколкото предаването им последователно един по един. Второ, ако при въвеждане на символи е разрешеногрешка, можем да използваме коригиращите инструменти на терминала, за да я поправим. И когато натиснем клавиша Enter, коригираният низ ще бъде предаден. За някои диалогови програми обаче небуферираният вход може да е приемлив. Например в текстообработващите програми би било желателно всяка команда да се въвежда веднага щом натиснем съответния клавиш. Следователно както буферираният, така и небуферираният вход имат своите предимства.
Помислете за отпечатване на групи от знаци. Желателно е по всяко време да можете да спрете програмата. За да направите това, нека напишем програма, така че да спре да работи, когато получи някакъв специален знак, например "!":
/* въвеждане и печат на знаци преди пристигането
#define STOP '!' /* дава знак '!' символично име */
В този пример, първия път през тялото на цикъла, функцията putchar() получава стойността на своя аргумент в резултат на изпълнение на оператора на ред 9. Освен това, до края на цикъла, стойността на този аргумент е знакът, предаден на програмата от функцията getchar, намираща се на ред 12. Цикълът while ще чете и отпечатва символи, докато пристигне знакът STOP.
Програмата по-долу прави същото, но стилът е по-добър в духа на езика C:
докато ((ch=getchar( )) != СТОП) /***8***/
Един ред 8 от тази програма замества редове 9, 10, 12 от предишната програма.
Четене на един ред
Нека усложним I/O примера:
/* инициализиране на брояча на символи 0 */
докато ((ch=getchar( )) != СПРИ)
брой++; /* добавяне на 1 към брояча */
Ако просто искаме да преброим броя на въведените знаци безза да ги покажете на екрана, функцията putchar( ) може да бъде пропусната.
Нека заменим знака за край на въвеждането на данни, използвайки символа за нов ред n. За да направите това, трябва да предефинирате флага STOP:
Знакът за нов ред се изпраща при натискане на клавиша Enter. Да приемем, че сме направили посочената промяна в програмата "броене на знаци" и след това сме въвели следния ред при изпълнение:
На екрана има тридесет и четири знака. [Enter]
В отговор на екрана ще се появят следните редове:
На екрана има тридесет и четири знака.
Знакът, който се появява в резултат на натискане на клавиша Enter, не е включен в броя от 34 знака, преброени от програмата, тъй като броенето се извършва вътре в цикъла. Сега имаме програма, която може да чете един ред.
докато ((ch = getchar( )) != EOF)
Това трябва да се помни:
Не е необходимо сами да дефинирате EOF флага. Описано е във файла.
Не е нужно да се интересуваме от действителното значение на символа EOF, тъй като директивата #define във файла ни позволява да използваме неговото символно представяне.
Променихме типа на променливата ch от char на int в нашата програма. Направихме това, защото стойността на променливите от тип char е цяло число без знак в диапазона от 0 до 255, а флагът EOF може да има числова стойност -1. Тази стойност е невалидна за променлива от тип char. Функцията getchar() всъщност връща int стойност, така че може да прочете символа EOF.
Променлива от целочислен тип ch няма ефект върху работата на функцията putchar(). Той просто отпечатва символния еквивалент на стойността на аргумента.
Когато работите с тази програма, когато символите се въвеждат от клавиатурата, трябва да можете да въведете знака EOF. В повечето реализации на операционната система UNIX, например, писане[CTRL/d] (натискането на клавиша [d] при задържане на клавиша [CTRL] се интерпретира като знак EOF. Много микрокомпютри използват знака [CTRL/z] за същата цел).
Да предположим, че сме въвели фраза от клавиатурата. Ето резултата от програмата "input-output_f" в системата, с буфериран вход:
Търсене на висококвалифицирани ИТ специалисти
Търсене на висококвалифицирани ИТ специалисти
нараства както от страна на държавата, така и
частните компании растат както отвън
публични и частни компании
При всяко натискане на клавиша Enter символите в буфера се обработват и се отпечатва копие на низа. Това продължава, докато не влезем в EOF флага. Програмата input-output_f отпечатва знаци на екрана, без значение откъде идват. Нашата програма може да преглежда съдържанието на файловете, да създава нови файлове и да получава копия на файлове. Решението на тези проблеми е в управлението на входа и изхода.
Превключване и работа с файлове
Концепцията за I/O включва функции, данни и устройства. Помислете например за програмата "input-output_f". Той използва функцията getchar(), за да приема входни данни, като входното устройство е клавиатурата (както предположихме), а изходът е единични знаци. Нека променим източника на данни, влизащи в програмата. По подразбиране C програма третира стандартния вход като източник на вход. Стандартният вход е устройство, което се приема като обичайно средство за въвеждане към машина. Това може да е четец на телетайп или терминал. Можем сами да изберем устройството за данни от всеки източник. Е, например, можем да напишем в програмата, че източникътВходните данни са файл, а не клавиатура.
Има два начина за писане на програми, които работят с файлове. Първият начин е изрично да използвате специални функции, които отварят и затварят файлове, организират четене и запис на данни и т.н. Ще обсъдим този въпрос в Глава 15. Вторият начин е да се използва програма, първоначално проектирана с въвеждане от клавиатурата и извеждане на екрана, но превключване на въвеждане и извеждане към други информационни канали, като например от файл към файл. Този метод е в някои отношения по-малко мощен от първия, но много по-лесен за използване. Операцията за превключване е характеристика на UNIX OC, а не на самия език C. Но се оказа толкова полезно, че когато даден компилатор се пренася от езика C към други изчислителни системи, тази операция често се прехвърля заедно с него. Много от новосъздадените операционни системи, като MS-DOS 2, включват тази възможност. Първо ще обсъдим възможностите на тази операция в OC UNIX, а след това и в други системи.
Превключване на изхода. Да предположим, че компилираме програмата "input-out_f" и поставим изпълнимия обектен код във файл, наречен get_put. След това, за да стартираме тази програма, въвеждаме от терминала само името на файла
и програмата се изпълнява, както е описано по-горе, т.е. приема като вход символи, въведени от клавиатурата. Сега да предположим, че искаме да видим как нашата програма работи с текстов файл с име words. Текстовият файл е файл, съдържащ някакъв текст, т.е. данни под формата на знаци. Това може да бъде например история или C програма. Файл, съдържащ команди на машинен език, не е текстов файл. Тъй като нашитеТъй като програмата обработва знаци, тя трябва да се използва заедно с текстов файл. За да направите това, въведете следната команда:
и започнете да въвеждате знаци. Символ > означава операцията за превключване, използвана в OC UNIX. Неговото изпълнение води до факта, че се създава нов файл с името my_words и след това резултатът от програмата input-output_f, който е копие на входните знаци, се изпраща към този файл. Ако вече съществува файл с име my_words, той обикновено се унищожава и вместо това се създава нов. Думите, които въвеждате, се появяват на екрана. Техните копия ще бъдат изпратени в посочения файл. За да завършим работата, въвеждаме EOF, в OC UNIX това обикновено е [CTRL / d].
Да предположим, че искаме да направим копие на файла my_words и да го кръстим my_words2. Трябва да въведете командата за това