Ocenite etot tekst:


 © Copyright Andrej Bogatyrev
 Email: abs@opentech.olvit.ru
---------------------------------------------------------------



Peremennaya - eto takoj "yashchichek" s imenem,
v kotorom mozhet hranit'sya nekoe ZNACHENIE.
Imya u peremennoj postoyanno i neizmenno,
znachenie zhe mozhet menyat'sya.

Naprimer, pust' u nas est' peremennaya s imenem "x".

	-----
       / x /
     ---------------
     | Tekushchee     |
     | znachenie,   |
     | naprimer 12 |
     ---------------

Peremennuyu mozhno izmenyat' pri pomoshchi operacii PRISVAIVANIYA.
V yazyke Si ona oboznachaetsya znakom ravenstva.

	x = 12  ;

|to chitaetsya ne kak "iks ravno 12",
a kak "prisvoit' peremennoj iks znachenie 12",
to est' "Polozhit' v yashchik s nadpis'yu IKS chislo 12".

Takaya stroka yavlyaetsya prostejshim OPERATOROM,
to est' DEJSTVIEM. V konce operatorov stavitsya tochka s zapyatoj.

Rassmotrim operator

	x = x + 3;


|to ne uravnenie. Esli rassmatrivat' etu stroku kak matematicheskoe
uravnenie, ono ne imeet reshenij. Na samom dele tut napisano:

	1) "vzyat' znachenie peremennoj IKS"
	2) "pribavit' k nemu 3"
	3) "polozhit' novoe znachenie v peremennuyu IKS",
	    sterev   v nej prezhnee znachenie.

U opreatora prisvaivaniya est' dve chasti: LEVAYA i PRAVAYA.

	LEVAYA_CHASTX = PRAVAYA_CHASTX ;

V levoj chasti obychno stoit prosto imya peremennoj V KOTORUYU
zapisyvaetsya vychislennyj sprava rezul'tat.

Esli imya peremennoj vstrechaetsya v PRAVOJ chasti, to eto
oznachaet "podstavit' syuda tekushchee znachenie etoj peremennoj".

Pri etom tekushchee znachenie samoj peremennoj NE izmenyaetsya,
beretsya ego kopiya. To est', "vynutoe iz yashchika znachenie"
ne ostavlyaet yashchik pustym! Vynimaetsya kopiya, drugaya kopiya ostaetsya v yashchike.

Itak:

	x = x + 3 ;

Pust' sejchas znachenie x est' 12

Snachala vychislyaetsya PRAVAYA chast' operatora prisvaivaniya.

		x + 3

	-----
       / x /
     ---------------
     |  12   |     |
     --------|------
	     |
	     |
	     | VZYATX kopiyu znacheniya (to est' chislo 12) iz yashchika s imenem "IKS"
	     |
	     V
	 Vmesto x
	 podstavlyaem
	   chislo
	    12    +    3    ---->   SKLADYVAEM.

				    Slozhenie daet 15.
				    V etot moment x vse eshche ravno 12
				    (v yashchike lezhit chislo 12)

Teper' vychislyaetsya samo prisvaivanie:

	x = 15 ;

	     |
	     |
	     | POLOZHITX rezul'tat v yashchik s imenem "IKS"
	     | (istrebiv v nem prezhnee znachenie, esli bylo)
	-----|
       / x / |
     --------|------
     |  12   V     |
     ---------------


Stalo:
	-----
       / x /
     ---------------
     |  15         |
     ---------------

V peremennoj s tem zhe imenem teper' nahoditsya novoe znachenie,
ona izmenilas'. Potomu i "peremennaya".

V nekotoryh yazykah programmirovaniya, naprimer v Pascal ili Modula,
operaciya prisvaivaniya oboznachaetsya simvolom :=  a ne =
|to umen'shaet putanicu, no k smyslu = mozhno privyknut' dovol'no bystro.
Ne ogorchajtes'.

V pravoj chasti znachenie peremennoj mozhet ispol'zovat'sya neskol'ko raz:

	z = x * x + 2 * x;

Tut est' dve peremennye:

	z - dlya rezul'tata.
	x - uzhe imeyushchaya kakoe-to znachenie.

	x * x oznachaet "umnozhit' iks na iks" (pri etom samo znachenie,
	      lezhashchee v yashchike iks ne izmenyaetsya!)

	x * 2 oznachaet "vzyat' dva znacheniya iks"

	+     oznachaet slozhenie.

Peremennye nado OB¬YAVLYATX.
|to neobhodimo potomu, chto inache, esli by peremennye vvodilis' prosto
ispol'zovaniem imeni peremennoj, i my vdrug dopustili by OPECHATKU, naprimer:

	idneks = 1;

vmesto

	indeks = 1;

to u nas poyavilas' by "lishnyaya" peremennaya "idneks", a ozhidaemoe dejstvie ne
proizoshlo by. Takuyu oshibku najti cherezvychajno tyazhelo. Esli zhe peremennye
nado ob®yavlyat', to neob®yavlennye peremennye budut vyyavleny eshche na stadii
kompilyacii programmy.

Peremennye, kotorye budut hranit' celye chisla ( ..., -2, -1, 0, 1, 2, 3, ...),
ob®yavlyayut tak:

	int peremennaya1;
	int peremennaya2;

Ili srazu neskol'ko v odnoj stroke:

	int peremennaya1, peremennaya2;

int oznachaet sokrashchenie ot slova integer - "celyj".



Programma sostoit iz OPERATOROV, to est' dejstvij.
Operatory vypolnyayutsya posledovatel'no v tom poryadke,
v kotorom oni zapisany.

	/* OB¬YAVLYAEM DVE PEREMENNYE */
	int x, y;      /* 0 */

	/* |to eshche ne operatory, hotya pri etom sozdayutsya 2 yashchika dlya
	   celyh chisel
	 */

	/* A TEPERX - OPERATORY. */
	/* My nachnem s prostyh operatorov prisvaivaniya i arifmetiki */

	x = 3;          /* 1 */
	y = 4;          /* 2 */
	x = x + y;      /* 3 */
	y = y - 1;      /* 4 */
	x = y;          /* 5 */

Znacheniya peremennyh (to, chto lezhit v yashchikah) menyayutsya takim obrazom:

			   x       y
/* 0 */                 musor   musor

/* posle 1 */           3       musor
/* posle 2 */           3       4
/* posle 3 */           7       4
/* posle 4 */           7       3
/* posle 5 */           3       3

Kak vy vidite, peremennye, kotorye ne uchastvuyut v levoj chasti operatora
prisvaivaniya, etim operatorom NE MENYAYUTSYA.

Poslednyaya operaciya x = y; NE delaet imena x i y sinonimami.
Takoj veshchi, kak "pereveshivanie tablichek s imenami s yashchika na yashchik"
ne proishodit. Vmesto etogo, dva yashchika s imenami x i y soderzhat
odinakovye znacheniya, to est' dve kopii odnogo i togo zhe chisla.

	-----                       -----
       / x /                       / y /
     ---------------             ---------------
     |  3      *<--|--------<----|-- 3         |
     ---------------    1)       ---------------
	2), 3)                       4)

1) Iz yashchika y beretsya KOPIYA chisla 3 (bezymyannoe znachenie).
2) Staroe soderzhimoe yashchika x unichtozhaetsya.
3) CHislo 3 kladetsya v yashchik x.
4) V ishodnom yashchike y poprezhnemu ostalos' 3.

Znachenie celoj peremennoj mozhno vyvesti na ekran operatorom pechati:

	printf("%d\n", x);

Poka budem rassmatrivat' ego kak "magicheskij".

Nad celymi chislami mozhno proizvodit' takie arifmeticheskie operacii:

	x + y   slozhenie
	x - y   vychitanie
	x * y   umnozhenie
	x / y   delenie nacelo (to est' s ostatkom; rezul'tat - celoe)
	x % y   vychislit' ostatok ot deleniya nacelo

	5 / 2 dast 2
	5 % 2 dast 1

V operatorah prisvaivaniya ispol'zuyutsya takie sokrashcheniya:

DLINNAYA ZAPISX          SMYSL                   SOKRASHCHAETSYA DO
x = x + 1;              "uvelichit' na 1"        x++;    (ili ++x; )
x = x - 1;              "umen'shit' na 1"        x--;    (ili --x; )
x = x + y;              "pribavit' y"           x += y;
x = x * y;              "umnozhit' na y"         x *= y;
x = x / y;              "podelit' na y"         x /= y;

V tom chisle x++; mozhno zapisat' kak x += 1;



Obychno operatory vypolnyayutsya posledovatel'no,
v tom poryadke, v kotorom oni zapisany v programme.

	operator1;      |
	operator2;      |
	operator3;      |
	operator4;      V



	if(uslovie) operator;

	...prodolzhenie...

Rabotaet tak:

	Vychislyaetsya uslovie.

	Esli ono istinno, to vypolnyaetsya operator,
	     zatem vypolnyaetsya prodolzhenie.

	Esli ono lozhno, to srazu vypolnyaetsya prodolzhenie,
	     a operator ne vypolnyaetsya.

Esli nam nado vypolnit' pri istinnosti usloviya neskol'ko operatorov,
my dolzhny zaklyuchit' ih v skobki { ... } - eto tak nazyvaemyj
"sostavnoj operator".

	if(uslovie) {
		operator1;
		operator2;
		...
	}
	prodolzhenie

