16. Форматиран вход. Функция scanf.
Форматиран вход – от външен носител постъпва входен поток от символи; функцията, която ги обработва задава вида на данните като елементи от този входен поток и ги преобразува в променливи, представени в оперативната памет;
Функция scanf
Синтаксис:
scanf (“форматиращи параметри”, списък от аргументи);
scanf връща резултат от тип int; този резултат е броят на успешно въведените символи; връща EOF, ако има грешка при въвеждането или ако е въведен символ за край на файла;
форматиращите параметри при scanf съвпадат с параметрите от втори тип на printf; модификаторите, които се допускат са l, L - те променят очаквания тип на променливата (l променя int на long int, unsigned int на unsigned long int, double на float; L променя float на long double); друг модификатор, който се допуска е цяло число, записано непосредствено след %, което задава дължината на полето за въвеждане; по този начин на съответната променлива се присвоява число или низ от входното поле със зададена дължина
в рамките на един въведен елемент, а останалите въведени символи до разделителя се преобразуват съгласно следващата форматна спецификация и се присвояват на следващата променлива, ако няма следваща променлива те се игнорират;
въвеждана информация чрез scanf се присвоява на определени променливи; затова аргументите на scanf са адресите на съответните променливи;
адресът на една променлива се получава като пред името на променливата се постави символ &; изключение са имената на низовите променливи, тъй като те се разглеждат като символни масиви; името на един символен масив е адресът на първия елемент на този масив;
информацията, която се въвежда от клавиатурата се нарича входен поток от данни; този поток от данни е разбит на елементи, като разделители между елементите се използват празните символи (интервал, символ за нов ред, символ за табулация);
при форматна спецификация s, можем да използваме
модификатор *, който е записан непосредствено след % (преди дължината на полето за въвеждане); този модификатор задава игнорирането на частта от входния поток, за която се отнася съответната спецификация;
Важно: scanf не въвежда празни символи!!; винаги, когато въвеждаме масив от символи, трябва да се съобразяваме с това, че последният символ в масива трябва да е нулевият байт; тогава дължината на най-дългия възможен низ, записан в един символен масив е с едно по-малка от размерността му;
Примери:
float x, y; int z; unsigned t;
scanf(“%6f%f%3d%o”, &x, &y, &z, &t);
нека е въведен входния поток (_ означава интервал):
25.12345678 _ 12376
тогава на x ще се присвои 25.123, на y ще се присвои 45678; на z ще се присвои 123, на t ще се присвои 62 (76 в осмична = 62 в десетична бройна система);
нека е въведен входния поток:
25.4 _ 123 _ 12 _ 76
тогава на x ще се присвои 25.4 (независимо от това, че за x сме задали по-голямо поле, тъй като сме достигнали празен символ), на y ще се присвои 123, на z ще се присвои 12, на t ще се присвои 62;
char x, y, z;
scanf(“%c%c%c”, &x, &y, &z);
нека е въведен входния поток:
abc
тогава на x се присвоява ‘a’, на ‘y’ се присвоява ‘b’, на z се присвоява ‘c’;
нека е въведен входния поток:
ab
тогава на x се присвоява ‘a’, на ‘y’ се присвоява ‘b’, на z се присвоява ‘\n’;
char m[5], a[5];
scanf(“%s%2s”, m, a);
нека е въведен входния поток:
abc _ def
тогава: m[0]=’a’, m[1]=’b’, m[2]=’c’, m[3]=’\0’; a[1]=’d’, a[2]=’e’, a[3]=’\0’;
scanf(“%2s%*2s%s”, m, a);
нека е въведен входния поток:
abcdefgh
тогава: m[0]=’a’, m[1]=’b’, m[2]=’\0’; a[0] = ‘e’, a[1] = ‘f’, a[2] = ‘g’, a[3]=’h’, a[4]=’\0’;
Обобщение: за scanf се отнасят същите забележки като за printf; тя е неефективна и не се препоръчва нейната употреба, когато е възможно използването на по-прости функции;
17. Функции. Общ вид. Оператор return.
Една програма на C представлява съвкупност от функции;
Общ вид на една функция:
[ тип ] име на функцията (списък от тип и име на формални параметри)
{
тяло на функцията
}
типът на една функция е типът на резултата, който тя връща; функцията може да не връща резултат, ако на мястото на типа е записано void; ако типът е пропуснат, той по подразбиране се смята за int;
името на функцията е идентификатор; главната функция има име main, това е запазена дума и не може да се използва за име на потребителска функция;
тялото на функцията се състои от дефиниции на променливи и оператори;
резултатът от една функция се формира с оператор return;
синтаксис:
return (израз);
изпълнение: пресмята се израза, типа на израза се преобразува към типа на функцията и се прекратява изпълнението на функцията; ако функцията е void можем да използваме return без израз за да прекратяваме изпълнението на функцията; ако една функция е void, но в нея няма оператор return, тогава достигането до затварящата фигурна скоба на тялото на функцията е еквивалентно на изпълнението на оператор return;
скобите, които заграждат изразът не са задължителни;
функцията може да няма формални параметри, но скобите са задължителни;
концепция за скобите в различните версии на C:
-
в Кърнингън и Ричи C ако е зададено (), това означава, че не се уточнява броя на параметрите;
-
в ANSI C за да зададем функция без формални параметри между кръглите скобки трябва да има void
-
в C++ () задава функция без формални параметри
19 ноември
в тялото на една функция може да има няколко оператора return, но ще се изпълни само един или нито един тях;
Пример:
преобразуване на малки латински букви в големи;
char toupper( c : char)
{ return ( (c>=’a’ && c<=’z’ )?c – ‘a’ + ‘A’:c ); }
намиране на n!
long int fact (int n)
{ long nf; nf = 1; int i;
for (i = 2; i<=n; i++)
nf = nf * i;
return nf;
}
18. Обръщение към функция.
За да се изпълни една функция, трябва да и се предаде управлението; това става чрез обръщение към тази функция;
функцията, която предава управлението е извикваща, а тази която приема управлението е извикана; една извикана функция може да извика друга функция;
Синтаксис на обръщението:
име_на_функцията (списък_от_фактически_параметри);
обръщението към функция може да се използва по два различни начина:
-
като операнд в израз; резултатът, който се връща от return замества операнда; ако обръщението към функцията е в операнд, тя обезателно трябва да връща резултат, в противен случай операндът ще има неопределена стойност;
-
обръщението към функцията завършва с точка със
запетая (;) – това обръщение се разглежда като оператор; естествено е в този случай функцията да е от тип void; ако тя не е от тип void резултатът от функцията не се използва (той се губи);
В общия случай фактическите параметри са изрази; въпросът за съответствие между тях и формалните параметри търпи развитие; в общия случай броят на фактическите параметри трябва да е равен на броя на формалните параметри; това не се спазва в случая, когато функцията е с променлив брой параметри; въпросът е дали типовете на фактическите параметри съвпадат с тези на формалните;
в Кърнингън и Ричи C се изисква съвпадение;
в ANSI C, C++ няма такова изискване, т.е. типа на фактическия параметър може да се различава от типа на формалния параметър; в такъв случай стойността на фактическия параметър се преобразува към типа на формалния параметър;
Реализация на обръщението – използва се програмен стек, разположен в частта от оперативната памет, разпределена за програмата;
-
пресмятат се фактическите параметри; проверява се дали типа на съответните формални параметри съвпадат с типа на фактическите параметри; ако някъде няма съотвествие се извършва преобразуване на стойността на фактическия параметър; в C фактическите параметри се пресмятат от дясно на ляво (за разлика от Pascal, където е от ляво на дясно) и стойностите им една по една се записват в стека; повечето компилатори имат опция с която се задава реда на пресмятане на фактическите параметри;
-
след това се предава управлението на функцията и се разпределя памет за формалните параметри в стека; при това за всеки формален параметър се разпределя памет точно там, където е записана стойността на съответния фактически параметър, която трябва да му се присвои;
Ако променяме стойностите на формалните параметри, тогава стойностите на съответните фактически параметри не се променят; ако искаме да променяме един фактически параметър, трябва в обръщението към функцията да зададем неговия адрес;
Примери:
#include
char toupper( c : char)
{ return ( (c>=’a’ && c<=’z’ )?c – ‘a’ + ‘A’:c ); }
void main ()
{ char a, b;
int br;
printf (“Въведи символи: \n”);
br = 0;
do {
a = getchar();
b = toupper (a);
if (br==0)
printf (“Преобразуваната последователност от символи: \n”);
printf(“%c”,b);
br++; }
while (b != ‘\n’);
br--;
printf (“Брой обработени символи: %d\n”, br);
}
#include
long int fact (int n)
{ long nf; nf = 1; int i;
for (i = 2; i<=n; i++)
nf = nf * i;
return nf;
}
void main ()
{ int x;
printf (“Въведи x = “);
scanf (“%d”, &x);
printf (“x! = %ld\n”, fact(x) );
}
19. Прототипи на функция.
Прототипите на една функция са нужни за да може правилно да стане заместването на формалните с фактическите параметри; когато транслаторът реализира обръщение към функция, той трябва предварително да има информация за броя и типовете на формалните параметри за да знае дали стойностите на съответните фактически параметри трябва да бъдат преобразувани и към какъв тип; освен това, той трябва да знае какъв е типа на връщания резултат, за да може да прецени дали този тип трябва да се преобразува;
в програмите по-горе, компилаторът научава функцията преди да има обръщение към нея; ако обаче разменим местата на двете функции, компилаторът ще даде съобщение за грешка, тъй като той попада на обръщението, но няма необходимата информация;
именно затова в този случай трябва да запишем прототипа на функцията преди обръщението към нея (прието е, прототипите на функциите да се поставят непосредствено след директивите към препроцесора);
Синтаксис:
тип_на_функция име_на_функция (списък от формални параметри);
в прототипа на една функция можем да пропуснем имената на формалните параметри;
Примери:
char toupper (char c);
long fact (int);
Един заглавен файл съдържа (не само) прототипи на функции; по същата причина, за да се обръщаме към стандартна функция, след като не сме я описали, трябва да зададем нейния прототип, който е записан в заглавния файл; затова го включваме в началото на програмата;
Сподели с приятели: |