Więc jak obiecałem omawiam kolokwium. Zestaw 1. Łopatologicznie jak tylko miałem cierpliwość
W pierwszej kolejności patrzymy na funkcję main. Nie trzeba od razu przyglądać się deklaracjom zmiennych, więc przechodzimy do pierwszego printf-a
printf("Zestaw 1:\n%3d.%04d.%3d.\n",A(2-1,3+1,4*2)*2,2+A(3-1,4+1,1+2)/2,2*A(2+2,2-3,4-3)%2);
Analizujemy pokolei pierwszy argument, czyli to co w "". Najpierw jest zwykły tekst "Zestaw 1:", więc wypisujemy go, kratka na literę. Dalej mamy "\n" co jest znakiem przejścia do nowej lini (do początku). Potem znak specjalny % oznaczjący, że będziemy wypisywać jakąś zmienną. Po % jest 3, co oznacza, że zajmie ona PRZYNAJMNIEJ 3 znaki. Jeśli będzie to np liczba 2, która jest 1 znakiem, to z lewej pozostałe 2 znaki bedą puste, tzn spacje, czyli wypisze " 3". Następnie mamy d oznaczające typ danych jaki wypisujemy, d akurat to liczba całkowita typu int. Na typie kończy się zapis opisujący w jaki sposób zmienna ma być wypisana. Sprawdzamy więc co to za zmienna. Patrzymy na drugi argument printf-a czyli
A(2-1,3+1,4*2)*2
Analizujemy co to za wyrażenie. Ponieważ mamy jakiś symbol A i po nim bezpośrednio ( (ew moga być spacje) to mamy do czynienia z funkcją, albo taką powiedzmy pseudo-funkcją z #define. Szukamy wyżej w kodzie co to jest A. Znajdujemy
#define A(x,y,z) y*(i+(3*x+z))+1
więc ta druga opcja. Warto zapamiętać, że instrukcje preprocesora, czyli te zaczynające się od # w tym #define operują na samym tekście kodu jak edytor tekstowy, nie analizując go prawie, a kompilacja jest dopiero potem. #define robi coś takiego, że w miejsce
A(2-1,3+1,4*2)
wkleja
y*(i+(3*x+z))+1
a w miejsce x, y i z zgodnie z oznaczeniem "A(x,y,z)" wkleja kolejne wyrażenia między przecinkami, czyli za x 2-1 za y 3+1 za z 4*2. Ostatecznie więc zrobi taka podmianę:
3+1*(i+(3*2-1+4*2))+1
i że mieliśmy "A(2-1,3+1,4*2)*2", a to co wyżej zastąpiło A(2-1,3+1,4*2) to na końcu jest jeszcze *2. Ostatecznie:
3+1*(i+(3*2-1+4*2))+1*2
Takie przekształcenia trzeba robić albo w pamięci, albo zapisywać sobie w brudnopisie... Obliczamy sobie to wyrażenie, priorytety działań są tu normalne jak w matmie. "i" jest zmienną, szukamy wyżej jej wartości, w pierwszej linijce maina widzimy i=3 więc podstawiamy 3... Wychodzi 21 i to wypisujemy, pamiętając że miały być min. 3 znaki, a więc będzie " 21". Analizujemy w ten sposób dalej:
"Zestaw 1:\n%3d.%04d.%3d.\n"
Mamy kropkę, wypisujemy ją i jest następny opis zmiennej jaką printf ma wstawić - %04d - nowość w stosunku do wcześniejszego to tylko 0 oznaczające, że jeśli liczba będzie mniej niż 4 cyfrowa to wcześniej nie będzie spacji a 0, np dla 3 to będzie 0003. Znak % w ostatnim wyrażeniu to operator reszty z dzielenia, priorytet ma taki sam jak zwykłe dzielenie. 14%4 to np 2.
wsk=&arr[i/2]
Tu liczą się priorytety. Największy ma [] więc arr[i/2] (i/2 to 3/2, dzielimy liczby całkowite więc w wyniku też będziemy mieli całkowitą, zaokręglenie jest w dół, otrzymujemy 1) jest odwołaniem do drugiego (bo indexy tablic liczymy od 0) elementu tablicy arr zadeklarowanej wcześniej. & powoduje pobranie adresu pamięci, gdzie jest przechowywana ta zmienna (ten 2 el. tablicy). Czyli mamy wskaźnik. I na końcu ten wskaźnik, adres pamięci, przypisujemy do zmiennej wsk. Zadeklarowana jest wyżej jako float *wsk, czyli właśnie wskaźnik do zmiennej typu float (liczby rzeczywistej). Warto sobie gdzieś na boku zapisać co zawiera wsk, czyli na co wskazuje.
Potem kolejny printf:
printf("%9s:%4.1f,%-12.3e\n","ptr=arr",*wsk+j,*(wsk+j));
9 oznacza jak wcześniej, że co najmniej 9 znaków, a jak nie to uzupełnienie spacjami z lewej, %s oznacza, że będziemy wstawiać zmienną tekstową(tablicę znaków). Ten tekst to "ptr=arr", wypisujemy, oczywiście bez "", pamiętając że miało być min 9 znaków, a to co dane to 7, więc z początku będą 2 spacje. : jest normalnym znakiem, wypisujemy. %4.1f oznacza - co najmniej 4 znaki, inaczej spacje, .1 oznacza, że wypisuje zawsze 1 cyfrę po przecinku(dokładniej kropce), f określa typ jako liczbę rzeczywistą. Patrzy co mamy dane jako tą zmienną: jest "*wsk+j". * ma wyższy priorytet od +. Ze wskaźnika robi nam zmienną na którą było wskazanie, więc mamy jak pamiętamy 2 el. tablicy arr równy 6.14542678. Dodajemy do niego wartość j równą 4 i jest 10.14542678 wypisujemy to zgodnie z założeniami i mamy "10.1". Następnie przecinek przepisujemy. Dalej mamy symbole formatowania %-12.3e . - oznacza, że jeśli będzie mniej znaków niż tych 12 to uzupełniające spacje (ew 0 gdyby było 0 po - i przed 12) będą nie po lewo, a po prawo reszty. e oznacza liczbę rzeczywistą w notacji wykładniczej w zapisie 0.0000e+000 , gdzie przed kropką jest zawsze 1 cyfra, po - co najmniej 1, max tyle ile w formatowaniu określa prezycja, czyli u nas to .3 oznacza, że będą 3 cyfry po kropce (jeślo nie ma wcale tego .precyzja to domyślna precyzja jest 6 liczb po kropce, dla %f również). Zamiast + może być - zależnie od znaku wykładnika, a na wykładnik są zawsze(w naszych zastosowaniach) 3 cyfry. A jako ta liczba rzeczywista w notacji wykładniczej ma być zmienna dana jako *(wsk+j) . Ponieważ mamy nawiasy to najpierw dodajemy. Kiedy dodajemy do wskaźnika, to do adresu pamięci dodajemy wartość razy liczba bajtów jaką ma rozmiar zmiennej, jakiej typu jest wskaźnik. A prościej to przesuwamy wskaźnik o j elementów w tablicy na którą wskazywał. * ze wskaźnika rwyciąga nam ten element. Jako że j jest 4, a byliśmy już na 2 el. tablicy to mamy 6 el. równy 2879.4 . Zgodnie z wszystkimi ustaleniami będzie zapisany jako "2.879e+003 "
Polecam poczytać dokumentację, o tym jak zapisuje się formatowanie zmiennych w printf-ie
http://msdn.microsoft.com/en-us/library/56e442dc(VS.80).aspx
Wymagania są pojeb***, ale co zrobić, zaliczyć jakoś trzeba, a z 2 kolosów wystarczy zdobyć 15 na 50pkt więc może warto się chociaż trochę przygotować i cokolwiek sensownego napisać...
Omawiam dalej kolosa, mam nadzieję, że się przyda!
Jesteśmy w linii:
fun1(tab);
Jak widać jest to wywołanie funkcji fun1 o argumencie tab. Na początku maina w linii
char c; int high, i=3, j=4, in, low, tab[]={2,3,1,4,6};
jest definicja. Czyli mamy tablicę elementów typu int(liczb całkowitych). Jeśli jest
samo [] bez numeru elementów w środku to liczba elementów jest automatycznie ustalana na
podstawie podanych danych inicjujących - mamy tam 5 liczb, rozmiar tablicy=5. Samo tab, jak podane w argumencie fun1, jest wskaźnikiem do pierwszego elementu tablicy. I rzeczywiście jak można sprawdzić w
deklaracji zapowiadającej nad mainem
void fun1(int*);
albo w samej definicji niżej
void fun1(int *tab)
jako argument jest potrzebny wskaźnik na typ int. Dobra, przechodzimy do wnętrza tej funkcji.
Wewnątrz niej argument funkcji, czyli int *tab jest już jak zwykła zmienna lokalna, zupełnie
niezależna od tej w mainie (w fun1 nie "widać" zmiennych lokalnych maina i na odwrót). Ta
zmienna będąca argumentem ma jednak początkową wartość taką, jaką podaliśmy wywołując
funkcję, czyli jest wskaźnikiem na 1 element tab main-ie. I ważne, że to na co wskazuje tab w
fun1 możemy sobie dowolnie zmieniać i to nie będzie wpływać na tablicę w mainie, ALE jeśli
wskazuje na tamtą tablicę i będziemy modyfikowali dane pod tym adresem pamięci (poprzez *
czyli odwołanie do danych na które pokazuje wskaźnik) to możemy zmienić zawartość tablicy w
main().
Analizujemy kod fun1. Najpierw są deklaracje zmiennych, będą potrzebne dopiero później. Mamy wyrażenie:
i=(j=++tab[1])-1;
Zgodnie z priorytetami operatorów najpierw będzie obliczone tab[1]. Jest to odwołanie do
adresu pamięci który wskazuje wskaźnik tab plus 1 element typu int (bo typ tab to int*), czyli +4bajty. ALE to nas mało interesuje, bo wiemy że to wskaźnik na tablicę z maina, czyli to jest odwołanie do 2 el. tej tablicy (bo tablice indeksowane od 0...). Czyli mamy zmienną typu int - liczbę o wartości 3. Następnie pierwszeństwo ma ++ (w wersji preinkrementacji, bo przed wyrażeniem), które dodaje 1 do zmiennej (czyli już ten 2 el. tablicy tab w mainie ma wartość nie 3, a 4). To 4 przypisywane jest zmiennej lokalnej fun1 - j (ale nie tej wewnątrz maina! To inne zmienne choć sie tak samo nazywają, mają inne zakresy). Całe wyrażenie:
(j=++tab[1])
ma więc wartość 4. Następnie wyższy priorytet od = ma - ,więc od tej wartości 4 odejmujemy 1,
mamy 3 i przypisujemy to zmiennej i (znowu lokalnej fun1).
Dalej...
++tab[--j];
Najwyższy priorytet ma tu operator []. Ale że --j jest jego niejakim argumentem, to musi to
być najpierw obliczone. --j odejmuje od zmiennej j 1 czyli ma ona teraz wartość 3 (warto
sobie zapisywać, bo można się pogubić w tych wartościach...). Ponieważ -- jest w wersji
predekrementacyjnej (przed wyrażeniem) to wartość używana w reszcie obliczeń, czyli tu dla
[], jest już tą zmniejszoną. W wersji postdekrementacyjnej (to samo dla inkrementacji)
wartość używana do obliczeń nie jest jeszcze zmieniona, dopiero potem do zmiennej jest
dodawane/odejmowane 1.
Czyli w tym przypadku mamy tab[3] co sprawia, że w to miejsce wskakuje 4 element tablicy. Na
koniec wykonuje się ++, które zwiększa ten element o 1 (działamy przez wskaźniki więc ta
wartość będzie zmieniona "zdalnie" w tablicy wewnątrz maina).
Kolejna linia
tab[i++-1]=--j;
I tu znowu priorytety operatorów i działanie post/pre inkrementacji/dekrementacji, o czym już
pisałem. j jest zmniejszane o 1, ma wartość już 2. Przypisywane jest to elementowi tablicy,
jaki określa [i++-1] . W tym wyrażeniu, z uwagi na wersję postikrementacji, używana jest
jeszcze niezwiększona wartość i, czyli jest [3-1] ,zatem 3 element tablicy, jemu przypisujemy
to 2 jak ustaliliśmy. Po tym dopiero i ma zwiększaną wartość, od teraz równą 4.
printf(ciag,i+++1,j++,*(tab+1),*tab,--tab[2]);
w miejsce "ciag" wskakuje tekst jaki jest mu przypisany, czyli jakby
printf("Fun1:%-4d,%2d,%-3d.%05d:%-3d",i+++1,j++,*(tab+1),*tab,--tab[2]);
Tu zdaje się już nic nowego nie ma, wszystko omawiałem. Trzeba uważać na to formatowanie
danych i priorytety (w kolejności [] * ++/-- + a najważniejsze to nawiasy). "i+++1" to mniej
czytelne i++ + 1.
Kończy się funkcja, wracamy do maina i jesteśmy w linijce
fun2(wsk-1);
Działania fun1 zmieniły tablicę tab w mainie tak, że ma ona teraz wartości 2,4,1,5,6. Reszta
zmiennych w mainie ma takie wartości jak przed wejściem do fun1, a zmienne lokalne z fun1
przepadają.
Wywołujemy fun2, potrzebuje ona wskaźnika na float i to jej dajemy przez wsk-1. wsk wskazywał na 2 element tablicy arr. Odejmując od wskaźnika 1 powodujemy że będzie to wskazanie na element 1. (wartość zmiennej wsk maina oczywiście nie jest zmieniana, natomiast ta pomniejszona jest przypisywana argumentowi fun2, czyli zmiennej lokalnej float *wsk w fun2).
Wewnątrz fun2:
printf("\nFun2:\n");
To chyba banał...
for(j=1,i=5-j;j<4;j++,ciag[4]++)
j=1,i=5-j
To jest wykonywane tylko raz, na samym początku. Przecinek oddziela operacje, wykonywane są
one od lewej do prawej. Czyli najpierw przypisujemy j 1, potem i przypisujemy 5-j czyli 5-1
czyli 4.
Dalej w środku między ;; jest zawsze warunek kontynuowania pętli, u nas j<4 czyli będzie
wykonywany przebieg jeśli j będzie mniejsze niż 4. Warunek jest sprawdzany na początku
każdego przebiegu(ale już po tamtych przypisaniach co wyżej), więc pętla może sie nie wykonać
ani razu. Na koniec
j++,ciag[4]++
To operacje wykonywane po każdym przebiegu pętli. A ciałem pętli, czyli tym co się wykonuje w
każdym przebiegu jest
printf("%-9s%1u%1s;%3.0f,%.3e\n",ciag,--i+2,"]",*(wsk+1)*j,*wsk+j);
Tu nic nowego, może tylko typ "u" - jest to liczba całkowita bez znaku, czyli nieujemna. To lecimy po tej pętli... Najpierw j było 1, 1<4 więc wykonuje się pierwszy przebieg, wypisujemy co tam printf wyprodukuje. Wykonujemy "j++,ciag[4]++". j ma od teraz 2, ciag[4]++ dodaje 1 do 5 elementu tablicy ciąg. Ponieważ jest to znak, a znak wewnętrznie jest właściwie odpowiadającą mu liczbą, to zwiększamy tę liczbę o 1, a tym samym literę na następną w alfabecie (dokładnie na znak kolejny w tablicy ASCII). I następne okrążenie pętli... 2<4 więc się wykona. W następnym 3<4 wiec znowu się wykona. Aż w końcu 4<4 nie jest prawdą, pętla sie już nie wykona, przechodzimy za nią, a że to już koniec funkcji to wracamy do maina.
high=i=in=low=0;
operator przypisania jest łączny prawostronnie, co oznacza, że kolejność działań będzie taka
jak gdyby zapisać:
high=(i=(in=(low=0)));
A więc wszystkie 4 zmienne uzyskają wartość 0.
while((c=NEXT(i))!=EOS) if(c<'0')low++; else if(c>'9')high++; else ++in;
while jest pętlą, która sprawdza warunek wykonania na początku, więc może nie byc ani jednego przebiegu. Warunek to:
(c=NEXT(i))!=EOS
NEXT oraz EOS to konstrukcje preprocesora, a wiec w tekście po prostu podstawiamy sobie to, co oznaczają. Mamy:
(c=wejscie[i++])!='\0'
Najpierw jest robione to co w nawiasie, c przypisywany jest [i] el. tablicy wejscie czyli
i+1wszy, ale dlatego, że indeksujemy od 0 nie za sprawą ++. Dopiero potem i jest zwiększane o 1
przez ++. Mamy != - operator porównania, który zwraca prawdę (liczbę 1) jeśli po obu stronach
ma różne wartości. Inaczej zwraca fałsz(liczbę 0). Z lewej strony mamy to co c (ale już nie
to co wejscie[i++], bo i ma już zwiększoną wartość) a z prawej '\0' . ' ' tak technicznie
rzecz biorąc zamieniają podany znak w nich zawarty na odpowiadającą mu liczbę. \0 to znak
specjalny, któremu odpowiada właśnie liczba 0. Więc po prawej != mamy 0.
Jeśli cały ten złożony warunek będzie prawdą, to wykonywane jest ciało pętli czyli
if(c<'0')low++; else if(c>'9')high++; else ++in;
If-y sprawdzają warunki w nawiasach np. c<'0' to porównanie niby znaków, technicznie cyfr im
odpowiadających wg ASCII, a praktycznie wg kolejności w alfabecie (z tym że duże litery są
niżej od wszystkich małych, polskie litery gdzieś zupełnie dalej, nie mówiąc o innych
znakach (te standardowe np */- są zazwyczaj przed wszystkimi literami i cyframi), a cyfry są kolejno
od 0, ale niżej od wszystkich liter). Jeśli warunek jest prawdziwy wykonuje się to co za if-em pierwszym
i znowu wykonywane są operacje na warunku while, sprawdzana wartość logiczna... Jeśli warunek
ifa nie jest prawdą to przechodzi do else. Że w else jest znowu if to sprawdza jego wartość i
znowu wykonuje, albo idzie do ostatniego else. W ostatnim else nie ma już if-a, jeśli do tego momentu dojdzie to zawsze wykona się to ++in. I wtedy przechodzi do warunku while. Kiedy już warunek while nie będzie prawdą to kończy się pętla i przechodzi do kolejnej linijki.
Ale jak spojrzeć na warunek while, że z zerem jest porównywany element tablicy wejscie, a
jest ona długa i tych przebiegów będzie za dużo żeby pokolei je sprawdzać (bo w tej tablicy znak
0 jest po ostatniej kropce. Automatycznie jest dodawany przy inicjacji tablicy znaków jako
znak końca tekstu). Trzeba pomyśleć ogólnie co właściwie robi ta pętla - sprawdza każdy znak z "Grupy M4 - M6 pisza kolokwium 1 z PRM w dniu 12/04/2007." , do zmiennej low zlicza te niżej zera (to będą
spacje - / oraz .) do high wyżej od 9 czyli wszystkie litery, a do in pozostałe, czyli cyfry.
PRINT3(-2d,low,in,high);
To zagnieżdżany preprocesor. Przekształcenia będą takie:
PR(-2d,low), PRINT2(-2d,in,high);
potem:
printf(" "#val"=%"#format",",(low)), PR(-2d,in), PRINT1(-2d,high);
# to tak zwany operator łańcuchujący. Otacza on w "" to co za nim stoi, ale najpierw jeśli
trzeba tamten symbol podmienia. U nas val odpowiada low, a format to -2d. Będzie więc
printf(" ""low""=%""-2d"",",(low)), PR(-2d,in), PRINT1(-2d,high);
Podwójne " się niejako redukują, więc jest
printf(" low=%-2d,",(low)), PR(-2d,in), PRINT1(-2d,high);
i podstawiamy dalej
printf(" low=%-2d,",(low)), printf(" in=%-2d,",(in)), PR(-2d,high), NL;
printf(" low=%-2d,",(low)), printf(" in=%-2d,",(in)), printf(" high=%-2d,",(high)), printf("\n");
uff i na tym koniec przekształceń preprocesora. printf-y oddzielane przecinkami wykonują się pokolei od lewej do prawej, chyba nie ma tu niczego nadzwyczajnego.
i=low=in=high=0; j=FALSE;
Nic nowego, preprocesor i o przypisaniu to co było
while((c=NEXT(i))!=EOS && !j) if(c<'Z')low++; else if(c>'A')high++; else in++;
pętla bardzo podobna do poprzedniej. && ma tu ze wszystkiego najmniejszy priorytet. To koniunkcja. Operuje na wartościach logicznych (w praktyce na liczbach, 0 to fałsz, każda inna to prawda) i zwraca 1 dla prawdy 0 dla fałszu. Jak wiadomo prawda będzie tylko jak oba zdania koniunkcji będą prawdą. ! jest negacja logiczną, traktuje wartość j jako logiczną i zwraca 1 albo 0. Obliczane są wartości logiczne po obu stronach &&. po lewej tak samo jak we wcześniejszej pętli. !j jest zawsze prawdą, bo j jest zawsze 0, nie zmienia się w pętli.
Negacja 0 czyli logicznego fałszu to logiczna prawda czyli 1. Ostatecznie warunek pętli jest taki sam jak wcześniejszej bo liczy się tylko to co z lewej &&. Zliczamy do low znaki niealfanumeryczne, cyfry i duże litery oprócz Z. Do high duże litery oprócz A (ale tylko te niezliczane przez low, czyli w rezultacie Z-y) oraz małe litery. Do in reszta - czyli nic.
if(low>=EN || high>+EN || in>=EN) j=TRUE;
To połączenie tego o czym już mówiłem. Preprocesor, operatory i ich priorytety. || to logiczna alternatywa, najniższy tu priorytet oprócz przypisania, >= to porównanie, prawda zwracana jeśli to co z lewej jest większe lub równe temu z prawej, chyba logiczne nie jest operatorem, jest nim samo > , a + jest operatorem znaku, który stoi przed liczbą i robi on NIC. Jak w matmie możemy + przed liczbą napisać, nawet ujemną (+-liczba=-liczba) albo nie i nic to nie zmienia. Ale ogólnie warto zauważyć, że tą linię równie dobrze możemy wyrzucić, bo jedyną zmiane, jaką może wprowadzic to zmienić wartość j. A kawałek dalej mamy zawsze j=FALSE; Po drodze wartość j nie jest nigdzie używana.
Potem:
PRINT3(-3d,low,in,high);
i=low=in=high=0; j=FALSE;
analogicznie jak wcześniej
while((c=NEXT(i))!=EOS && !j)
warunek ten sam, ale tu j już będzie sie zmieniało w pętli i ma znaczenie.
if(c<'a') j=(++low==EN); else if(c>'z') j=(high++==EN); else j=(++in==EN);
Nowość to konstrukcje typu "j=(++low==EN)", "j=(high++==EN)" i "j=(++in==EN)". zmiennej j jest przypisywana wartość obliczona w nawiasie. A np. dla tego drugiego == porównuje high z EN(podstawione przez preprocesor, to jest 3). Zwraca 1 jeśli jest równe, 0 jeśli nie. po tym dopiero zwiększa high o 1. j jest przypisywana wartość logiczna, zawsze to będzie 0 lub 1.
Jak się chwilę zastanowić, to pętla jest przerywana albo jak sie skończy tekst, albo kiedy j będzie równe 1 (a to nastąpi u nas szybciej). j będzie równe 1 po tym gdy low osiągnie 3, czyli zliczone zostaną w sumie 3 litery duże\cyfry\znaki niealfanumeryczne, albo gdy high porównywane będzie równe 3, a będzie to w momencie zliczania już 4 znaku high(za sprawą postinkrementacji), czyli 4 znaku większego od 'z' - takich w ogóle tam nie mamy, lub gdy in osiągnie wartość 3, czyli przy zliczaniu 3 litery małej. Jak spojrzymy na tekst to widać że pierwszy będzie warunek z in. Zliczone będą tylko znaki "Grup" więc high osiągnie 0, low 1, a in właśnie 3.
PRINT3(-4d,low,in,high);
Zakładając dla pierwszego wiersza po fun2
że c na wejściu jest 1 elementem tablicy wejscie[] czyli w tym przypadku bedzie to litera G
to patrzymy jaki jest pierwszy warunek if(c<'0')low++ else if(c>'9')high++ else ++in
otwieramy teraz tablicę ASCII która mam nadzieje bedzie na wykładzie
http://www.programuj.com/ascii.php
i teraz cały trick polegający na tym że liczymy ile mamy znaków które leżą powyżej 0 w tym przypadku będą to od nr 0 - 47 w tablicy
przelatujemy przez tekst zliczamy wszystkie i to jest nasze low
następnie liczymy ile mamy znaków które leżą powyżej 9 czyli od 58-127 w ASCII
i to jest nasze high
reszta czyli nasze in to będą wszystkie cyferki występujące w tym tekscie
mamy low in high
teraz na chybił trafił wypisujemy te spacje przecinki (bo nie mamy czasu na dalszą analizę) załóżmy
" low=15, in=11, high=30,"
Następny wiersz lecimy analogicznie (przynajmniej tak mi sie wydaje
)
if(c<'Z')low++ else if(c>'A')high++ else in++
W tablicach ASCII nad Z leżą duże litery cyfry znaki niealfanumeryczne
zliczamy je z tekstu to jest nasze low
high to bedą wszystkie ktore leża pod A
in to w tym przypadku bedize 0 bo te dwa poprzednie przedzialy sie pokryja
i analogicznie
" low=32 , in=0 , high=24 ,"
Dlaczego spacja przed każdym bo w każdym printfie jest(" low.....") a dlaczego spacje na końcu? ponieważ w pierwszym wierszu jst -2d czyli conajmniej dwa znaki i dopisujemy spacje na prawo
w drugim wierszu natomiast jest już -3d i dlatego przecinek przesuwa nam sie w prawo bowiem jest to ta dodatkowa spacja
Trzeci wiersz to już calkowity spontan
Poprostu patrze na warunek dla c
I zlizcam wszystko z pierwszego wyrazu razem ze spacją czyli "Grupy " i porównuje to z wartością EN
1 dla prawdy 0 dla fałszu i chyba tyle
i tak wypisuje nie zapominając o brakujących spacjach w tym przypadku -4d
Nie mam zielonego pojecia czy ktoś to zrozumiał.
Ale życzę samych maxów
EDIT
Co do tego wypisywania juz na czysto
to mniej wiecej printf ma taka postac
printf(" #val=%#format", (val))
czyli w naszym przypadku val może byc low , in , high
a formatem jest pierwsza "współrzędna" z tego PRINT3(-2d,low,in,high) czyli -2d
po podstawieniu drukuje nam
printf(" low=%-2d, in=%-2d, high=%-2d) w miejsce %-2d wstawiamy to co policzyliśmy na szybko
tak samo dla następnych wierszy z tą różnicą że zmienia sie tylko %-2d na %-3d
a w ostatnim dochodzi porównanie tego co policzmy z wartością EN = 3 w tym przypadku
EDIT2
Nawet jeśli nie wiecie jak wypełnić 3 wiersz wystarczy że wpiszecie (chyba):
" low=0 , in=0 , high=0 ,"
Traficie 1/3 jak nie 2/3
if(low>=EN || high>EN || in>=EN) j=TRUE;
Ten cały warunek to zmyła. Równie dobrze można tą linię wyrzucić, bo kawałek dalej jest
j=FALSE;
a nigdzie po drodze wartość j nie jest używana.
Strona nr 8