Posle } tochka s zapyatoj NE STAVITSYA (mozhno i postavit', no ne nuzhno).

Uslovnyj operator izobrazhayut na shemah tak:

		|
		|
		|
	----------------
     ---| ESLI uslovie |----
     |  ----------------   |
     |                     |
     V                     V
   istinno               lozhno
     |                     |
     V                     |
------------               |
| operator |               |
------------               |
     |                     |
     ------->-------<-------
		|
		|
		V
	  prodolzhenie
		|

Imeetsya vtoraya forma, s chast'yu "inache":

	if(uslovie) operator_esli_istinno;
	else        operator_esli_lozhno;

"ili to, ili drugoe" (no ne oba srazu)


		|
		|
		|
	----------------
     ---| ESLI uslovie |-----------
     |  ----------------          |
     |                            |
     V                            V
   istinno                      lozhno
     |                            |
     V                            |
-------------------------    -----------------------
| operator_esli_istinno |    | operator_esli_lozhno |
-------------------------    -----------------------
     |                            |
     ------->-------<--------------
		|
		|
		V
	  prodolzhenie
		|

Primer1:

	if(x > 10)
		printf("Iks bol'she desyati\n");

Primer2:

	int x, y, z;

	if(x < y)       z = 1;
	else            z = 2;

Usloviya:

	V kachestve uslovij mogut ispol'zovat'sya operatory SRAVNENIYA
	(sravnivat' mozhno peremennye, vyrazheniya, konstanty)

	x <  y          men'she
	x >  y          bol'she
	x <= y          men'she ili ravno
	x >= y          bol'she ili ravno
	x == y          ravno
	x != y          ne ravno

	Vse eti operatory v kachestve rezul'tata operacii sravneniya vydayut
	1, esli sravnenie istinno
	0, esli ono lozhno.

Takim obrazom, na samom dele uslovnyj operator rabotaet tak:

	if(uslovie) ....

Esli uslovie est' NOLX                               - to uslovie schitaetsya lozhnym.
Esli uslovie est' NE NOLX a ... -2, -1, 1, 2, 3, ... - to uslovie istinno.

|to opredelenie.

Iz nego v chastnosti vytekaet, chto sravnenie s celym nulem mozhno opuskat':

if(x != 0) ... ;        sokrashchaetsya do          if(x)  ... ;
if(x == 0) ... ;        sokrashchaetsya do          if(!x) ... ;
-------------------------------------------------------------------------
Primer:

	int x, y, z;

	if(x == 1){ y = 2; z = x + y; }
	else      { y = 1; z = x - y; }

-------------------------------------------------------------------------
Primer so vlozhennymi uslovnymi operatorami:

	if(x == 1){
		printf("Iks raven 1\n");
		if(y == 2){
			printf("Igrek raven 2\n");
		}
	} else {
		printf("Iks ne raven 1\n");
	}
-------------------------------------------------------------------------
CHasto primenyaetsya posledovatel'nost' uslovnyh operatorov,
perebirayushchaya razlichnye varianty:

	if(x == 1)
		printf("Iks raven 1\n");
	else if(x == 2)
		printf("Iks raven 2\n");
	else if(x == 3){
		printf("Iks raven 3\n");
		y = 1;
	} else
		printf("Nepredusmotrennoe znachenie iks\n");
-------------------------------------------------------------------------
Samoe slozhnoe - privyknut' k tomu, chto sravnenie oboznachaetsya znakom ==,
a ne =
Znak = oznachaet "prisvoit' znachenie", a ne "sravnit' na ravenstvo".



	while(uslovie)
		operator;
	...prodolzhenie...

ili

	while(uslovie){
		operatory;
		...
	}
	...prodolzhenie...

		|
		V
		|
      +------>--+
      |         |
      |         V
   P  |     ---------------------
   o  |     | proverit' USLOVIE |-------> esli lozhno (nul')
   v  A     ---------------------             |
   t  |         |                             |
   o  |         V                             |
   r  |     esli istinno (ne nul')            |
   i  |         |                             |
   t  |         V                             |
   '  |     operator                          V
      |         |                             |
      |         |                             |
      +-----<---+                             |
					      |
		+-------<---------------------+
		|
		V
	    prodolzhenie

Primer:
	int x;

	x = 10;
	while(x > 0){
		printf("x=%d\n", x);
		x = x - 1;
	}
	printf("Konec.\n");
	printf("x stalo ravno %d.\n", x);       /* pechataet 0 */

"Cikl" on potomu, chto ego telo povtoryaetsya neskol'ko raz.

CHtoby cikl okonchilsya, operator-telo cikla dolzhen menyat'
kakuyu-to peremennuyu, ot kotoroj zavisit istinnost' usloviya povtorenij.



Usloviya mogut byt' slozhnymi.

	ESLI krasnyj I ves < 10 TO ...;
	ESLI krasnyj ILI sinij  TO ...;
	ESLI NE krasnyj TO ...;

Na yazyke Si takie usloviya zapisyvayutsya tak:

	if(uslovie1 && uslovie2) ...;           /* "I"   */
	if(uslovie1 || uslovie2) ...;           /* "ILI" */
	if(! uslovie1)           ...;           /* "NE"  */

Naprimer:

	if(4 < x && x <= 12) ...;

Bylo by nepravil'no zapisat'

	if(4 < x <= 12) ...;

ibo yazyk programmirovaniya Si NE PONIMAET dvojnoe sravnenie!

Eshche primery:

	if(x < 3 || y > 4) ...;

	if( ! (x < 3 || y > 4)) ...;



|tot cikl yavlyaetsya prosto inoj zapis'yu odnogo iz variantov cikla while.
On sluzhit obychno dlya vypolneniya operedelennogo dejstviya neskol'ko raz,
ne "poka istinno uslovie", a "vypolnit' N-raz".

U takogo cikla est' "peremennaya cikla" ili "schetchik povtorenij".

	int i;

	i = a;  /* nachal'naya inicializaciya */

	while(i < b){

		telo_cikla;

		i += c; /* uvelichenie schetchika */
	}
	...prodolzhenie...

perepisyvaetsya v vide

	int i;

	for(i=a; i < b; i += c)
		telo_cikla;


telo_cikla budet vypolneno dlya znachenij i
	a
	a+c
	a+c+c
	...

	poka i < b

V prostejshem sluchae

	for(i=1; i <= N; i++)
		printf("i=%d\n", i);

i oznachaet "nomer povtoreniya".

Takoj cikl sluzhit dlya povtoreniya SHOZHIH dejstvij NESKOLXKO raz
s raznym znacheniem parametra.



Operator break zastavlyaet prervat' vypolnenie tela cikla
i srazu perejti k prodolzheniyu programmy.

	while(uslovie1){
		operatory1;

		if(uslovie2)
			break;  ------->----+
					    |
		operatory2;                 |
	}                                   |
	...prodolzhenie...<--------<---------+

i

	for(i=0; uslovie1; i++){
		operatory1;

		if(uslovie2)
			break;  ------->----+
					    |
		operatory2;                 |
	}                                   |
	...prodolzhenie...<--------<---------+


|tot operator pozvolyaet organizovyvat' dopolnitel'nye
tochki vyhoda iz cikla (pri dopolnitel'nyh usloviyah).

Primer:

	for(i=0; i < 20; i++){
		printf("i=%d\n", i);
		if(i == 7){
			printf("break loop!\n");
			break;          /* vyvalit'sya iz cikla */
		}
		printf("more\n");
	}
	printf("finished, i=%d\n", i);  /* pechataet 7 */

V chastnosti, s ego pomoshch'yu mozhno organizovyvat' beskonechnyj cikl:

	for(;;){        /* zagolovok beskonechnogo cikla */
		operatory1;

		if(uslovie2)
			break;  ------->----+
					    |
		operatory2;                 |
	}                                   |
	...prodolzhenie...<--------<---------+

Zdes' v samom zagolovke cikla NE PROVERYAETSYA NIKAKIH USLOVIJ,
takoj cikl prodolzhaetsya beskonechno.
Uslovie prodolzheniya schitaetsya vsegda istinnym.

Edinstvennyj sposob vyjti iz nego -
eto sdelat' break (pri kakom-to uslovii) v tele cikla, chto i napisano.

Beskonechnyj cikl mozhno takzhe organizovat' pri pomoshchi
	while(1){
		...
	}



	printf("tekst");

Pechataet na ekran tekst.

	printf("tekst\n");

Pechataet na ekran tekst i perehodit k novoj stroke.

	printf("slovo1 slovo2 ");
	printf("slovo3\n");

pechataet

slovo1 slovo2 slovo3
i perehodit na novuyu stroku.

Esli perehod na novuyu stroku ne zadan yavno, simvolom \n,
to tekst prodolzhaet pechatat'sya v tekushchej stroke.

	printf("%d", x);

Pechataet v tekstovom vide ZNACHENIE peremennoj x.
Special'naya konstrukciya %d oznachaet
"vzyat' peremennuyu iz spiska posle zapyatoj
 i napechatat' ee znachenie v ivde celogo chisla".

	printf("iks raven %d - ogo-go\n", x);

Pechataet snachala tekst

		iks raven

zatem znachenie peremennoj x kak celoe chislo,
zatem tekst
		- ogo-go

i perehodit na novuyu stroku (poskol'ku ukazan simvol \n).

|tot operator mozhet pechatat' i neskol'ko znachenij peremennyh:

	int x, y;

	x = 12; y = 15;
	printf("iks est' %d, igrek est' %d, vse.\n", x, y);
						    ~~~~~~

Dannyj operator rabotaet tak.
Stroka "iks est' %d, igrek est' %d\n" nazyvaetsya FORMATOM.
Komp'yuter chitaet format sleva napravo i pechataet tekst
do teh por, poka ne vstretit simvol %d.
Kursor izobrazhen simvolom _

	iks est' _

Dalee on beret PERVUYU peremennuyu iz spiska ~~~~ i
pechataet ee kak celoe chislo.

	iks est' 12_

dalee on snova pechataet tekst poka ne vstretit %d

	iks est' 12, igrek est' _

Teper' on beret VTORUYU peremennuyu iz spiska i pechataet ee:

	iks est' 12, igrek est' 15_

Snova pechataet tekst, vklyuchaya perevod stroki \n.
Kak tol'ko stroka formata konchilas', operator printf zavershen.

	iks est' 12, igrek est' 15, vse.
	_

Pechatat' mozhno ne tol'ko znacheniya peremennyh, no i znacheniya arifmeticheskih
vyrazhenij:

	printf("ravno: %d\n", 12 + 3 * 5);

Kontrol'nyj vopros, chto pechataetsya:

	int x, y, z;

	x = 13;
	y = 23;
	z = 34;

	printf("x=%d xx=%d\nzzz=%d\n", x, y - 1, z * 2 + 1);

Tut v formate est' DVA perevoda stroki,
poetomu budet napechatano:

	x=13 xx=22
	zzz=69
	_

Zamet'te, chto pered tem kak byt' napechatannymi,
vyrazheniya v spiske posle formata VYCHISLYAYUTSYA.

CHto napechataet

	printf("x=%d\n y=%d\n", x, y);

x=13
 y=23
_

Probel pered y voznik potomu, chto on SODERZHITSYA
v stroke formata posle simvola \n !!!
Bud'te vnimatel'ny.



Funkciej nazyvaetsya fragment programmy,
v kotoryj peredayutsya PARAMETRY,
i kotoryj VOZVRASHCHAET znachenie (ili nichego).

Prelest' funkcii v tom, chto ee mozhno vypolnit' mnogo raz
iz raznyh tochek programmy.

Funkciya sostoit iz

	OB¬YAVLENIYA      - opisaniya togo, kak ona chto-to vychislyaet
			  Ob®yavlenie byvaet rovno odno.

	VYZOVOV         - s konkretnymi znacheniyami parametrov,
			  chto imenno ona dolzhna na etot raz vychislit'.
			  Vyzovov mozhet byt' skol'ko ugodno.

Ob®yavlenie prostejshej funkcii vyglyadit tak:

	int func(int x){

		/* Odin ili neskol'ko operatorov,
		   zavershayushchihsya operatorom return(nechto);
		 */

		return x+1;
	}

-------------------------------------------------------------------------
	int func(...

zadaet funkciyu s imenem func
(imya vydumyvaet programmist, kak i imena peremennyh).

	int oznachaet, chto funkciya vozvrashchaet celoe znachenie.
-------------------------------------------------------------------------

	...(int x)...

zadaet spisok argumentov (ili parametrov) funkcii.
-------------------------------------------------------------------------
	      ...){
	      ...
	}

zadaet telo funkcii - nekuyu posledovatel'nost' ob®yavlenij
peremennyh i operatorov.
-------------------------------------------------------------------------

		return vyrazhenie;

zadaet operator vyhoda iz funkcii v tochku ee vyzova s vozvratom znacheniya
vyrazheniya.
-------------------------------------------------------------------------
Pokazhem prostoj primer VYZOVA etoj funkcii:

	int y;
	...
	y = func(5);            /* a */
	...prodolzhenie...       /* b */

|tot fragment rabotaet sleduyushchim obrazom:

	y = func(5);

V etoj tochke my
	1) "zapisyvaem na bumazhke",
	   chto vyzov proizoshel v takoj-to stroke, takom-to meste
	   nashej programmy.

	2) Smotrim na OPREDELENIE funkcii func.

	    int func(int x){...

	My vyzvali funkciyu kak func(5).
	|to znachit, chto v tele funkcii x poluchaet nachal'noe znachenie 5.

	To est' DLYA DANNOGO VYZOVA nasha funkciya (ee telo) prevrashchaetsya v

		int x;

		x = 5;
		return x+1;

	3) x+1 est' 6.

	   Dalee dolzhen vypolnit'sya operator return.

	   On vypolnyaetsya tak:

	   My "chitaem s bumazhki" - otkuda byla vyzvana funkciya func,
	   i smotrim na eto mesto. |to bylo

		y = func(5);

	   Vycherkivaem func(5) i zamenyaem ego ZNACHENIEM vyrazheniya,
	   vychislennogo v operatore return;

		y = 6;

	4) Vypolnyaem etot operator i perehodim k prodolzheniyu.

-------------------------------------------------------------------------

	int y, z, w;

	y = func(5);
	z = func(6);
	w = func(7) + func(8) + 1;

Prevratitsya v

	y = 6;
	z = 7;
	w = 8 + 9 + 1;

Pri etom my chetyre raza "prygnem" na opredelenie funkcii func(),
projdem vse ee operatory s raznymi znacheniyami parametra x
i vernemsya obratno v tochku vyzova.



Programma v celom sostoit iz funkcij.
Odna iz funkcij dolzhna imet' imya main(),

	S FUNKCII main NACHINAETSYA VYPOLNENIE PROGRAMMY.

	(na samom dele etomu predshestvuet otvedenie i inicializaciya
	 global'nyh peremennyh; smotri posleduyushchie lekcii).

CHasto main() - edinstvennaya funkciya v programme.

-------------------------------------------------------------------------
Struktura programmy takova:

	#include <stdio.h>      /* magicheskaya stroka */

	/* GLOBALXNYE PEREMENNYE (o nih pozzhe) */
	int a = 7;
	int b;          /* po umolchaniyu 0 */

	/* FUNKCII */
	f1(){....}
	f2(){....}

	/* NACHALXNAYA (GLAVNAYA) FUNKCIYA */
	void main(){
		...
	}
-------------------------------------------------------------------------
Primer programmy:

#include <stdio.h>

int f1(int x, int y){
	return (x + y*2);
}

int f2(int x){
	int z;

	z = x+7;
	return 2*z;
}

void main(){
	/* Ob®yavleniya peremennyh */
	int a, b, c;

	/* Operatory */
	a = 5; b = 6;

	c = f1(a, b+3);
	b = f1(1, 2);
	a = f2(c);

	printf("A est' %d B est' %d C est' %d\n", a, b, c);
}

Ona pechataet:

A est' 60 B est' 5 C est' 23



	int i;

	for(i=0; i < 4; i++){
		if(i == 0)      func0();
		else if(i == 1) func1();
		else if(i == 2) func2();
		else if(i == 3) func3();
	}

V dannom primere cikl ABSOLYUTNO NE NUZHEN.
To, chto tut delaetsya, est' prosto POSLEDOVATELXNOSTX operatorov:

	func0();
	func1();
	func2();
	func3();

Cikl imeet smysl lish' togda, kogda mnogo raz vyzyvaetsya
ODNO I TO ZHE dejstvie, no mozhet byt' zavisyashchee ot parametra, vrode func(i).
No ne raznye funkcii dlya raznyh i.

Analogichno, rassmotrim takoj primer:

	int i;

	for(i=0; i < 10; i++){
		if(i==0)        func0();
		else if(i == 1) func1();
		else if(i == 2) func2();
		else            funcN(i);
	}

Tut funcN(i) beret na sebya rol' "a v ostal'nyh sluchayah".
Odnako, etot primer bolee estestvenno mozhet byt' zapisan tak:

	int i;

	func0();
	func1();
	func2();
	for(i = 3; i < 10; i++)
		funcN(i);

Zamet'te, chto cikl teper' nachinaetsya s indeksa 3.

A teper' - sluchaj, gde smes' cikla i uslovnogo operatora opravdana:

	int i;

	for(i=0; i < 100; i++){
		if((i % 2) == 0) even();        /* chetnyj */
		else             odd();         /* nechetnyj */
	}

Tut v cikle proveryaetsya chetnost' indeksa i.

/* Treugol'nik iz zvezdochek */

#include <stdio.h>

/* putchar('c') - pechataet odinokij simvol c */
/* simvol \n - perevodit stroku              */
/* nstars - skol'ko zvezdochek napechatat'     */

/* Funkciya risovaniya odnoj stroki treugol'nika */
void drawOneLine(int nstars){
	int i;          /* nomer pechataemoj zvezdochki, schetchik */

	for(i=0; i < nstars; i++)  /* Risuem nstars zvezdochek podryad  */
		putchar('*');
	putchar('\n');             /* I perehodim na sleduyushchuyu stroku */
}

void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int nline;      /* nomer stroki */

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=1; nline <= 25; nline++)
		drawOneLine(nline);
	/* skol'ko zvezdochek? stol'ko zhe, kakov nomer stroki */
}

/* Treugol'nik iz zvezdochek */
/* Tot zhe primer so vlozhennym ciklom, a ne s funkciej */

#include <stdio.h>

void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int nline;      /* nomer stroki */
	int i;          /* nomer pechataemoj zvezdochki, schetchik */

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=1; nline <= 25; nline++){
		/* skol'ko zvezdochek? stol'ko zhe, kakov nomer stroki */
		for(i=0; i < nline; i++)
			putchar('*');
		putchar('\n');
	}
}

/* Treugol'nik iz zvezdochek */
/* Teper' treugol'nik dolzhen byt' ravnobedrennym */

#include <stdio.h>

/* nstars  - skol'ko zvezdochek napechatat'     */
/* nspaces - skol'ko probelov napechatat' pered zvezdochkami */

void drawOneLine(int nspaces, int nstars){
	int i;          /* nomer pechataemoj zvezdochki, schetchik */
			/* on zhe - nomer pechataemogo probela   */

	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nstars; i++)
		putchar('*');
	putchar('\n');
}

/*
			n (nomer stroki)
     ...*               1
     ..***              2
     .*****             3
     *******            4

	Vsego strok:                                    LINES
	CHislo zvezdochek v n-oj stroke:                  n*2 - 1
	CHislo probelov speredi (oboznacheny tochkoj):     LINES - n

	Vse eti chisla podschityvayutsya s kartinki...

	Ih my budem peredavat' v funkciyu drawOneLine v tochke _vyzova_,
	a ne vychislyat' v samoj funkcii. Funkciya dlya togo i zavedena,
	chtoby ne vychislyat' nichego KONKRETNOGO -
	vse parametry ee peremennye, i dolzhny PEREDAVATXSYA v nee
	iz tochki vyzova.

	V kachestve parametra v tochke vyzova mozhno peredavat' ne
	tol'ko znachenie peremennoj, no i znachenie vyrazheniya,
	to est' formuly.

*/
void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int LINES = 25; /* vsego strok.
			   |to opisanie peremennoj
			   srazu s ee inicializaciej
			 */
	int nline;      /* nomer stroki */

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=1; nline <= LINES; nline++)
		drawOneLine(LINES - nline,   /* chislo probelov  --> nspaces */
			    nline*2 - 1      /* chislo zvezdochek --> nstars */
			   );
}

/* Treugol'nik iz zvezdochek */
/* Teper' treugol'nik dolzhen byt' ravnobedrennym */

#include <stdio.h>

void drawOneLine(int nspaces, int nstars){
	int i;          /* nomer pechataemoj zvezdochki, schetchik */
			/* on zhe - nomer pechataemogo probela   */

	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nstars; i++)
		putchar('*');
	putchar('\n');
}

void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int LINES = 25; /* vsego strok. */
	int nline;      /* nomer stroki */

	/* Dlya cheloveka estestvenno schitat' s 1.
	   Dlya mashiny zhe pervoe chislo - eto NULX.
	   Poetomu cikl
		for(nline=1; nline <= LINES; nline++)
	   Sleduet zapisat' v vide
		for(nline=0; nline <  LINES; nline++)

	   On tozhe vypolnitsya 25 raz, no znachenie peremennoj-schetchika
		nline budet na kazhdoj iteracii na 1 men'she. Poetomu nado
		pomenyat' raschet parametrov dlya funkcii risovaniya.

			n (nomer stroki)
     ...*               0
     ..***              1
     .*****             2
     *******            3

	Vsego strok:                                    LINES
	CHislo zvezdochek v n-oj stroke:                  n*2 + 1
	CHislo probelov speredi (oboznacheny tochkoj):     LINES - n - 1

	*/

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=0; nline < LINES; nline++)
		drawOneLine(LINES - nline - 1, nline*2 + 1);
}

/*
	Tip peremennyh dlya hraneniya BUKV nazyvaetsya

		char

	(ot slova character).

	Bukvy izobrazhayutsya v odinochnyh kavychkah 'a'  'b'   '+'.

	Primer:
		char letter;

		letter = 'a';
		putchar(letter);
		letter = 'b';
		putchar(letter);
		letter = '\n';
		putchar(letter);

	Simvol '\n' oboznachaet "nevidimuyu bukvu" -
	perehod na novuyu stroku, new line.
	Est' neskol'ko takih special'nyh bukv, o nih - pozzhe.

	Zato srazu sdelaem ogovorku.
	CHtoby izobrazit' samu bukvu \
	sleduet ispol'zovat' '\\'

		putchar('\');   ili
		printf ("\");   oshibochny.

	Nado:   putchar('\\');  printf("\\");

	Delo v tom, chto simvol \ nachinaet posledovatel'nost' iz DVUH bukv,
	izobrazhayushchih ODNU bukvu, inogda vyzyvayushchuyu special'nye
	dejstviya na ekrane ili na printere.
*/

/*
	CHislo delitsya na n, esli OSTATOK ot deleniya ego na n raven 0,
	to est' esli

			(x % n) == 0

	V chastnosti, tak mozhno proveryat' chisla na chetnost'/nechetnost',
	berya x%2.

	Ostatki ot deleniya chisla x na n
	eto 0 1 2 ... n-1.
	V sluchae deleniya na 2 ostatok
		0 sootvetstvuet chetnomu   x
		1 sootvetstvuet nechetnomu x

*/

/* Zadacha:
	Narisovat' treugol'nik
	iz zvezdochek v nechetnyh strokah
	iz plyusikov  v chetnyh strokah
 *--------------------------------------------------------*

 Reshenie: ispol'zuem prezhnyuyu programmu,
 dobaviv v funkciyu drawOneLine eshche odin argument - symbol -
 kakim simvolom risovat' stroku.

 Dalee v osnovnom cikle ispol'zuem uslovnyj operator i
 proverku nomera stroki na chetnost'.

*/

#include <stdio.h>

void drawOneLine(int nspaces, int nsymbols, char symbol){
	int i;          /* schetchik */

	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nsymbols; i++)
		putchar(symbol);
	putchar('\n');
}

/* My vynesem ob®yavlenie etoj peremennoj iz funkcii,
   sdelav ee "global'noj", to est' vidimoj vo VSEH funkciyah.
 */
int LINES = 25; /* vsego strok. */

void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int nline;      /* nomer stroki */

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=0; nline <  LINES; nline++){

		if((nline % 2) == 0)    /* chetnoe ? */
			drawOneLine(LINES - nline - 1, nline*2 + 1, '+');
		else    drawOneLine(LINES - nline - 1, nline*2 + 1, '*');
	}
}

/* To zhe samoe, no teper' nuzhno eshche i pechatat' nomer stroki.
 */

#include <stdio.h>

/* Voobshche-to global'nye peremennye
   prinyato ob®yavlyat' v samom nachale fajla s programmoj.
 */

int LINES = 25; /* vsego strok. */

/* Dobavim k funkcii eshche odin argument, ukazatel' - pechatat' li
   nomer stroki. Nazovem ego drawLineNumber.
   Ne vpadite v zabluzhdenie po analogii s imenem FUNKCII drawOneLine() !
   V dannom sluchae - eto imya PEREMENNOJ - ARGUMENTA FUNKCII.

   Operator if(x) .....;
   RABOTAET TAKIM OBRAZOM (tak on ustroen):
	v kachestve usloviya on prinimaet celoe chislo (tipa int).
	Uslovie istinno, esli x != 0,
	i lozhno, esli         x == 0.

   Vtoroj dobavlennyj argument - sobstvenno nomer stroki.
*/
void drawOneLine(int nspaces,
		 int nsymbols,
		 char symbol,
			/* a eto my dobavili */
		 int drawLineNumber,
		 int linenum
){
	int i;          /* schetchik */

	if(drawLineNumber)
		printf("%d\t", linenum);  /* bez perevoda stroki */

	/* Na samom dele eto uslovie bolee polno nado zapisyvat' kak

	      if(drawLineNumber != 0)

	   no v yazyke Si eto to zhe samoe.
	*/

/* Tut my snova vidim novyj special'nyj simvol \t - TABULYACIYA.
   Ves' ekran (ili list bumagi) uslovno podelen
   na kolonki shirinoj po 8 pozicij.
   Primerno tak:
|       |       |       |       |       |       |       |       |       ...
   Simvol tabulyacii vyzyvaet perehod iz tekushchej pozicii v nachalo sleduyushchej
   kolonki. Naprimer
|       |       |       |       |       |       |       |       |       ...
		    ^ otsyuda

|       |       |       |       |       |       |       |       |       ...
			^ v eto mesto

*/
	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nsymbols; i++)
		putchar(symbol);
	putchar('\n');
}

void main(){
	/* OB¬YAVLENIE PEREMENNYH */
	int nline;      /* nomer stroki */

	/* VYPOLNYAEMYE OPERATORY (DEJSTVIYA) */
	for(nline=0; nline <  LINES; nline++){

	    if((nline % 2) == 0)    /* chetnoe ? */
		    drawOneLine(LINES - nline - 1, nline*2 + 1, '+', 1, nline);
	    else    drawOneLine(LINES - nline - 1, nline*2 + 1, '*', 9, nline);
	}

	/* A pochemu imenno 1 ili imenno 9 ?
	 * A vse chto popalo, lish' by ne 0.
	 * Mozhno 3, 333, 666, -13445, itp
	 *
	 * Vopros: chto budet, esli tut napisat' 0 ?
	 */
}

/* Sleduyushchaya zadacha budet kasat'sya togo,
   chtoby kazhdaya stroka treugol'nika pechatalas'
   v vide:
	*+*+*+*.....*+*

   Tut nam uzhe pridetsya modificirovat' funkciyu risovaniya stroki.
*/

#include <stdio.h>

int LINES = 25; /* vsego strok. */

void drawOneLine(int nspaces, int nsymbols){
	int i;

	for(i=0; i < nspaces; i++)
		putchar(' ');

	/* v cikle my budem proveryat' na chetnost' NOMER
	   pechataemogo simvola.
	 */
	for(i=0; i < nsymbols; i++){
		if((i % 2) == 0)
			putchar('*');
		else    putchar('+');
	}
	putchar('\n');
}

void main(){
	int nline;      /* nomer stroki */

	for(nline=0; nline <  LINES; nline++) {
		drawOneLine(LINES - nline - 1, nline*2 + 1);
	}
}

/* Zadacha narisovat' ROMB:
	*
       ***
      *****
       ***
	*
*/

#include <stdio.h>

int LINES = 10; /* vsego strok v polovine romba. */

void drawOneLine(int nspaces, int nsymbols){
	int i;

	for(i=0; i < nspaces; i++)
		putchar(' ');

	for(i=0; i < nsymbols; i++)
		putchar('+');
	putchar('\n');
}

void main(){
	int nline;      /* nomer stroki */

	for(nline=0; nline <  LINES; nline++)
		drawOneLine(LINES - nline - 1, nline*2 + 1);

	/* My narisovali treugol'nik.
	   Teper' nam nuzhen perevernutyj treugol'nik.
	   Pishem cikl po ubyvaniyu indeksa.
	   S dannogo mesta nomera strok otschityvayutsya v obratnom poryadke:
	   ot LINES-2 do 0
	 */

	for(nline=LINES-2; nline >= 0; nline--)
		drawOneLine(LINES - nline - 1, nline*2 + 1);
}

/* A teper' risuem romb, ispol'zuya matematicheskie formuly. */

#include <stdio.h>

void draw(int nspaces, int nstars, char symbol){
	int i;

	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nstars; i++)
		putchar(symbol);
	putchar('\n');
}

void main(){
	int LINES = 21;
	int MIDDLELINE = LINES/2 + 1;   /* seredina romba */
	int nline;

	for(nline=0; nline < MIDDLELINE; nline++)
		draw(MIDDLELINE - nline -1, nline*2+1, 'A');

	/* U sleduyushchego cikla for() net inicializacii
	   nachal'nogo znacheniya indeksa.
	   Nachal'noe nline nasleduetsya iz predydushchego cikla,
	   takim, kakim ono ostalos' posle ego okonchaniya, to est'
	   ravnym MIDDLELINE.
	 */

	for( ; nline < LINES; nline++)
		draw(nline - MIDDLELINE + 1, (LINES - 1 - nline) * 2 + 1, 'V');
}




Massiv - eto neskol'ko pronumerovannyh peremennyh,
	 ob®edinennyh obshchim imenem.
	 Vse peremennye imeyut ODIN I TOT ZHE TIP.

Rassmotrim POLKU s N yashchikami,
pust' imya polki - var.
Togda kazhzhdyj yashchik-yachejka imeet imya
	var[0]
	var[1]
	...
	var[N-1]

Numeraciya idet s NULYA.

	  --------
	 /  var  /
	/       /
	-------------------------------------------  ------------------
	|           |           |           |            |            |
	|           |           |           | ....   ... |            |
	|           |           |           |            |            |
	-------------------------------------------  ------------------
	 / var[0] /   / var[1] /   / var[2] /             / var[N-1] /
	 ---------    ---------    ---------              -----------

Massiv ob®yavlyaetsya tak:

	int var[N];

zdes' N - ego razmer, chislo yacheek.

|to opisanie kak by ob®yavlyaet N peremennyh tipa int s imenami
	var[0] ... var[N-1];

V operatorah dlya obrashcheniya k n-omu yashchichku (gde 0 <= n < N)
ispol'zuetsya imya yashchika

	var[n]

gde n - celoe znachenie (ili znachenie celoj peremennoj,
ili celochislennogo vyrazheniya), "indeks v massive".
|ta operaciya [] nazyvaetsya "indeksaciya massiva".
Indeksaciya - est' VYBOR odnogo iz N yashchikov pri pomoshchi ukazaniya celogo nomera.
	var    - massiv (N yacheek)
	n      - vyrazhenie (formula), vydayushchaya celoe znachenie v intervale 0..N-1
	var[n] - vzyat odin iz elementov massiva. Odin iz vseh.
	n      - nomer yashchika - nazyvaetsya eshche i "indeksom" etoj peremennoj v massive.

Primer:

	int var[5];                                     /* 1 */

	var[0] = 2;                                     /* 2 */
	var[1] = 3 + var[0];                            /* 3 */
	var[2] = var[0] * var[1];                       /* 4 */
	var[3] = (var[0] + 4) * var[1];                 /* 5 */

	printf("var tret'e est' %d\n", var[3]);

V hode etoj programmy elementy massiva menyayutsya takim obrazom:

	  var[0]    var[1]     var[2]     var[3]    var[4]
	  ------------------------------------------------
/* 1 */   musor     musor      musor      musor     musor
/* 2 */   2         musor      musor      musor     musor
/* 3 */   2         5          musor      musor     musor
/* 4 */   2         5          10         musor     musor
/* 5 */   2         5          10         30        musor

Kak vidim, kazhdyj operator izmenyaet lish' ODNU yachejku massiva za raz.

Massiv - nabor peremennyh, kotorye ne IMENOVANY raznymi imenami,
vrode var0, var1, var2, ...
a PRONUMEROVANY pod odnim imenem:
var[0], var[1], var[2], ...

Indeks - chast' IMENI PEREMENNOJ.

Na samom dele indeksaciya - eto
	1) vybor elementa v massive
	2) sprava ot prisvaivanij i v vyrazheniyah - eshche i razymenovanie,
	   to est' vzyatie vmesto imeni peremennoj - znacheniya, v nej hranyashchegosya.
---------------------------------------------------------------------
Esli v peremennuyu ne bylo zaneseno znachenie,
a my ispol'zuem etu peremennuyu,
to v nej lezhit MUSOR (lyuboe, nepredskazuemoe znachenie).

	printf("var4 est' %d\n", var[4]);

napechataet vse chto ugodno.

Poetomu peremennye nado vsegda inicializirovat'
(davat' im nachal'noe znachenie).

Global'nye peremennye avtomaticheski inicializiruyutsya nulem,
esli my ne zadali inache.

Lokal'nye peremennye ne inicializiruyutsya avtomaticheski, i soderzhat MUSOR.
---------------------------------------------------------------------
Massivy NELXZYA prisvaivat' celikom, yazyk Si etogo ne umeet.

	int a[5];
	int b[5];

	a = b;  /* oshibka */

Takzhe nel'zya prisvoit' znachenie srazu vsem elementam (yachejkam) massiva:

	a = 0;  /* oshibka */

ne delaet togo, chto nami ozhidalos', a yavlyaetsya oshibkoj.
Dlya obnuleniya vseh yacheek sleduet ispol'zovat' cikl:

	int i;

	for(i=0; i < 5; i++)    /* dlya kazhdogo i prisvoit' a[i] = 0; */
		a[i] = 0;

---------------------------------------------------------------------
SVYAZX MASSIVOV I CIKLOV
=======================
Vsledstvie etogo massivy prihoditsya kopirovat' (i inicializirovat')
poelementno, v cikle perebiraya vse (ili chast') yachejki massiva.

	int i;

	for(i=0; i < 5; i++)
		a[i] = b[i];

V dannom sluchae indeks cikla sluzhit takzhe i indeksom v massive.

	Indeksy v massive idut s NULYA.

Primer inicializacii:

	int index, array[5];

	for(index=0; index < 5; index++)
		array[index] = index * 2 + 1;


ili

	int index, array[5];

	index = 0;
	while(index < 5){
		array[index] = index * 2 + 1;
		index++;
	}

	/* V massive budet: { 1, 3, 5, 7, 9 } */

INDEKS
	dlya massivov -
		nomer "yashchika/yachejki" v massive.

	dlya ciklov -
		nomer povtoreniya cikla, schetchik.
		My dolzhny izmenyat' ego SAMI.

Obychno massivy i cikly sovmeshchayutsya tak:
indeks cikla est' indeks v massive;
to est' indeks cikla ispol'zuetsya dlya perebora vseh
elementov massiva:

	int a[N], i;

	for(i=0; i < N; i++)
		...a[i]...
---------------------------------------------------------------------
Primery:

	int a[5];

	a[0] = 17;
	a[0] += 4;
	a[0]++;
---------------------------------------------------------------------
Primer: chisla Fibonachchi.
Zadayutsya matematicheskimi formulami:

	f[1]   = 1
	f[2]   = 1
	f[n+2] = f[n+1] + f[n]

Vot programma:
------------------
#include <stdio.h>      /* magicheskaya stroka */
#define N 20            /* skol'ko pervyh chisel poschitat' */

void main(){
	int fibs[N], index;

	fibs[0] = 1;    /* indeksy otschityvayutsya s nulya!!! */
	fibs[1] = 1;

	/* Tut pokazano, chto indeks elementa massiva mozhet vychislyat'sya */

	for(index=2; index < N; index++)
		fibs[index] = fibs[index-1] + fibs[index-2];

	/* Raspechatka v obratnom poryadke */
	for(index = N-1; index >= 0; index--)
		printf("%d-oe chislo Fibonachchi est' %d\n",
			index+1,                   fibs[index]);
}

Zdes' my vidim novyj dlya nas operator #define
On zadaet tekstual'nuyu ZAMENU slova N na slovo 20,
v dannom sluchae prosto yavlyayas' ekvivalentom

	const int N = 20;

K neschast'yu razmer massiva ne mozhet byt' zadan pri pomoshchi peremennoj,
a vot pri pomoshchi imeni, opredelennogo v #define - mozhet.



Stroki est' massivy BUKV - tipa char,
okanchivayushchiesya specsimvolom \0

	char string[20];

	string[0] = 'P';
	string[1] = 'r';
	string[2] = 'i';
	string[3] = 'v';
	string[4] = 'e';
	string[5] = 't';
	string[6] = '\0';

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

%s - format dlya pechati STROK.
Nikakie drugie massivy ne mogut byt' napechatany
celikom odnim operatorom.

	char string[20];

	string[0] = 'P';
	string[1] = 'r';
	string[2] = 'i';
	string[3] = 'v';
	string[4] = 'e';
	string[5] = 't';
	string[6] = '\n';       /* Perevod stroki - tozhe bukva */
	string[7] = '\0';

	printf("%s", string);

ili dazhe prosto

	printf(string);

Takie massivy mozhno zapisat' v vide stroki bukv v ""

	char string[20] = "Privet\n";

Ostavshiesya neispol'zovannymi simvoly massiva ot string[8] do string[19]
soderzhat MUSOR.

POCHEMU DLYA STROK IZOBRELI SIMVOL "PRIZNAK KONCA"?
=================================================
Stroka - eto CHASTX massiva bukv.
V raznoe vremya chislo bukv v stroke mozhet byt' razlichnym,
lish' by ne prevyshalo razmer massiva (togda sluchitsya sboj programmy).
Znachit, sleduet gde-to hranit' tekushchuyu dlinu stroki (chislo ispol'zovannyh
simvolov). Est' tri resheniya:
(1)     V otdel'noj peremennoj. Ee sleduet peredavat' vo vse
	funkcii obrabotki dannoj stroki (prichem ona mozhet izmenyat'sya).

	char str[32];     /* massiv dlya stroki */
	int  slen;        /* brat' pervye slen bukv v etom massive */
	...
	func(str, &slen); /* DVA argumenta dlya peredachi ODNOJ stroki */
	...

	|tot podhod rabotosposoben, no stroka razbivaetsya na dva
	ob®ekta: sam massiv i peremennuyu dlya ego dliny. Neudobno.

(2)     Hranit' tekushchuyu dlinu v elemente str[0],
	a bukvy - v str[1] ... itd.
	Ploho tem, chto v str[0] mozhno hranit' lish' chisla ot 0 do 255,
	i esli stroka dlinnee - to takoj podhod neprimenim.

(3)     Ne hranit' dlinu NIGDE, a vvesti simvol-priznak konca stroki.
	Teper' v

	func(str);      /* ODIN argument - sam massiv */

	peredaetsya tol'ko sam massiv, a ego tekushchaya dlina mozhet byt'
	pri nuzhde vychislena pri pomoshchi nekoej funkcii, vrode takoj:

int strlen(char s[]){                   /* funkciya ot massiva bukv            */
	int counter = 0;                /* schetchik i odnovremenno indeks      */

	while(s[counter] != '\0')       /* poka ne vstretilsya priznak konca teksta */
		counter++;              /* poschitat' simvol                   */
	return counter;                 /* skol'ko simvolov, otlichnyh ot '\0' */
}

	Tut nikakih ogranichenij net. Imenno etot podhod i byl izbran
	v yazyke Si, hotya v principe mozhno samomu pol'zovat'sya i drugimi.
	Na samom dele v yazyke est' takaya STANDARTNAYA funkciya strlen(s)
	(vam ne nado pisat' ee samomu, ee uzhe napisali za vas).
---------------------------------------------------------------------
INICIALIZACIYA GLOBALXNOGO MASSIVA
=================================
Massiv, zadannyj vne kakih-libo funkcij, mozhno proinicializirovat'
konstantnymi nachal'nymi znacheniyami:

int array[5]   = { 12, 23, 34, 45, 56 };

char string[7] = { 'P', 'r', 'i', 'v', 'e', 't', '\0' };

Esli razmer massiva ukazan BOLXSHE, chem my perechislim elementov,
to ostal'nye elementy zapolnyatsya nulyami (dlya int) ili '\0' dlya char.

int array[5] = { 12, 23, 34 };

Esli my perechislim bol'she elementov, chem pozvolyaet razmer massiva -
eto budet oshibkoj.


int a[5] = { 177, 255, 133 };

Operaciya indeksacii massiva a[] daet:

pri n           znachenie vyrazheniya a[n] est'
--------------------------------------------
-1              ne opredeleno (oshibka: "indeks za granicej massiva")
0               177
1               255
2               133
3               0
4               0
5               ne opredeleno (oshibka)

KAK PROISHODIT VYZOV FUNKCII
============================

Pust' u nas opisana funkciya, vozvrashchayushchaya celoe znachenie.

	/* OPREDELENIE FUNKCII func(). */
	/* Gde func - ee imya. Nazvat' my ee mozhem kak nam ugodno. */

	int func(int a, int b, int c){
		int x, y;

		...
		x = a + 7;
		...
		b = b + 4;
		...

		return(nekoe_znachenie);
	}

Zdes'
	a, b, c    - argumenty funkcii (parametry)
	x, y       - lokal'nye peremennye

Tochka vyzova - nahoditsya vnutri kakoj-to drugoj
funkcii, naprimer funkcii main()

main(){

	int zz, var;
	...
	var = 17;
	zz = func(33, 77, var + 3) + 44;
	...
}

Kogda vypolnenie programmy dohodit do stroki

	zz = func(33, 77, var + 3) + 44;

1) Proishodit VYZOV FUNKCII func()

	(a)     |tot punkt my uvidim nizhe.

	(b)     Sozdayutsya peremennye s imenami a, b, c, x, y;

	(c)     Peremennym-argumentam prisvaivayutsya nachal'nye znacheniya,
		kotorye berutsya iz tochki vyzova.
		V tochke vyzova perechislen spisok (cherez zapyatuyu) vyrazhenij (formul):

			func(vyrazhenie1, vyrazhenie2, vyrazhenie3)

		Vychislennye znacheniya etih vyrazhenij sootvetstvenno budut prisvoeny
		1-omu, 2-omu i 3-emu argumentam (parametram) iz opredeleniya funkcii:

			int func(a, b, c){      /* a = nomer 1, b = 2, c = 3 */

		Pervyj parametr:

			a = 33;

		Vtoroj parametr:

			b = 77;

		Tretij parametr:

			c = var + 3;

		to est', vychislyaya,

			c = 20;

		Lokal'nye peremennye x i y soderzhat neopredelennye znacheniya,
		to est' musor (my ne mozhem predskazat' ih znacheniya,
		poka ne prisvoim im yavnym obrazom kakoe-libo znachenie sami).

2) Vypolnyaetsya TELO funkcii, to est' vychisleniya, zapisannye vnutri { ... }
   v opredelenii funkcii. Naprimer:

			x = a + 7;

	I parametry, i lokal'nye peremennye - eto PEREMENNYE,
	to est' ih mozhno izmenyat'.

			b = b + 4;

	Pri etom nikakie peremennye VNE etoj funkcii ne izmenyayutsya.
	(Ob etom eshche raz pozzhe).


3) Proizvoditsya VOZVRAT iz funkcii.

		...
		return(nekoe_znachenie);
	}


	Naprimer, eto mozhet byt'

		...
		return(a + 2 * x);
	}

	Rassmotrim, chto pri etom proishodit v tochke vyzova:

		zz = func(33, 77, var + 3) + 44;

	(1) Vycherkivaem func(.....)

		zz = XXXXXXX + 44;

	(2) Vychislyaem znachenie "nekoe_znachenie" v operatore return,
	    i berem KOPIYU etogo znacheniya.
	    Pust' pri vychislenii tam poluchilos' 128.

	(3) Podstavlyaem eto znachenie na mesto vycherknutogo func(.....)
	    U nas poluchaetsya

		zz = 128 + 44;

	(4) AVTOMATICHESKI UNICHTOZHAYUTSYA lokal'nye peremennye i argumenty funkcii:

		a       - ubito
		b       - ubito
		c       - ubito
		x       - ubito
		y       - ubito

	Takih peremennyh (i ih znachenij) bol'she net v prirode.

	(5) Punkt, kotoryj my obsudim pozzhe.

	(6) Prodolzhaem vychislenie:

		zz = 128 + 44;

	Vychislyaetsya v

		zz = 172;       /* operator prisvaivaniya */

-------------------------------------------------------------------------

int func1(int x){
	printf("func1: x=%d\n", x);     /* 1 */
	x = 77;
	printf("func1: x=%d\n", x);     /* 2 */
	return x;
}

void main(){
	int var, y;

	var = 111;
	y = func1(var);                 /* @ */

	printf("main: var=%d\n", var);  /* 3 */
}

V dannom sluchae v tochke @ my peredaem v funkciyu func1()
ZNACHENIE peremennoj var, ravnoe 111.
|to znachit, chto pri vyzove funkcii budet sozdana peremennaya x
i ej budet prisvoeno nachal'noe znachenie 111

	x = 111;

Poetomu pervyj operator printf() napechataet 111.

Zatem my izmenyaem znachenie peremennoj x na 77.
My menyaem peremennuyu x, no ne peremennuyu var !!!
Ispol'zovav ZNACHENIE (ego kopiyu) iz peremennoj var dlya x,
my o peremennoj var zabyli - ona nas ne kasaetsya (a my - ee).

Poetomu vtoroj operator printf() napechataet 77.
V peremennoj zhe var ostalos' znachenie 111,
chto i podtverdit nam tretij operator printf,
kotoryj napechataet 111.

-------------------------------------------------------------------------
VREMENNOE SOKRYTIE PEREMENNYH
=============================

int func1(int x){                       /* f.1 */
	printf("func1: x=%d\n", x);     /* f.2 */
	x = 77;                         /* f.3 */
	printf("func1: x=%d\n", x);     /* f.4 */
	return x;                       /* f.5 */
}

void main(){
	int x, y;                       /* 1 */

	x = 111;                        /* 2 */
	y = func1(x);                   /* 3 */

	printf("main: x=%d y=%d\n", x, y);  /* 4 */
}

A teper' my i peremennuyu vnutri main(), i argument funkcii
func1() nazvali odnim i tem zhe imenem. CHto budet?

Budet to zhe samoe, chto v predydushchem primere.

V moment vyzova funkcii func1() budet sozdana NOVAYA peremennaya
s imenem x, a staraya (prezhnyaya) peremennaya i ee znachenie budut
VREMENNO SPRYATANY (skryty).

Mozhno bylo by utochnit' eti peremennye imenami funkcij,
v kotoryh oni opredeleny:

	main::x

	   i

	func1::x

(no eto uzhe konstrukcii iz yazyka Si++, a ne Si).

Vypolnim programmu po operatoram:

|/* 1    */      Otvodyatsya peremennye main::x i main::y dlya celyh chisel;
|/* 2    */      main::x = 111;
|/* 3    */      Vyzyvaetsya func1(111);
|
+-------+
.       |/* f.1  */      Otvoditsya peremennaya func1::x so znacheniem 111;
.       |/* f.2  */      Pechataetsya 111 iz peremennoj func1::x;
.       |
.       |/* f.3  */      func1::x = 77; (eto ne main::x, a drugaya peremennaya,
.       |                                LOKALXNAYA dlya funkcii func1.
.       |                                Peremennuyu main::x my sejchas ne vidim -
.       |                                ona "zaslonena" imenem nashej lokal'noj
.       |                                peremennoj.
.       |                                Poetomu my ne mozhem ee izmenit').
.       |
.       |/* f.4  */      Pechataet 77 iz func1::x;
.       |/* f.5  */      Vozvrashchaet znachenie func1::x , to est' 77.
.       |                Peremennaya func1::x unichtozhaetsya.
.       |
.       |                Teper' my snova vozvrashchaemsya v funkciyu main(),
.       |                gde imya x oboznachaet peremennuyu main::x
.       |                a ne func1::x
+-------+
|
|/* 3    */      y = 77;
|/* 4    */      Pechataet znacheniya main::x i main::y, to est'
|                111 i 77.


|tot mehanizm sokrytiya imen pozvolyaet pisat' funkcii main() i func1()
raznym programmistam, pozvolyaya im NE ZABOTITXSYA o tom, chtoby imena
lokal'nyh peremennyh v funkciyah NE SOVPADALI. Pust' sovpadayut - huzhe ne
budet, mehanizm upryatyvaniya imen razreshit konflikt.
Zato programmist mozhet ispol'zovat' lyuboe ponravivsheesya emu imya
v lyuboj funkcii - hotya by i x, ili i.

-------------------------------------------------------------------------
To zhe samoe proishodit s lokal'nymi peremennymi,
a ne s argumentami funkcii.

int func1(int arg){     /* lokal'naya peremennaya-parametr func1::arg */
	int x;          /* lokal'naya peremennaya          func1::x   */

	x = arg;
	printf("func1: x=%d\n", x);
	x = 77;
	printf("func1: x=%d\n", x);
	return x;
}

void main(){
	int x, y;       /* peremennye main::x i main::y */

	x = 111;
	y = func1(x);

	printf("main: x=%d y=%d\n", x, y);
}

Dejstvuet tot zhe samyj mehanizm vremennogo sokrytiya imeni x.
Voobshche zhe, argumenty funkcii i ee lokal'nye peremennye
otlichayutsya tol'ko odnim:
	argumentam avtomaticheski prisvaivayutsya
	nachal'nye znacheniya, ravnye znacheniyam sootvetstvuyushchih vyrazhenij
	v spiske

		imya_funkcii(..., ..., ....)
			    arg1 arg2 arg3

	v meste vyzova funkcii.

To est'

OPISANIE FUNKCII:

int f(int arg1, int arg2, int arg3){
	int perem1, perem2;
	...
	/* prodolzhenie */
}

VYZOV:

	.... f(vyrazhenie1, vyrazhenie2, vyrazhenie3) ...

TO V TELE FUNKCII VYPOLNITSYA (v moment ee vyzova):

	arg1 = vyrazhenie1;
	arg2 = vyrazhenie2;
	arg3 = vyrazhenie3;

	perem1 = MUSOR;
	perem2 = MUSOR;

	...
	/* prodolzhenie */

-------------------------------------------------------------------------
GLOBALXNYE PEREMENNYE
=====================

Nakonec, sushchestvuyut peremennye, kotorye ob®yavlyayutsya VNE VSEH FUNKCIJ,
i sushchestvuyushchie vse vremya vypolneniya programmy
(a ne tol'ko to vremya, kogda aktivna funkciya, v kotoroj oni sozdany).

Lokal'nye peremennye i argumenty UNICHTOZHAYUTSYA pri vyhode
iz funkcii. Global'nye peremennye - net.

int x = 12;             /* ::x - ej mozhno zaranee prisvoit' konstantu */
int globvar;            /* ::globvar                                  */

int f1(){
	int x;          /* f1::x */

	x = 77;
	printf("x=%d\n", x);            /* 4 */
	return x;
}

int f2(){
	printf("x=%d\n", x);            /* 5 */
	return 0;
}

void main(){
	int x, y;       /* main::x */

	x = 111;                         /* 1 */
	printf("x=%d\n", x);             /* 2 */
	printf("glob=%d\n", globvar);    /* 3 */

	y = f1();
	y = f2();
}

V dannom primere my vidim:
- vo-pervyh my vidim FUNKCII BEZ PARAMETROV. |to normal'naya situaciya.
- vo-vtoryh tut ispol'zuyutsya TRI peremennye s imenem "x".

Kak vypolnyaetsya programma?

/* 1 */   main::x = 111;
	  |to lokal'nyj x, a ne global'nyj.
	  Global'nyj x poprezhnemu soderzhit 12.

/* 2 */   Napechataet znachenie peremennoj main::x, to est' 111.
	  Vnutri funkcii main global'naya peremennaya ::x
	  zaslonena svoej sobstvennoj peremennoj x.
	  V dannom sluchae NET SPOSOBA dobrat'sya iz main k global'noj
	  peremennoj x, eto vozmozhno tol'ko v yazyke Si++ po imeni ::x

	  K peremennoj zhe globvar u nas dostup est'.

/* 3 */   Pechataet ::globvar. My obnaruzhivaem, chto ee znachenie 0.
	  V otlichie ot global'nyh peremennyh,
	  kotorye iznachal'no soderzhat MUSOR,
	  global'nye peremennye iznachal'no soderzhat znachenie 0.

	  V ramochku, podcherknut'.

/* 4 */   Pri vyzove f1()
	  peremennaya f1::x
		zaslonyaet soboj kak
		     main::x
		tak i
		     ::x

	  V dannom sluchae napechataetsya 77,
	  no ni ::x ni main::x ne budut izmeneny operatorom x = 77.
	  |to izmenyalas' f1::x

/* 5 */   Pri vyzove f2() istoriya interesnee.
	  Tut net svoej sobstvennoj peremennoj x.
	  No kakaya peremennaya pechataetsya tut -
		::x     ili
		main::x   ?

	  Otvet: ::x
		 to est' 12.

	  Peremennye nazvany lokal'nymi eshche i potomu,
	  chto oni NEVIDIMY V VYZYVAEMYH FUNKCIYAH.

	  |to OPREDELENIE lokal'nyh peremennyh.
	  (Poetomu ne sprashivajte "pochemu?" Po opredeleniyu)

	  To est', esli my imeem

		funca(){
			int vara;
			...
			...funcb();...  /* vyzov */
			...
		}

	  to iz funkcii funcb() my NE IMEEM DOSTUPA K PEREMENNOJ vara.

		funcb(){
			int z;

			z = vara + 1;   /* oshibka,
					   vara neizvestna vnutri funcb() */
		}

	  Esli, v svoyu ochered', funcb() vyzyvaet funcc(),
	  to i iz funcc() peremennaya vara nevidima.

	  Ostanovites' i osoznajte.
	  |to pravilo sluzhit vse toj zhe celi - raznye funkcii
	  mogut byt' napisany raznymi programmistami, kotorye mogut
	  ispol'zovat' odni i te zhe imena dlya RAZNYH peremennyh,
	  ne boyas' ih vzaimoperesecheniya.
	  Mnozhestva imen, ispol'zovannyh v raznyh funkciyah, nezavisimy
	  drug ot druga. Imena iz odnoj funkcii NIKAK ne otnosyatsya
	  k peremennym s temi zhe imenami IZ DRUGOJ funkcii.

	  Vernemsya k paragrafu KAK PROISHODIT VYZOV FUNKCII
	  i rassmotrim punkt (a). Teper' on mozhet byt' opisan kak

	(a) Lokal'nye peremennye i argumenty vyzyvayushchej funkcii delayutsya nevidimymi.
					     ~~~~~~~~~~
	  A pri vozvrate iz funkcii:

	(5) Lokal'nye peremennye i argumenty vyzyvayushchej funkcii snova delayutsya vidimymi.

	  ODNAKO global'nye peremennye vidimy iz LYUBOJ funkcii,
	  isklyuchaya sluchaj, kogda global'naya peremennaya zaslonena
	  odnoimennoj lokal'noj peremennoj dannoj funkcii.

-------------------------------------------------------------------------
PROCEDURY
=========
Byvayut funkcii, kotorye ne vozvrashchayut nikakogo znacheniya.
Takie funkcii oboznachayutsya void ("pustyshka").
Takie funkcii nazyvayut eshche PROCEDURAMI.

	void func(){
		printf("Privetik!\n");
		return;  /* vernut'sya v vyzyvayushchuyu funkciyu */
	}

Takie funkcii vyzyvayutsya radi "pobochnyh effektov",
naprimer pechati strochki na ekran ili izmeneniya global'nyh (i tol'ko)
peremennyh.

	int glob;

	void func(int a){
		glob += a;
	}

Operator return tut neobyazatelen, on avtomaticheski vypolnyaetsya
pered poslednej skobkoj }

Vyzov takih funkcij ne mozhet byt' ispol'zovan
v operatore prisvaivaniya:

main(){
	int z;

	z = func(7);     /* oshibka, a chto my prisvaivaem ??? */
}

Korrektnyj vyzov takov:

main(){
	func(7);
}

Prosto vyzov i vse.



CHtoby vyzyvat' ih s raznymi argumentami!

	int res1, res2;
		...

	res1 = func(12 * x * x + 177, 865,     'x');
	res2 = func(432 * y + x, 123 * y - 12, 'z');

Kstati, vy zametili, chto spisok fakticheskih parametrov
sleduet cherez zapyatuyu;
i vyrazhenij rovno stol'ko, skol'ko parametrov u funkcii?

Funkciya opisyvaet POSLEDOVATEXNOSTX DEJSTVIJ,
kotoruyu mozhno vypolnit' mnogo raz,
no s raznymi ishodnymi dannymi (argumentami).
V zavisimosti ot dannyh ona budet vydavat' raznye rezul'taty,
no vypolnyaya odni i te zhe dejstviya.

V tom to i sostoit ee prelest':
my ne dubliruem odin kusok programmy mnogo raz,
a prosto "vyzyvaem" ego.

Funkciya - abstrakciya ALGORITMA, to est' posledovatel'nosti dejstvij.
Ee konkretizaciya - vyzov funkcii s uzhe opredelennymi parametrami.
-------------------------------------------------------------------------
Operator return mozhet nahodit'sya ne tol'ko v konce funkcii,
no i v ee seredine.
On vyzyvaet nemedlennoe prekrashchenie tela funkcii i vozvrat znacheniya
v tochku vyzova.

	int f(int x){
		int y;

		y = x + 4;
		if(y > 10) return (x - 1);
		y *= 2;
		return (x + y);
	}



Rekursivnoj nazyvaetsya funkciya, vyzyvayushchaya sama sebya.

	int factorial(int arg){
		if(arg == 1)
			return 1;                               /* a */
		else
			return arg * factorial(arg - 1);        /* b */
	}

|ta funkciya pri vyzove factorial(n) vychislit proizvedenie

	n * (n-1) * ... * 3 * 2 * 1

nazyvaemoe "faktorial chisla n".
V dannoj funkcii peremennaya arg budet otvedena (a posle i unichtozhena) MNOGO RAZ.

Tak chto peremennaya factorial::arg dolzhna poluchit' eshche i NOMER vyzova funkcii:

	factorial::arg[uroven'_vyzova]

I na kazhdom novom urovne novaya peremennaya skryvaet vse predydushchie.
Tak dlya factorial(4) budet


		+----------------------------------------+
     |          | factorial::arg[ 0_oj_raz ]  est' 4     |
     |          | factorial::arg[ 1_yj_raz ]  est' 3     |
     |          | factorial::arg[ 2_oj_raz ]  est' 2     |
     |          | factorial::arg[ 3_ij_raz ]  est' 1     |
     V  --------+                                        +---------

Zatem pojdut vozvraty iz funkcij:

		+----------------------------------------+
     A          | /* b */ return 4 * 6 = 24              |
     |          | /* b */ return 3 * 2 = 6               |
     |          | /* b */ return 2 * 1 = 2               |
     |          | /* a */ return 1;                      |
     |  --------+                                        +---------

Takaya konstrukciya nazyvaetsya STEK (stack).

	--------+               +------------
		|               |                       pustoj stek
		+---------------+

	Polozhim v stek znachenie a
			|
	--------+       |       +------------
		|       V       |
		+---------------+
		|       a       | <--- vershina steka
		+---------------+

	Polozhim v stek znachenie b

	--------+               +------------
		|               |
		+---------------+
		|       b       | <--- vershina steka
		+---------------+
		|       a       |
		+---------------+

	Polozhim v stek znachenie c

	--------+               +------------
		|               |
		+---------------+
		|       c       | <--- vershina steka
		+---------------+
		|       b       |
		+---------------+
		|       a       |
		+---------------+

	Analogichno, znacheniya "snimayutsya so steka" v obratnom poryadke: c, b, a.

	V kazhdyj moment vremeni u steka dostupno dlya chteniya (kopirovaniya) ili
	vybrasyvaniya tol'ko dannoe, nahodyashcheesya na VERSHINE steka.

	Tak i v nashej rekursivnoj funkcii peremennaya factorial::arg
	vedet sebya imenno kak stek (etot yashchik-stek imeet imya arg) -
	ona imeet ODNO imya, no raznye znacheniya v raznyh sluchayah.
	Peremennye, kotorye AVTOMATICHESKI vedut sebya kak stek,
	vstrechayutsya tol'ko v (rekursivnyh) funkciyah.

	Stek - eto chasto vstrechayushchayasya v programmirovanii konstrukciya.
	Esli podobnoe povedenie nuzhno programmistu, on dolzhen promodelirovat'
	stek pri pomoshchi massiva:

	int stack[10];
	int in_stack = 0;       /* skol'ko elementov v steke */

	/* Zanesenie znacheniya v stek */
	void push(int x){
		stack[in_stack] = x;
		in_stack++;
	}

	/* Snyat' znachenie so steka */
	int pop(){
		if(in_stack == 0){
			printf("Stek pust, oshibka.\n");
			return (-1);
		}
		in_stack--;
		return stack[in_stack];
	}

	Obratite v nimanie, chto net nuzhdy STIRATX (naprimer obnulyat')
	znacheniya elementov massiva, vykinutyh s vershiny steka.
	Oni prosto bol'she ne ispol'zuyutsya, libo zatirayutsya novym znacheniem pri
	pomeshchenii na stek novogo znacheniya.

	void main(){
		push(1);
		push(2);
		push(3);

		while(in_stack > 0){
			printf("top=%d\n", pop());
		}
	}



Budem rassmatrivat' kazhdyj VYZOV funkcii kak pomeshchenie v special'nyj stek
bol'shogo "bloka informacii", vklyuchayushchego v chastnosti
ARGUMENTY I LOKALXNYE PEREMENNYE vyzyvaemoj funkcii.

Operator return iz vyzvannoj funkcii vytalkivaet so steka VESX takoj blok.

V kachestve primera rassmotrim takuyu programmu:

int x = 7;      /* global'naya */
int v = 333;    /* global'naya */

int factorial(int n){
	int w;  /* lishnyaya peremennaya, tol'ko dlya demonstracionnyh celej */

	w = n;

	if(n == 1)      return 1;                       /* #a */
	else            return n * factorial(n-1);      /* #b */
}
void func(){
	int x;          /* func::x */

	x = 777;        /* #c */
	printf("Vyzvana funkciya func()\n");
}
void main(){
	int y = 12;     /* main::y */
	int z;

				/* A */
	z = factorial(3);       /* B */
	printf("z=%d\n", z);

	func();                 /* C */
}
-------------------------------------------------------------------------
Vypolnenie programmy nachnetsya s vyzova funkcii main().
V tochke /* A */

				|    v  z  g  l  ya  d   |
				V                       V

	--------+                       +--------
		|=======================|
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


V kazhdyj dannyj moment vidimy peremennye, kotorye nahodyatsya
a) na vershine (i tol'ko) steka vyzovov funkcij.
b) i nezaslonennye imi global'nye peremennye.
V dannom sluchae my smotrim "sverhu" i vidim:

	main::z,  main::y,  ::x,  ::v

-------------------------------------------------------------------------
V tochke /* B */ my vyzyvaem factorial(3).


	--------+                       +--------
		|=======================|
		|       w = musor       |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE

Pri novom vzglyade vidimy:
	factorial(3)::w,  factorial(3)::n,  ::x,  ::v

Stali nevidimy:
	main::z,  main::y

Stroka "tekushchij operator ..." ukazyvaet mesto, s kotorogo nado vozobnovit'
vypolnenie funkcii, kogda my vernemsya v nee.
-------------------------------------------------------------------------
Kogda vypolnenie programmy v funkcii factorial(3) dojdet do tochki
/* #b */ budet vypolnyat'sya return 3 * factorial(2).
V itoge budet vyzvana funkciya factorial(2).

	--------+                       +--------
		|=======================|
		|       w = musor       |
		|       n = 2           |
		|factorial(2)           |
		|=======================|
		|                     +-|---> tekushchij operator return 3 * factorial(2);
		|       w = 3           |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


-------------------------------------------------------------------------
Kogda vypolnenie programmy v funkcii factorial(2) dojdet do tochki
/* #b */ budet vypolnyat'sya return 2 * factorial(1).
V itoge budet vyzvana funkciya factorial(1).

	--------+                       +--------
		|=======================|
		|       w = musor       |
		|       n = 1           |
		|factorial(1)           |
		|=======================|
		|                     +-|---> tekushchij operator return 2 * factorial(1);
		|       w = 2           |
		|       n = 2           |
		|factorial(2)           |
		|=======================|
		|                     +-|---> tekushchij operator return 3 * factorial(2);
		|       w = 3           |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE

-------------------------------------------------------------------------
Zatem v factorial(1) vypolnenie programmy dojdet do tochki /* #a */
i budet proizvodit'sya return 1.

Pri return vycherkivaetsya ODIN blok informacii so steka vyzovov funkcij,
i vozobnovlyaetsya vypolnenie "tekushchego operatora" v funkcii,
stavshej NOVOJ vershinoj steka vyzovov.
Zamet'te, chto v dannoj situacii vyzvannye funkcii factorial(m) eshche ne zavershilis'.
V nih eshche ESTX chto sdelat': vychislit' vyrazhenie v return,
i sobstvenno vypolnit' sam return. Vychisleniya budut prodolzheny.

	--------+                       +--------
		|=======================|
		|                     +-|---> tekushchij operator return 1;
		|       w = 1           |
		|       n = 1           |
		|factorial(1)           |
		|=======================|
		|                     +-|---> tekushchij operator return 2 * factorial(1);
		|       w = 2           |
		|       n = 2           |
		|factorial(2)           |
		|=======================|
		|                     +-|---> tekushchij operator return 3 * factorial(2);
		|       w = 3           |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE

-------------------------------------------------------------------------
Nachinaetsya vytalkivanie funkcij so steka i vypolnenie operatorov return;

	--------+                       +--------
		|=======================|
		|                     +-|---> tekushchij operator return 2 * 1;
		|       w = 2           |
		|       n = 2           |
		|factorial(2)           |
		|=======================|
		|                     +-|---> tekushchij operator return 3 * factorial(2);
		|       w = 3           |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


	--------+                       +--------
		|=======================|
		|                     +-|---> tekushchij operator return 3 * 2;
		|       w = 3           |
		|       n = 3           |
		|factorial(3)           |
		|=======================|
		|                     +-|---> tekushchij operator z = factorial(3);
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


	--------+                       +--------
		|=======================|
		|                     +-|---> tekushchij operator z = 6;
		|       z = musor       |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


	--------+                       +--------
		|=======================|
		|       z = 6           |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE

-------------------------------------------------------------------------
Nakonec, v tochke /* C */ budet vyzvana funkciya func().
Rassmotrim tochku /* #c */ v nej.

	--------+                       +--------
		|=======================|
		|       x = 777;        |
		|func();                |
		|=======================|
		|                     +-|---> tekushchij operator func();
		|       z = 6           |
		|       y = 12          |           +------+---------+
		|main()                 |           |x = 7 | v = 333 |
		+-----------------------+-----------+------+---------+-----
		 STEK VYZOVOV FUNKCIJ                GLOBALXNYE PEREMENNYE


V dannom meste nas interesuet - kakie peremennye vidimy?
Vidimy:
		func::x = 777
		::v     = 333

I vse.
		::x                zaslonen lokal'noj peremennoj.
		main::y,  main::z  nevidimy, tak kak nahodyatsya
				   ne na vershine steka vyzovov funkcij
-------------------------------------------------------------------------
Mnogie funkcii bolee estestvenno vyrazhayutsya cherez rekursiyu.
Hotya, chasto eto privodit k izlishnim vychisleniyam po sravneniyu s iteraciyami
(to est' ciklami). Vot primer - chisla Fibonachchi.

int fibonacci(int n){
	if(n==1 || n==2) return 1;

	/* else */

	return fibonacci(n-1) + fibonacci(n-2);
}
void main(){
	printf("20oe chislo Fibonachchi ravno %d\n", fibonacci(20));
}

Poskol'ku tut otsutstvuet massiv dlya zapominaniya promezhutochnyh
rezul'tatov, to etot massiv na samom dele neyavno modeliruetsya
v vide lokal'nyh peremennyh vnutri steka vyzovov funkcij.
Odnako etot sposob ploh - v nem slishkom mnogo povtoryayushchihsya
dejstvij. Dobavim operator pechati - i poschitaem, skol'ko raz
byla vyzvana fibonacci(1) ?

int called = 0;

int fibonacci(int n){
	if(n==1){
		called++;
		return 1;

	} else  if(n==2)
		return 1;

	return fibonacci(n-1) + fibonacci(n-2);
}
void main(){
	printf("20oe chislo Fibonachchi ravno %d\n", fibonacci(20));
	printf("fibonacci(1) byla vyzvana %d raz\n", called);
}

Ona byla vyzvana... 2584 raza!

/* Risuem hitruyu geometricheskuyu figuru */
#include <stdio.h>

const int LINES = 15;

void draw(int nspaces, int nstars, char symbol){
	int i;

	for(i=0; i < nspaces; i++)
		putchar(' ');
	for(i=0; i < nstars; i++)
		putchar(symbol);
}

void main(){
	int nline, nsym;
	char symbols[3];        /* Massiv iz treh bukv */

	symbols[0] = '\\';
	symbols[1] = 'o';
	symbols[2] = '*';

	for(nline=0; nline < LINES; nline++){
		for(nsym = 0; nsym < 3; nsym++)
			draw(nline, nline, symbols[nsym]);

		/* Perehod na novuyu stroku vynesen
		   iz funkcii v glavnyj cikl */
		putchar('\n');
	}
}

/* Zadacha:
	narisovat' tablicu vida

	kot     kot     kot     koshka   koshka   kot
	kot     kot     koshka   koshka   kot     ...

   Gde idet posledovatel'nost'
	kot, kot, kot, koshka, koshka...
   povtoryayushchayasya mnogo raz i raspolagaemaya po 6 zverej v stroku.
*/

#include <stdio.h>      /* magicheskaya stroka */

/* Ob®yavlenie global'nyh peremennyh.
   V dannom sluchae - konstant.
 */

int TOMCATS     = 3;            /* tri kota  */
int CATS        = 2;            /* dve koshki */
int ANIMALS_PER_LINE    = 6;    /* shest' zverej v kazhdoj stroke */
int LINES       = 25;           /* chislo vyvodimyh strok */

/* i nam ponadobitsya eshche odna peremennaya - obshchee chislo zverej.
   Ee my vychislim cherez uzhe zadannye, poetomu tut my ee ob®yavim...
   no vychislit' chto-libo mozhno tol'ko vnutri funkcii.
   V nashem sluchae - v funkcii main().
*/
int ANIMALS;                    /* obshchee chislo zverej */

int nth_in_line = 0;            /* nomer zverya v tekushchej stroke */
/* |ta peremennaya ne mozhet byt' lokal'noj v funkcii, tak kak
 * togda ona unichtozhitsya pri vyhode iz funkcii. Nam zhe neobhodimo,
 * chtoby ee znachenie sohranyalos'. Poetomu peremennaya - global'naya.
 */

/* Funkciya, kotoraya schitaet chislo zverej v odnoj stroke
   i libo perevodit stroku, libo perevodit pechat' v
   sleduyushchuyu kolonku (tabulyaciej).
*/
void checkIfWeHaveToBreakLine(){
	nth_in_line++;  /* tekushchij nomer zverya v stroke (s edinicy) */

	if(nth_in_line == ANIMALS_PER_LINE){
	/* Esli stroka zapolnena zver'mi... */
		putchar('\n');     /* novaya stroka */
		nth_in_line = 0;   /* v novoj stroke net zverej */
	} else {
		putchar('\t');     /* v sleduyushchuyu kolonku */
	}
}

void main(){
	int nanimal;    /* nomer zverya */
	int i;          /* schetchik     */

	ANIMALS = ANIMALS_PER_LINE * LINES;
	nanimal = 0;

	while(nanimal < ANIMALS){

		for(i=0; i < TOMCATS; i++){
			/* Operator printf() vyvodit STROKU SIMVOLOV.
			   STROKA zaklyuchaetsya v dvojnye kavychki
			   (ne putat' s odinochnymi dlya putchar().
			 */
			printf("kot");
			nanimal++;      /* poschitat' eshche odnogo zverya */

			/* i proverit' - ne nado li perejti na novuyu stroku ? */
			checkIfWeHaveToBreakLine();
		}
		for(i=0; i < CATS; i++){
			printf("koshka");
			nanimal++;      /* poschitat' eshche odnogo zverya */

			/* i proverit' - ne nado li perejti na novuyu stroku ? */
			checkIfWeHaveToBreakLine();
		}
	}
	/* putchar('\n'); */
}

/*
	Ta zhe zadacha, no eshche nado pechatat' nomer kazhdogo zverya.
	Ogranichimsya pyat'yu strokami.
*/

#include <stdio.h>      /* magicheskaya stroka */

int TOMCATS     = 3;            /* tri kota  */
int CATS        = 2;            /* dve koshki */
int ANIMALS_PER_LINE    = 6;    /* shest' zverej v kazhdoj stroke */
int LINES       = 5;            /* chislo vyvodimyh strok */
int ANIMALS;                    /* obshchee chislo zverej */

int nth_in_line = 0;            /* nomer zverya v tekushchej stroke */

void checkIfWeHaveToBreakLine(){
	nth_in_line++;

	if(nth_in_line == ANIMALS_PER_LINE){
		putchar('\n');
		nth_in_line = 0;
	} else
		printf("\t\t");         /* @ */

	/* Odinokij operator mozhet obojtis' bez {...} vokrug nego */
}

void main(){
	int nanimal;
	int i;

	ANIMALS = ANIMALS_PER_LINE * LINES;
	nanimal = 0;

	while(nanimal < ANIMALS){

		for(i=0; i < TOMCATS; i++){
		/* Format %d vyvodit znachenie peremennoj tipa int
		   v vide tekstovoj stroki.
		   Sama peremennaya dolzhna byt' v spiske posle formata
		   (spisok - eto perechislenie peremennyh cherez zapyatuyu).
		   Peremennyh ILI vyrazhenij (formul).

		   Davajte vyvodit' po DVE tabulyacii --
		   eto mesto otmecheno v funkcii checkIfWeHaveToBreakLine()
		   kak @.

		   Eshche raz vnimanie - odin simvol my vyvodim kak
			putchar('a');
		   Neskol'ko simvolov - kak
			printf("abcdef");

		   Odinochnye kavychki - dlya odnoj bukvy.
		   Dvojnye kavychki   - dlya neskol'kih.
		*/

			printf("kot%d", nanimal);
			nanimal++;

			checkIfWeHaveToBreakLine();
		}
		for(i=0; i < CATS; i++){
			printf("koshka%d", nanimal);
			nanimal++;

			checkIfWeHaveToBreakLine();
		}
	}
}

/* Zadacha: napechatat' korni iz chisel ot 1 do 100.

   Novaya informaciya:
	Nam ponadobitsya novyj tip dannyh - DEJSTVITELXNYE CHISLA.
	|to chisla, imeyushchie drobnuyu chast' (posle tochki).
	Kak my uzhe znaem, celye - eto   int.
			  bukva - eto   char.
			  dejstvitel'noe chislo - eto double.
	(est' eshche slovo float, no im pol'zovat'sya ne rekomenduetsya).

   Dlya vychisleniya kornya ispol'zuetsya iteracionnyj algoritm Gerona.

		q = koren' iz x;

		q[0]   := x;
		q[n+1] := 1/2 * ( q[n] + x/q[n] );

   Glavnoe tut ne vpast' v oshibku, ne klyunut' na q[n] i ne
   zavesti massiv. Nam ne nuzhny rezul'taty kazhdoj iteracii,
   nam nuzhen tol'ko konechnyj otvet. Poetomu nam budet vpolne
   dostatochno ODNOJ, no izmenyayushchejsya v cikle, yachejki q.
*/

#include <stdio.h>

/* Eshche odno novoe klyuchevoe slovo - const. Oboznachaet konstanty.
   V otlichie ot peremennyh, takie imena nel'zya izmenyat'.
   To est', esli gde-to potom poprobovat' napisat' epsilon = ... ;
   to eto budet oshibkoj.
 */
const double epsilon = 0.0000001;       /* tochnost' vychislenij */

/* Funkciya vychisleniya modulya chisla */
double doubleabs(double x){
	if(x < 0) return -x;
	else      return x;
}

/* Funkciya vychisleniya kvadratnogo kornya */
double sqrt(double x){

	double sq = x;

	/* Takaya konstrukciya est' prosto sklejka dvuh strok:
		double sq;
		sq = x;
	   Nazyvaetsya eto "ob®yavlenie peremennoj s inicializaciej".
	 */

	while(doubleabs(sq*sq - x) >= epsilon){
		sq = 0.5 * (sq + x/sq);
	}
	return sq;
}

void main() {
	int n;

	for(n=1; n <= 100; n++)
		printf("sqrt(%d)=%lf\n",
			     n,  sqrt((double) n)
		      );

}

/*
   Zdes' v operatore printf() my pechataem DVA vyrazheniya.
	FORMAT          ZNACHENIE
	------          --------
	%d      --      n
	%lf     --      sqrt((double) n)

	Po formatu %d pechatayutsya znacheniya tipa int.
	Po formatu %c pechatayutsya znacheniya tipa char.
	Po formatu %lf (ili %g) pechatayutsya znacheniya tipa double.

   CHto znachit "napechatat' znachenie vyrazheniya sqrt(xxx)" ?
   |to znachit:
	- vyzvat' funkciyu sqrt() s argumentom, ravnym xxx;
	- vychislit' ee;
	- vozvrashchennoe eyu znachenie napechatat' po formatu %lf,
	  to est' kak dejstvitel'noe chislo.

   Zamet'te, chto tut vozvrashchaemoe znachenie NE prisvaivaetsya
   nikakoj peremennoj, my ne sobiraemsya ego hranit'.

   Tochno tak zhe, kak v operatore x = 12 + 34;
   12 i 34 ne hranyatsya ni v kakih peremennyh,
   a operator

	printf("%d\n", 12);

   pechataet CHISLO 12, a ne peremennuyu.

   Tochno tak zhe, kak mozhno pisat'

	double z;

	z = sqrt(12) + sqrt(23);

   gde znachenie, vychislennoe kazhdoj funkciej, NE hranitsya
   v svoej sobstvennoj peremennoj (takaya peremennaya na samom
   dele sushchestvuet v komp'yutere, no programmistu ona ne
   nuzhna i nedostupna).
   Ili

	z = sqrt( sqrt(81));

	(koren' iz kornya iz 81 --> dast 3)

   Dalee, chto oznachaet konstrukciya (double) n   ?
   Funkciya sqrt() trebuet argumenta tipa double.
   My zhe predlagaem ej celyj argument

	int n;

   Celye i dejstvitel'nye chisla predstavleny v pamyati
   mashiny PO-RAZNOMU,
   poetomu chisla

	12   i   12.0  hranyatsya v pamyati PO-RAZNOMU.

   Mashina umeet preobrazovyvat' celye chisla v dejstvitel'nye
   i naoborot, nado tol'ko skazat' ej ob etom.
   Operator (double) x
   nazyvaetsya "privedenie tipa k double".

   Zametim, chto chasto preobrazovanie tipa
   vypolnyaetsya avtomaticheski.

   Tak, naprimer, pri slozhenii int i double
   int avtomaticheski privoditsya k double, i rezul'tat
   imeet tip double.

	int    var1;
	double var2, var3;

	var1 = 2;
	var2 = 2.0;
	var3 = var1 + var2;

   chto oznachaet na samom dele

	var3 = (double) var1 + var2;

   var3 stanet ravno 4.0

   Bolee togo, k primeru tip char - eto tozhe CELYE CHISLA iz intervala
   0...255. Kazhdaya bukva imeet kod ot 0 do 255.

*/

UKAZATELI
=========
void f(int x){
	x = 7;
}

main(){
	int y = 17;
	f(y);
	printf("y=%d\n", y);       /* pechataet: y=17 */
}

V argumente x pereda£tsya KOPIYA znacheniya y,
poetomu x=7; ne izmenyaet znacheniya u.
Kak vse zhe sdelat', chtoby vyzyvaemaya funkciya
mogla izmenyat' znachenie peremennoj?

Otbrosim dva sposoba:

	- ob®yavlenie y kak global'noj
	  (mnogo global'nyh peremennyh - plohoj stil'),

	- y=f(y);
	  (a chto esli nado izmenit' MNOGO peremennyh?
	  return, k neschast'yu, mozhet vernut' lish' odno znachenie).

Ispol'zuetsya novaya dlya nas konstrukciya: UKAZATELX.
--------------------------------------------------
Primer (@)

void f(int *ptr){       /* #2 */
	*ptr = 7;       /* #3 */
}

main (){
	int y=17;

	f(&y);          /* #1 */
	printf("y=%d\n", y);       /* pechataet: y=7 */
}

Nu kak, nashli tri otlichiya ot ishodnogo teksta?
----------------------------------------------------------------------
My vvodim dve novye konstrukcii:

	&y              "ukazatel' na peremennuyu y" ili
			"adres peremennoj y"

	*ptr            oznachaet "razymenovanie ukazatelya ptr"
			(podrobnee - pozzhe)

	int *ptr;       oznachaet ob®yavlenie peremennoj ptr,
			kotoraya mozhet soderzhat' v sebe
			ukazatel' na peremennuyu,
			hranyashchuyu int-chislo.


Dlya nachala opredelim, chto takoe ukazatel'.

	int var1, var2, z;      /* celochislennye peremennye */
	int *pointer;           /* ukazatel' na celochislennuyu peremennuyu */

	var1    = 12;
	var2    = 43;
	pointer = &var1;

My budem izobrazhat' ukazatel' v vide STRELKI;
eto horoshij priem i pri prakticheskom programmirovanii.
	________
       /pointer/
     _/_______/_
     | znachenie|        Peremennaya, hranyashchaya ukazatel'
     |   est'  |        (adres drugoj peremennoj)
     |         |
     |  &var1  |
     |         |
     |_______|_|
	     |
	     |&var1     - sam ukazatel' na var1 -
	     |            "strelka, ukazyvayushchaya na peremennuyu var1".
	     V            Ona oboznachaetsya &var1
	________
       / var1  /
     _/_______/_
     | znachenie|
     |   est'  |
     |    12   |
     |_________|

Takim obrazom, UKAZATELX - eto "strelka, ukazyvayushchaya na nekij yashchik-peremennuyu".
Nachalo etoj strelki mozhno (v svoyu ochered') hranit' v kakoj-nibud' peremennoj.

Pri etom, esli strelka ukazyvaet na peremennuyu tipa int,
to tip peremennoj, hranyashchej nachalo strelki, est' int *

Esli tipa char, to tip - char *

ADRES (ukazatel' na) mozhno vzyat' tol'ko ot peremennoj ili elementa massiva,
no ne ot vyrazheniya.

	int x;
	int arr[5];

	Zakonno     &x          strelka na yashchik "x"
		    & arr[3]    strelka na yashchik "arr[3]"

	Nezakonno   &(2+2)      tut net imenovannogo "yashchika",
				na kotoryj ukazyvaet strelka,
				da i voobshche yashchika net.



Ukazateli neskol'ko razlichno vedut sebya SLEVA i SPRAVA
ot operatora prisvaivaniya.
Nas interesuet novaya operaciya, primenyaemaya tol'ko k ukazatelyam:

	*pointer

--------------------------------------------------------------------
SPRAVA ot prisvaivanij i v formulah
===================================
*pointer        oznachaet
		"vzyat' znachenie peremennoj (lezhashchee v yashchike),
		na kotoruyu ukazyvaet ukazatel',
		hranyashchijsya v peremennoj pointer".

V nashem primere - eto chislo 12.

To est' *pointer oznachaet "projti po strelke i vzyat' ukazyvaemoe eyu ZNACHENIE".

	printf("%d\n", *pointer);

Pechataet 12;

	z = *pointer;        /* ravnocenno z = 12;        */
	z = *pointer + 66;   /* ravnocenno z = 12 + 66;   */

Zastavim teper' ukazatel' ukazyvat' na druguyu peremennuyu
(inache govorya, "prisvoim ukazatelyu adres drugoj peremennoj")

	pointer = &var2;

	________
       /pointer/
     _/_______/_
     |         |
     |  &var2  |
     |         |
     |_______|_|
	     |
	     |&var2
	     |
	     V
	________
       / var2  /
     _/_______/_
     |         |
     |   43    |
     |         |
     |_________|

Posle etogo   z = *pointer;
oznachaet      z = 43;

--------------------------------------------------------------------
Takim obrazom, konstrukciya

	z = *pointer;

	    oznachaet

	z = *(&var2);

	    oznachaet

	z = var2;

To est' * i & vzaimno STIRAYUTSYA.



	*pointer = 123;

Oznachaet        "polozhit' znachenie pravoj chasti (t.e. 123)
		 v peremennuyu (yashchik), na kotoryj ukazyvaet ukazatel',
		 hranyashchijsya v peremennoj pointer".

Projti po strelke i polozhit' znachenie v ukazyvaemuyu peremennuyu.

V dannom sluchae *pointer oboznachaet
ne ZNACHENIE ukazyvaemoj peremennoj,
 a SAMU     ukazyvaemuyu peremennuyu.

	________
       /pointer/
     _/_______/_
     |         |
     |  &var2  |
     |         |
     |_______|_|
	     |
	     |Polozhit' tuda 123
	     |
	     V
	________
       / var2  /
     _/_______/_
     |         |
     |   123   |
     |         |
     |_________|

	pointer  = &var2;
	*pointer = 123;

		oznachaet

	*(&var2) = 123;

		oznachaet

	var2 = 123;

To est' snova * i & vzaimno STIRAYUT drug druga.

--------------------------------------------------------------------
Eshch£ primer:

	*pointer = *pointer + 66;

		ili

	*pointer += 66;

--------------------------------------------------------------------
Vernemsya k primeru s funkciej (@). Kak on rabotaet?

V stroke /* #1 */
	My vyzyvaem funkciyu f(), peredavaya v nee
	UKAZATELX na peremennuyu y ("adres peremennoj y").

V stroke /* #2 */
	Otvoditsya lokal'naya peremennaya s imenem ptr,
	kotoraya v kachestve nachal'nogo znacheniya
	poluchaet znachenie pervogo argumenta funkcii v tochke vyzova -
	to est' UKAZATELX na y.

V stroke /* #3 */
	My vidim
		*ptr = 7;

	chto sleduet rassmatrivat' kak

		*(&y) = 7;          tochnee *(&main::y)=7;

	to est' kak

		y = 7;              tochnee main::y=7;

	CHto i hotelos'.

Pri etom otmetim, chto samo imya "y" etoj peremennoj
vnutri funkcii f() NEVIDIMO i NEIZVESTNO!

--------------------------------------------------------------------
PRIMER: obmen znachenij dvuh peremennyh.

void main(){
	int x, y;
	int temporary;  /* vspomogatel'naya peremennaya */

	x=1; y=2;

	temporary=x; x=y; y=temporary;
	printf("x=%d y=%d\n", x, y);    /* Pechataet x=2 y=1 */
}
-----------------------------------------------------------------------
Teper' to zhe s ispol'zovaniem adresov i ukazatelej:

void swap(int *a, int *b){
	int tmp;

	tmp = *a; *a = *b; *b = tmp;
}

void main(){
	int x, y;

	x = 1; y = 2;
	swap(&x, &y);
	printf("x=%d y=%d\n", x, y);
}
-------------------------------------------------------------------------
Eshch£ primer:

	int x;
	int *ptr1, *ptr2;

	ptr1 = &x; ptr2 = &x;
	*ptr1 = 77;
	printf("%d\n", *ptr2);          /* Pechataet 77 */

To est' na odnu peremennuyu MOGUT ukazyvat' neskol'ko ukazatelej.
-------------------------------------------------------------------------
Eshch£ primer:
	int x;
	int *ptr1;              /* Ne inicializirovana */

	x = *ptr1;

V ptr1 net ukazatelya ni na chto, tam est' musor.
Ukazatel' ukazyvaet "v nikuda" (pal'cem v nebo).
Skoree vsego proizojd£t sboj v rabote programmy.

Moral': VSEGDA inicializiruj peremennye, ukazateli v tom chisle.



YAzyk Si rabotaet s imenami massivov special'nym obrazom.
Imya massiva "a" dlya

	int a[5];

yavlyaetsya na samom dele ukazatelem na ego nulevoj element.

To est' u nas est' peremennye (yashchiki)
s imenami

	a[0]    a[1]    ...     a[4].

Pri etom samo imya a pri ego ispol'zovanii v programme oznachaet &a[0]

	a
	|
	|
	|
	V
       a[0]    a[1]    a[2]    a[3]    a[4]
     _________________________________________
     |       |       |       |       |       |
     |       |       |       |       |       |
     |       |       |       |       |       |
     -----------------------------------------

Poetomu

	int a[5];

	/* Pereda£tsya ne KOPIYA samogo massiva, a kopiya UKAZATELYA na ego nachalo */

	void f(int *a){         /* ili f(int a[]), chto est' ravnocennaya zapis' */
		printf("%d\n", a[1]);
		a[2] = 7;
	}

	main (){
		a[1] = 777;
		f(a);           /* argument - massiv */
		printf("%d\n", a[2]);
	}

Vyzov f(a); sdelaet imenno ozhidaemye veshchi.
V etom primere my vidim dva pravila:

PRAVILO_1:
	Pri peredache v funkciyu imeni massiva
	v argument funkcii kopiruetsya ne ves' massiv (zhirnovato budet),
	a ukazatel' na ego 0-oj element.

PRAVILO_2:
	Ukazatel' na nachalo massiva
	MOZHNO indeksirovat' kak sam massiv.
	|to vtoraya operaciya, pomimo *pointer,
	primenimaya k ukazatelyam: pointer[n].

Vtoroe pravilo vlechet za soboj ryad sledstvij.

	int a[5];       /* massiv */
	int *ptr;       /* ukazatel'naya peremennaya */

	ptr = a;        /* zakonno, oznachaet ptr = &a[0]; */

Teper'

	ptr[0] = 3;     /* oznachaet a[0] = 3;   */
	ptr[1] = 5;     /* oznachaet a[1] = 5;   */


Bolee togo. Voz'mem teper'

	ptr = &a[2];


       a[0]    a[1]    a[2]    a[3]    a[4]
     _________________________________________
     |       |       |       |       |       |
 a:  |       |       |       |       |       |
     |       |       |       |       |       |
     ----------------------------------------------
		     |       |       |       | ...
 ptr:                |       |       |       |
		     -----------------------------
	-2      -1     ptr[0]  ptr[1]  ptr[2]


My kak by "prilozhili" k massivu a[] massiv ptr[].

V kotorom

	ptr[0]  est'    a[2]
	ptr[1]  est'    a[3]
	ptr[2]  est'    a[4]
	ptr[3]          nahoditsya za koncom massiva a[], MUSOR

Bolee togo, dopustimy otricatel'nye indeksy!

	ptr[-1] est'    a[1]
	ptr[-2] est'    a[0]
	ptr[-3]         nahoditsya pered nachalom massiva a[], MUSOR

Itak: indeksirovat' mozhno I massivy I ukazateli.

Kstati, dlya imeni massiva a[]
	*a oznachaet to zhe samoe, chto i a[0].

|to obratnoe sledstvie iz shozhesti massivov i ukazatelej.

/* Zadacha: napisat' funkciyu invertirovaniya poryadka simvolov
   v massive char.
	A B C D ---> D C B A
   V reshenii mozhno ispol'zovat' rekursiyu.
 */

/* My privedem rekursivnoe i nerekursivnoe resheniya (dva varianta) */
#include <stdio.h>

/* Snachala - neskol'ko sluzhebnyh funkcij. */

/* FUNKCIYA PODSCHETA DLINY STROKI.
   Kak uzhe ob®yasnyalos', stroka teksta - eto massiv char,
   v konce kotorogo pomeshchen simvol '\0'.
   Sam simvol \0 ne schitaetsya.
 */
int strlen(char s[]){                   /* funkciya ot massiva bukv            */
	int counter = 0;                /* schetchik i odnovremenno indeks      */

	while(s[counter] != '\0')       /* poka ne vstretilsya priznak konca teksta */
		counter++;              /* poschitat' simvol                   */
	return counter;                 /* skol'ko simvolov, otlichnyh ot '\0' */
}

/* FUNKCIYA PECHATI STROKI.
   Pechataem kazhdyj element massiva kak simvol pri pomoshchi putchar(c).
   Kak tol'ko vstrechaem element massiva, ravnyj '\0' - ostanavlivaemsya.
   Zamet'te, chto pri nalichii zavershayushchego simvola nam NE NADO
   peredavat' v funkciyu razmer massiva, on nam neinteresen.

   V konce eta funkciya perevodit stroku.
*/
int putstr(char s[]){
	int i = 0;      /* indeks */

	while(s[i] != '\0'){
		putchar(s[i]);
		i++;
	}
	putchar('\n');
	return i;
}

/* TEPERX MY ZANIMAEMSYA FUNKCIEJ INVERTIROVANIYA.
   Dlya etogo nam nuzhna vspomogatel'naya funkciya:
   sdvig elementov massiva na 1 vlevo.

	Ishodnyj massiv: A B C D E F
			 <----------
	Rezul'tat:       B C D E F F
				   -
	Poslednij element udvaivaetsya.

	n - razmer massiva.
	Funkciya rabotaet tak:

	Ishodnyj massiv: A B C D E F  n=6
	Posle i=1        B B C D E F
	Posle i=2        B C C D E F
	Posle i=3        B C D D E F
	Posle i=4        B C D E E F
	Posle i=5        B C D E F F
	i=6 ==> ostanovka.

*/
void shiftLeft(char s[], int n){
	int i;

	for(i=1; i < n; i++)
		s[i-1] = s[i];
}

/* Funkciya invertirovaniya.
   Ideya takova:
	- esli dlina massiva men'she ili ravna 1, to invertirovat' nechego,
	  ibo massiv sostoit iz 1 ili 0 elementov.
	- esli dlina massiva > 1, to
	  a) Spasti nulevoj element massiva.
		A B C D E F
		|
		|
		V
	       tmp

	  b) Sdvinut' massiv vlevo
		B C D E F F

	  c) V poslednij element massiva pomestit' spasennyj nulevoj element.
			 tmp
			  |
			  V
		B C D E F A


	  d) Invertirovat' nachalo massiva dlinoj n-1.
	       {B C D E F}A

	     Poluchitsya:
		F E D C B A

	     CHto i trebovalos'.

	s[] - massiv,
	n   - ego dlina.
*/
void reverse(char s[], int n){
	char tmp;

	if(n <= 1)              /* nechego invertirovat' */
		return;

	tmp = s[0];             /* spasti */
	shiftLeft(s, n);        /* sdvinut' */
	s[n-1] = tmp;           /* peremestit' */

	reverse(s, n-1);        /* invertirovat' nachalo */
}

/* VTORAYA VERSIYA nerekursivna. Rekursiya zamenena ciklom.
   Dlina nachala massiva, kotoruyu nado invertirovat',
   vynesena na peremennuyu length.
*/
void reverse1(char s[], int n){
	char tmp;
	int length;

	for(length=n; length > 1; --length){
		tmp = s[0];
		shiftLeft(s, length);
		s[length-1] = tmp;
	}
}

char testString[] = "abcdefghijklmnopqrstuvwxyz";

/* Esli ne zadat' razmer massiva, on budet vychislen kompilyatorom avtomaticheski.
   On budet raven chislu bukv vnutri "..." PLYUS odna yachejka dlya nevidimogo
   simvola '\0' na konce.
   V dannom sluchae eto 27.
*/

void main(){
	int len;

	len = strlen(testString);
	/* vychislit' dlinu stroki: 26 ('\0' na konce ne schitaetsya) */

	printf("Stroka dlya testa: \"%s\", ee dlina %d\n",
				    testString,    len);
	/* Obratite vnimanie na dva momenta:
		- stroku (massiv char) sleduet pechatat' po formatu %s
		- chtoby vnutri "..." napechatat' simvol "
		  nado izobrazit' ego kak \"

	   A chtoby v putchar napechatat' simvol ' nado pisat' putchar('\'');
	 */

	/* Pervaya inversiya */
	reverse(testString, len);
	putstr("Invertirovannaya stroka:");
	putstr(testString);

	/* Vtoraya inversiya - vozvrashchaet v ishodnoe sostoyanie */
	reverse1(testString, len);
	putstr("Invertirovannaya v ishodnoe sostoyanie stroka:");
	putstr(testString);
}

/* Eshche bolee prostoj variant resheniya:
   prosto obmenivat' elementy mestami.

	A B C D E F G H I J
	J B C D E F G H I A
	|                 |     eti
	J B C D E F G H I A
	J I C D E F G H B A
	  |             |       potom eti
	J I C D E F G H B A
	J I H D E F G C B A
	    |         |         potom eti
	  ---->     <-----

	J I H D E F G C B A
	J I H G E F D C B A
	      |     |
	J I H G E F D C B A
		| |
	J I H G F E D C B A

		stop.
*/

#include <stdio.h>

/* Obmen znachenij dvuh peremennyh tipa char */
void swap(char *s1, char *s2){
	char c;

	c = *s1; *s1 = *s2; *s2 = c;
}

void reverse(char s[], int n){
	int first, last;

	first = 0;              /* indeks pervogo elementa massiva */
	last = n-1;             /* indeks poslednego elementa massiva */

	while(first < last){    /* poka first levee last */
		swap(&s[first], &s[last]);
		first++;        /* sdvinut' vpravo */
		last--;         /* sdvinut' vlevo  */
	}
}

char testString[] = "abcdefghijklmnopqrstuvwxyz.";

void main(){
	int len;

	len = strlen(testString);       /* Est' takaya standartnaya funkciya */
	reverse(testString, len);
	printf("Invertirovannaya stroka: %s\n", testString);
}

/* Eshche odin variant resheniya:
   sformirovat' otvet v dopolnitel'nom massive,
   a potom skopirovat' ego na prezhnee mesto.
*/

#include <stdio.h>

char testString[] = "abcdefghijklmnopqrstuvwxyz.";

/* Konstrukciya sizeof(massiv)/sizeof(massiv[0])
   vydaet razmer massiva, dazhe esli on ne byl yavno ob®yavlen.
   |ta konstrukciya primenyaetsya (chashche vsego) dlya zadaniya massiva
   s razmerom, ravnym razmeru uzhe ob®yavlennogo massiva.
 */

char tempString[ sizeof(testString) / sizeof(testString[0]) ];

void reverse(char s[], int n){
	int i;

	/* vyvernut', rezul'tat v tempString[] */
	for(i=0; i < n; i++)
		tempString[n-1-i] = s[i];

	tempString[n] = '\0';   /* priznak konca stroki */

	/* skopirovat' na staroe mesto */
	for(i=0; i < n; i++)
		s[i] = tempString[i];

	s[n] = '\0';            /* priznak konca stroki */
}

void main(){
	int len;

	len = strlen(testString);       /* Est' takaya standartnaya funkciya */
	reverse(testString, len);
	printf("Invertirovannaya stroka: %s\n", testString);
}

/* Zadacha invertirovaniya massiva celyh chisel */

#include <stdio.h>

int arr[]  = {1, 5, 10, 15, 20, 25, 30};
int arrLen = sizeof(arr) / sizeof(arr[0]);   /* razmer massiva */

/* Raspechatka massiva v stroku */
void printit(int row[], int n){
	int i;

	for(i=0; i < n; i++){
		printf("%d", row[i]);

		if(i == n-1) putchar('\n');
		else         putchar(' ');
	}
}
/* Pechat' otstupa. Otladochnaya funkciya */
void printShift(int n){
	n = arrLen - n;
	while(n > 0){
		printf("   ");
		n--;
	}
}
/* Sdvig massiva */
void shiftleft(int row[], int n){
	int i;

	for(i=1; i < n; i++)
		row[i-1] = row[i];
}
/* Invertirovanie */
void reverse(int  row[], int n){
	int pocket;

	printShift(n);                          /* trassirovka */
	printf("CALLED reverse(row, %d)\n", n); /* trassirovka */

	if(n <= 1){
		printShift(n);                  /* trassirovka */
		printf("return from reverse(row, %d);\n", n); /* trassirovka */
		return;
	}

	pocket = row[0];
	shiftleft(row, n);
	row[n-1] = pocket;

	printShift(n);                          /* trassirovka */
	printit(arr, arrLen);                   /* trassirovka */

	reverse(row, n-1);

	printShift(n);                          /* trassirovka */
	printf("all done; return from reverse(row, %d);\n", n); /* trassirovka */
}
void main(){
	reverse(arr, arrLen);
	printit(arr, arrLen);
}


/* Zadacha: napisat' funkciyu dlya raspechatki massiva celyh chisel
   v vide tablicy v columns stolbcov.
   Pri etom poryadok elementov dolzhen byt' takov:

   0    4    8
   1    5    9
   2    6    10
   3    7
*/

/* Pust' v massive n elementov.
   Esli n < columns, to my poluchaem takuyu situaciyu (n=2, columns=4)

	0       1       pusto       pusto

   Poetomu

	if(n < columns) columns = n;

   Dalee, pryamougol'naya tablica s columns stolbcami i lines strokami
   mozhet soderzhat' maksimum columns*lines elementov. Poetomu:

	columns*lines >= n

   Vychislim chislo strok.
   Nam nuzhno minimal'noe celoe chislo strok, takoe chto

	lines >= n/columns

   Takoe chislo vychislyaetsya po formule

	lines = (n + (columns - 1)) / columns;

   gde delenie celochislennoe.

   Dalee nado tol'ko vyvesti formulu dlya indeksa elementa v massive
   v zavisimosti ot nomera stroki (y) i stolbca (x).

   index(x, y) = (x * lines + y);
		 prichem esli index >= n, to nichego ne vyvodit'
*/

#include <stdio.h>

int array[100];

void printArray(int a[], int n, int columns){
	int lines;      /* chislo strok */

	int x, y;       /* nomer kolonki, nomer stroki - s nulya */
	int index;      /* indeks elementa v massive */

	if(n < columns) columns = n;
	lines = (n + (columns-1)) / columns;

	/* Ispol'zuem vlozhennye cikly: po strokam, a vnutri - po stolbcam */
	for(y=0; y < lines; y++){
		for(x=0; x < columns; x++){
			index = x * lines + y;
			if(index >= n)  /* element za koncom massiva */
				break;  /* prervat' stroku */

			/* break vyvodit tol'ko
			   iz vnutrennego cikla (po stolbcam) */

			/* sdelat' otstup v sleduyushchuyu kolonku */
			if(x != 0) putchar('\t');

			printf("%02d|%d", index, a[index]);
			/* Format %02d zastavlyaet pechatat' celoe chislo
			   s ispol'zovaniem DVUH cifr, prichem esli
			   chislo sostoit iz odnoj cifry, to speredi
			   pripisyvaetsya nul'.
			 */
		}
		putchar('\n');  /* perejti k sleduyushchej stroke */
	}
}
void main(){
	int i, cols;

	/* Inicializaciya znachenij elementov massiva */
	for(i=0; i < 100; i++)
		array[i] = i + 1;

	for(cols=4; cols <= 13; cols++){
		printf("\t\t* * * TABLICA V %d STOLBCOV * * *\n", cols);
		printArray(array, 77, cols);
		putchar('\n');
	}
}

#include <stdio.h>

main(){
	int x, y;
	int COLUMNS = 11;
	int LINES = 10;

	int value;

	/* cikl po strokam */
	for(y=0; y < LINES; y++){

		/* cikl po stolbcam */
		for(x=0; x < COLUMNS; x++){

			/* chto napechatat' */
			value = LINES * x + y;

			/* esli eto ne nulevoj stolbec, to perejti
			   v sleduyushchuyu kolonku
			 */

			if(x > 0) putchar('\t');

			/* ... i v nej napechatat' znachenie */
			printf("%d", value);

		}
		putchar('\n');  /* novaya stroka */
	}
}

/*
	elem(x, y) = LINES * x + y;

		togda

	elem(0, y+1) - elem(COLUMNS-1, y) = 1 + LINES - COLUMNS*LINES;
	elem(x+1, y) - elem(x, y)         = LINES;
*/

#include <stdio.h>

int A = 150;            /* Kolichestvo elementov      */
int COLUMNS = 7;        /* Kolichestvo stolbcov       */
int LINES;              /* Kolichestvo strok          */
int value;              /* Znachenie v tekushchej kletke */

int OFFSET_NEXT_COLUMN;
int OFFSET_NEXT_LINE;

/* Risuem stroku tablicy */
void line(){
	int col;        /* nomer kolonki */

	for(col=0; col < COLUMNS; col++){
		if(value >= A)       /* otsutstvuyushchij element */
			printf("* ");
		else    printf("%03d ", value);

		/* Uvelichenie pri perehode v sosednyuyu kolonku */
		value += OFFSET_NEXT_COLUMN;    /* 1 */
	}
	/* Perejti k sleduyushchej stroke */
	putchar('\n');

	/* Uvelichenie pri perehode iz konca odnoj stroki k nachalu sleduyushchej.
	   Zametim, chto k value uzhe pribavleno OFFSET_NEXT_COLUMN iz tochki 1,
	   poetomu pri perehode v nachalo sleduyushchej stroki v summe pribavlyaetsya
	   OFFSET_NEXT_COLUMN + OFFSET_NEXT_LINE ravnoe
		1 - LINES*COLUMNS + LINES,
	   chto sootvetstvuet formule.
	 */
	value += OFFSET_NEXT_LINE;              /* 2 */
}

int main(){
	int nline;  /* Nomer stroki */

	LINES = (A + (COLUMNS - 1)) / COLUMNS;

	OFFSET_NEXT_COLUMN = LINES;
	OFFSET_NEXT_LINE = 1 - LINES*COLUMNS;

	for(nline=0; nline < LINES; nline++)
		line();

	/* vozvrat 0 iz main() oznachaet "programma zavershena uspeshno" */
	return 0;
}

/* DVUMERNYE MASSIVY */

/*
	Dvumernyj massiv predstavlyaet soboj dvumernuyu
	pryamougol'nuyu tablicu iz numerovannyh peremennyh.

	On ob®yavlyaetsya tak:

		int array[LINES][COLUMNS];

	A indeksiruetsya tak:

		    array[y][x]

		gde 0 <= y <= LINES - 1
		    0 <= x <= COLUMNS - 1

	+-------------+-------------+-------------+------> os' x
	| array[0][0] | array[0][1] | array[0][2] | ...
	+-------------+-------------+-------------+
	| array[1][0] | array[1][1] | array[1][2] | ...
	+-------------+-------------+-------------+
	| array[2][0] | array[2][1] | array[2][2] | ...
	+-------------+-------------+-------------+
	| ...           ...           ...
	V
       os' y

Poka, na dannoj stadii znaniya Si,
ya rekomenduyu vam ob®yavlyat' dvumernye massivy kak global'nye
i ne pytat'sya peredavat' ih imena v funkcii kak argumenty.
*/

/* Privedem primer, kotoryj zavodit dvumernyj massiv bukv,
   risuet v nem nekuyu geometricheskuyu figuru,
   i pechataet etot massiv.

   Zdes' my privodim algoritm Brezenhema dlya risovaniya pryamyh,
   ob®yasneniya KAK on eto delaet my opustim. Pardon.
*/

#define LINES   31      /* chislo strok    */
#define COLUMNS 79      /* chislo stolbcov */

char field[LINES][COLUMNS];

/* V dannoj programme massiv NE yavlyaetsya parametrom,
   my rabotaem s nim kak s global'noj peremennoj.
   Funkciya risovaniya pryamoj linii, algoritm Brezenhema.
 */
void line(int x1, int y1, int x2, int y2, char sym){
        int dx, dy, i1, i2, i, kx, ky;
	int d;      /* "otklonenie" */
	int x, y;
	int flag;

	dy = y2 - y1;
	dx = x2 - x1;
	if (dx == 0 && dy == 0){
		field[y1][x1] = sym;    /* edinstvennaya tochka */
		return;
        }
        kx = 1; /* shag po x */
        ky = 1; /* shag po y */

        /* Vybor taktovoj osi */
        if( dx < 0 ){ dx = -dx; kx = -1; } /* Y */
	else if(dx == 0)        kx = 0;    /* X */

	if(dy < 0) { dy = -dy; ky = -1; }

	if(dx < dy){ flag = 0; d = dx; dx = dy; dy = d; }
	else         flag = 1;

        i1 = dy + dy; d = i1 - dx; i2 = d - dx;
        x = x1; y = y1;

	for(i=0; i < dx; i++){
		field[y][x] = sym;      /* narisovat' tochku */

		if(flag) x += kx; /* shag po takt. osi   */
		else     y += ky;

		if( d < 0 ) /* gorizontal'nyj shag      */
			 d += i1;
		else{       /* diagonal'nyj shag        */
			 d += i2;
			 if(flag) y += ky; /* prirost vysoty */
			 else     x += kx;
		}
	}
	field[y][x] = sym; /* poslednyaya tochka  */
}

int main(){
	int x, y;

	/* Zapolnit' pole probelami */
	for(y=0; y < LINES; y++)
		for(x=0; x < COLUMNS; x++)
			field[y][x] = ' ';

	/* Narisovat' kartinku */
	line(0,0,               0,         LINES-1, '*');
	line(0,0,               COLUMNS-1, 0,       '*');
	line(COLUMNS-1, 0,      COLUMNS-1, LINES-1, '*');
	line(0, LINES-1,        COLUMNS-1, LINES-1, '*');

	line(0,0,               COLUMNS-1, LINES-1, '\\');
	line(COLUMNS-1,0,       0,LINES-1,          '/');

	/* Raspechatat' massiv */
	for(y=0; y < LINES; y++){
		for(x=0; x < COLUMNS; x++)
			putchar(field[y][x]);
		putchar('\n');
	}
	return 0;
}

Last-modified: Fri, 05 Nov 2004 22:22:09 GMT
Ocenite etot tekst: