Forum Hacking , problemy , zainteresowania itp. Strona Główna  
 FAQ  •  Szukaj  •  Użytkownicy  •  Grupy •  Galerie   •  Rejestracja  •  Profil  •  Zaloguj się, by sprawdzić wiadomości  •  Zaloguj
 Kurs C++ Zobacz następny temat
Zobacz poprzedni temat
Napisz nowy tematOdpowiedz do tematu
Autor Wiadomość
Jarol
Administrator



Dołączył: 26 Paź 2005
Posty: 97 Przeczytał: 0 tematów

Pomógł: 1 raz
Ostrzeżeń: 0/5

PostWysłany: Wto 12:47, 20 Cze 2006 Powrót do góry

WSTĘP

Celem tego kursu jest wprowadzenie do programowania w językach wysokiego poziomu. Będzie on dotyczył języka C++. Kurs jest przeznaczony dla osób początkujących. Przedstawienie całej złożoności i możliwości tego języka jest nierealne, a bez znajomości podstaw nie da się go opanować. Reszta przyjdzie z czasem - wszystko zależy od wyobraźni twórcy i jego chęci zagłębienia się w szczegóły.

Jeżeli zamierzasz zająć się pisaniem poważnych i skomplikowanych programów, ten kurs może okazać sie niewystarcząjacy. Zachęcam więc do studiowana helpa, który obfituje w przykłady i zawiera odnośniki do tematów pokrewnych. Jedynym minusem tego rozwiązania jest to, że trzeba choć w minimalnym stopniu znać język angielski. Ale - jak się przekonasz - język C++ to jeden wielki skrót języka angielskiego.
j). Borland C++ utworzy najprawdopodobniej katalog BORLANDC. W nim znajduje się katalog BIN (na razie dla Ciebie najważniejszy) oraz kilka innych, między innymi BGI, INCLUDE i LIB.

Po uruchomieniu pliku BC.EXE (z katalogu BIN) ukaże się standardowy dosowski interfejs. Myszką lub przy pomocy klawisza F10 aktywujemy z menu FILE opcje NEW i już możemy zabrać się do pisania.

Wszystko co napiszesz, zostanie zachowane w pliku tekstowym z rozszerzeniem .C lub .CPP. Jeżeli program jest już gotowy, wystarczy nacisnąć kombinację klawiszy CTR+F9 i podziwiać efekty własnej pracy... Oczywiście jeśli kompilator nie znajdzie błędów Wink


SKRÓTY

Pisanie programów - zwłaszcza tych bardziej zaawansowanych - bardzo przyspiesza znajomość tak zwanych skrótów klawiaturowych. Już przy pierwszych lekcjach proponuję używać choć kilku. Nie chcę nawet słyszeć, ze ktoś sięga po myszkę, aby skompilować program!

Abyś nie musiał ich ciągle szukać po menu, zamieszczam poniżej listę i opis najważniejszych z nich.

* Operacje na pliku .CPP
o F3 OPEN (otwórz) - otwiera istniejący dokument *.CPP
o F2 SAVE (zachowaj) - zachowuje plik z wprowadzonymi zmianami

* Operacje podstawowe
o Ctrl+F9 RUN (uruchomienie) - w ten sposób uruchamiasz swój program
o F10 MENU (menu)- uaktywnienie menu
o Shift+F1 HELP INDEX (indeks tematów pomocy) - przyda się bardziej niż Ci się wydaje
o ALT+X QUIT (wyjście) - opuszczenie programu

* Operacje na dużej ilości powtarzającego się tekstu
o SHIFT+kursor - zaznaczenie tekstu
o CTRL+K+H - odznaczenie tekstu
o CTRL+INS COPY (kopiuj) - skopiowanie zaznaczonego tekstu do schowka
o SHIFT+INS PASTE (wklej) - wklejenie skopiowanego wcześniej tesktu ze schowka
o SHIF+DEL CUT (wytnij) - wycięcie zaznaczonego tekstu i skopiowanie go do schowka
o CTRL+DEL CLEAR (wyczyść) - usunięcie zaznaczonego tekstu bez kopiowania do schowka

* Operacje dla niezdecydowanych Wink
o ALT+BKSP UNDO (cofnij) - cofa ostatnie zmiany
o SHIFT+ALT+BKSP REDO (ponów) -przywraca cofnięte wcześniej zmiany

W tej chwili pierwsze dwie kategorie są dla Ciebie najważniejsze.



LEKCJA 1 - PODSTAWOWE INSTRUKCJE


Nadszedł czas, aby napisać pierwszy program. Na razie nie będzie on robił nic nadzwyczajnego. Stopniowo zaczniemy go rozbudowywać, a przy okazji omówię tu najistotniejsze sprawy. Oto nasz pierwszy program:

#include <stdio.h>
void main(void)
{
printf("Anna Miedzianowska");
}

Ten program możemy bez problemu skompilować. Ale efekt może wydać się marny... Czarny ekran zaraz znika i nie można się przyjrzeć efektom własnej pracy... Dlatego musimy wprowadzić małą modyfikację. Ale najpierw wyjaśnię to, co już zostało napisane.

Linijka pierwsza: instrukcja #include poleca kompilatorowi dołączyć do programu plik stdio.h (tzw. pseudonagłówkowy), w którym zawarta jest definicja funkcji printf. Jest tam też wiele innych definicji przeróżnych funkcji i jest on jednym z najczęściej używanych plików pseudonagłówkowych. Bardzo często używa się też plików: conio.h, math.h itp. Zamiast znaków nierówności (< >) można też użyć znaku cudzysłowia (""). Wszystkie pliki *.h znajdują się w podkatalogu INCLUDE. Tak więc pierwsza rzecz, od której należy zacząc pisanie programu to właśnie dyrektywa #include.

Linijka druga: Tu rozpoczyna się główna funkcja programu (main()). Musi ona wystąpić w programie dokładnie 1 raz! Wszystkie instrukcje programowe zawierają się w jej ciele, czyli między nawiasami klamrowymi. Nagłówek tej funkcji ma w naszym przypadku postać: void main(void). Słowo void oznacza brak parametrów i w zasadzie można je pominąć. Znaczy to, że funkcja główna nie daje wyniku żadnego typu i nie pobiera żadnych parametrów do poprawnego wywołania. Dla przykładu deklaracja funkcji main może wyglądać również tak:

* int main() - funkcja w wyniku swojego działania zwróci wartość typu int i nie pobiera żadnych parametrów przy rozpoczęciu działania.
* int main(void) - inny zapis, ale znaczenie takie samo jak wyżej
* main() - jeszcze inny zapis, ale znaczenie takie samo jak wyżej
* float main() - w tym przypadku wynikiem działania funkcji będzie typ float.

Przez dłuższy czas możemy się tym jednak nie przejmować i po prostu pisać: main()

Linijka czwarta: To ciało naszej funkcji głównej. Instrukcja printf która sprawia, że określony tekst zostanie wyświetlony na ekranie. Jak każda instrukcja kończy się średnikiem.
Linijka trzecia i piąta: Nawiasy klamrowe oznaczają grupę instrukcji. W tym przypadku pokazują one ciało funkcji głównej.

Podsumowując:

1. Na początku piszemy #include i pliki z definicjami instrukcji.
2. Deklarujemy funkcję main().
3. W ciele funkcji głównej wypisujemy wszystkie instrukcje (zakończone średnikiem), które program ma wykonać.
4. Wielkość liter nie jest bez znaczenia, więc x i X oznaczać mogą dwie różne zmienne.
5. Kompilujemy przez użycie kombinacji klawiszy: CTRL+F9.

A teraz czas na modyfikacje:

#include <stdio.h>
#include <conio.h>
main(void)
{
//to jest komentarz, który
//kończy się na końcu linii
clrscr();
printf("Anna \nMiedzianowska");
getch();
return 0;
}

Efektem skompilowania tego kodu będzie wypisanie na ekranie napisu "Anna Miedzianowska".

Modyfikacja polegała przede wszystkim na wprowadzeniu nowych funkcji: clrscr() oraz getch(). Ich definicje opisane są w pliku conio.h, dlatego należało go dopisać na samym początku po dyrektywie #include. Co robią dane funkcje? Pierwsza z nich czyści ekran (odpowiednik "cls" w Dosie). Druga zatrzymuje działanie programu i czeka na wciśnięcie dowolnego klawisza. Jest jeszcze kilka innych sposobów na zatrzymanie pracy programu, aby można było obejrzeć efekt, np. wpisanie while(!kbhit()); zamiast getch() lub np. getchar();.

To, co pojawiło się w kodzie przed moim nazwiskiem, to nie jest żadna literówka. Efekt widać po uruchomieniu programu - nazwisko zostało przeniesione do następnej linijki. \n jest to tzw. znak specjalny. Innym z częściej używanych znaków specjalnych jest np. \t - tabulacja czy \a - krótki sygnał dźwiękowy.

Po modyfikacji pojawiło się także tajemnicze return 0;. Chodzi o to, że skoro funkcja główna została zadeklarowana jakby zwracała typ int (domyślnie), więc na końcu programu należy wpisać return 0; jako pomyślny wynik jej działania. Bez tego oczywiście nic się nie stanie, więc równie dobrze można to pominąć.

Ostatnią nową sprawą jest komentarz. Można w nim napisać co się tylko chce, kompilator z założenia nie czyta komentarzy. Dla krótkich komentarzy stosuje się najczęściej formę przedstawioną w przykładzie: dwa ukośniki rozpoczynają komentarz (//), a kończy się on samoistnie na koncu linii. Jeżeli komentarz jest dłuższy niż jedna linijka należy rozpocząć go znakami /* i zakończyć w odpowiednim miejscu znakami: */ Nie jest istotne dla kompilatora, w którym miejscu napiszemy komentarz.

Podsumowując:

1. Mamy 2 rodzaje komentarzy i możemy w nich pisać, co nam się podoba.
2. Aby zatrzymać pracę programu, używamy funkcji getch();.
3. Do czyszczenia ekranu służy funkcja clrscr();.
4. Przyzwoicie by było napisać na końcu return 0;.
5. W tekście możemy używać tzw. znaków specjalnych, np. złamanie tekstu do następnej linii (\n).

To tyle, jeżeli chodzi o pierwszą lekcję. Dla ciekawych powiem, że kolory w edytorze dla poszczególnych wyrażeń nie są przypadkowe. Kolorem białym sa wyróżniane tzw. słowa kluczowe, niebieskim tekst cytowany i liczby, zielonym dyrektywy kompilatora, a wszystko inne na żółto. Jeśli natomiast zaczniemy wpisywać coś zupełnie bez sensu, edytor zaznaczy to kolorem czerwonym.



LEKCJA 2 -TYPY ZMIENNYCH I WZORCE KONWERSJI


Pierwszą lekcję mamy już za sobą. Była długa i nie dawała zbyt efektownego wyniku. Program wyświetlił napis i poczekał na wciśnięcie klawisza. Aby lepiej współpracować z programem, należy zająć się pojęciem zmiennych.

Zmienne najogólniej mówiąc służą do tego, aby zapamiętać sobie tymczasową wartość, którą potem można zmienić w każdej chwili według potrzeby.

Istnieje kilka typów zmiennych:

* char - typ znakowy
* int - liczba całkowita
* float - liczba zmiennoprzecinkowa (rzeczywista)
* short - liczby całkowite krótkie
* long - liczby całkowite długie
* double - liczby zmiennoprzecinkowe podwójnej precyzji
* long double - liczby zmiennoprzecinkowe podwójnej precyzji długie

Dla nas najważniejsze są pierwsze trzy typy i na razie tymi będziemy się zajmować.

Operacje arytmetyczne przypominają konwencjonalny matematyczny zapis. Również kolejność działań jest identyczna jak w matematyce. Poniżej przedstawiam zestaw najczęściej używanych operatorów:

+, -, *, /, = dodawanie, odejmowanie, mnożenie, dzielenie, operator przypisania
% reszta z dzielenia (odpowiada operacji modulo)
++, -- inkrementacja i dekrementacja
! negacja
<, > mniejsze, większe
<=, >= nie większe, nie mniejsze
&&, || i, lub (logicznie)
== równe
+=, -=, *=, /= połączenie operatorów przypisania i innych

Kilka operatorów wymaga krótkiego omówienia. Inkrementacja jest to proces zwiększenia zmiennej o 1, a dekrementacja zmniejszenia o 1. W tej chwili wydaje się to zupełnie niepotrzebne, ale w dalszych lekcjach okaże się bardzo przydatne. Zmienną A możemy inkrementować na dwa sposoby:

A=A+1; - sposób tradycyjny
A++; - sposób krótszy, choć mniej intuicyjny

Podobnie sprawa się ma z ostatnim przykładem w powyższej tabelce, czyli z połączeniem operatorów przypisania z innymi operatorami. Działanie takich złożonych operatorów można opisać używając sposobu tradycyjnego:

Sposób krótszy Sposób tradycyjny
a+=5; a=a+5;
b-=3; b=b-3;
a*=2; a=a*2;
b/=4; b=b/4;

Pierwszy przykład oznacza, że nową wartość zmiennej a uzyskamy dodając do jej obecnej wartości liczbę 5.
Drugi przykład oznacza, że nową wartość zmiennej b uzyskamy odejmując od jej obecnej wartości liczbę 3.
Trzeci przykład oznacza, że nową wartość zmiennej c uzyskamy mnożąc jej obecną wartość przez liczbę 2.
Czwarty przykład oznacza, że nową wartość zmiennej d uzyskamy dzieląc jej obecną wartość przez liczbę 4.

Znając typy zmiennych i zapis operacji matematycznych, możemy zabrać się za pisanie następnego programu. Najprostszym przykładem użycia zmiennych jest prosty kalkulator. Napiszemy więc program, który poprosi nas o wpisanie dwóch liczb i wykona na nich podstawowe działania matematyczne: zsumuje je, odejmie, pomnoży i podzieli. Na początku program musi wczytać dwie liczby:

#include <stdio.h>
#include <conio.h>
main (void)
{
int a,b; //deklaracja zmiennych a i b
clrscr();
printf("Podaj liczbę A: \n");
scanf("%d",&a);
printf("Podaj liczbę B: \n");
scanf("%d",&b);

printf("Wpisane liczby to: %d, %d.\n",a,b);
getch();
return 0 ;
}

W efekcie na ekranie możemy zobaczyć na przykład napisy:


Podaj liczbę A
15
Podaj liczbę B
28
Wpisane liczby to: 15, 28.

A teraz komentarz:
Na początku w funkcji głównej programu zadeklarowaliśmy zmienne a i b. Najpierw napisaliśmy typ zmiennych (calkowity), a następnie po przecinku wymienialiśmy nazwy zmiennych tego typu. Jak po każdej instrukcji i tu pojawił się średnik. Typ int (integer=całkowity) oznacza, że zmienna może przyjmować wartości z zakresu +/- 32767. Należy o tym pamiętać, jeżeli zamierzamy używać w programie dużych liczb (wtedy zamiast typu int używamy typu long). Teraz kompilator już wie, że w kodzie programu będą pojawiać się zmienne a i b i wie ile pamięci musi zarezerwować na ich przechowanie.

Następnie wypisujemy na ekranie komunikat, który prosi nas o wpisanie liczby. Program zatrzyma się w tym miejcu i będzie czekał dotąd, aż napiszemy liczbę i zatwierdzimy ję ENTERem. To co wpiszemy przechwyci z klawiatury funkcja scanf(). Zapis tej procedury wyglada dość skomplikowanie, ale w rzeczywistości wystarczy znac kilka tzw. wzorców konwersji. Wzorzec konwersji określa typ zmiennej, którą wpiszemy z klawiatury lub wypiszemy na ekranie. Należy zapamiętać kilka podstawowych wzorców. Poniższa tabela przedstawia deklaracje zmiennych określonego typu, odpowiednie dla nich wzorce konwersji oraz przykłady ich użycia:

typ zmiennej deklaracja wzorzec postaś funkcji scanf() postaś funkcji printf()
liczba całkowita int A %d scanf("%d",&A); printf("Liczba A wynosi: %d",A);
liczba rzeczywista float B %f scanf("%f",&B); printf("Liczba B wynosi: %f",B);
ciąg znaków char *C %s scanf("%s",&C); printf("Lańcuch ma postać: %s",C);
pojedynczy znak char D %c scanf("%c",&D); printf("Znak D to: %c",D);

Są oczywiście jeszcze inne wzorce, ale te są najważniejsze i na razie tylko tymi będziemy się zajmować.

Podsumowując:

1. Aby wczytać liczbę należy użyć funkcji scanf w postaci: scanf("wzorzec",&zmienna);
2. Aby wypisać wczytaną w ten sposób liczbę należy użyć funkcji printf, która służy do wypisywania komunikatów. Postać funkcji: printf("Komunikat wzorzec",zmienna);
3. W funkcji scanf zawsze przed nazwą zmiennej używamy znaku &, a nie robimy tego przy używaniu funkcji printf.

Jest coraz lepiej - program komunikuje się z nami, ale nadal jeszcze nic nie oblicza. Jest to jednak sprawa prosta. Teraz należy tylko zadeklarować kilka nowych zmiennych, które przechowają wyniki zamierzonych działań i wykonać określone działania. Modyfikujemy nasz program do postaci:

#include <stdio.h>
#include <conio.h>
main (void)
{
int a,b; //deklaracja zmiennych a i b
int suma,roznica,iloczyn;
float iloraz;
clrscr();
printf("Podaj liczbę A: \n");
scanf("%d",&a);
printf("Podaj liczbę B: \n");
scanf("%d",&b);

suma=a+b;
roznica=a-b;
iloczyn=a*b;
iloraz=a/b;

printf("Wyniki działań:\n");
printf("Suma: %d\n",suma);
printf("Różnica: %d\n",roznica);
printf("Iloczyn: %d\n",iloczyn);
printf("Iloraz: %f\n",iloraz);

getch();
return 0 ;
}

Jak widać zmienna nie musi być przedstawiana jako pojedyncza litera. Może to być również wyraz, ale należy zwracać uwagę na wielkość liter. Ekran powykonaniu programu może wyglądać tak:

Podaj liczbę A
21
Podaj liczbę B
8
Wyniki działań:
Suma: 29
Różnica: 13
Iloczyn: 168
Iloraz: 2.000000

Pierwsze trzy działania nie budzą żadnych zastrzeżeń. W końcu suma, różnica i iloczyn liczb całkowitych daje w wyniku również liczbę całkowitą. Ale rzadko się zdarza, aby również iloraz był liczbą całkowitą. Przewidzieliśmy to deklarując zmienną iloraz jako liczbę rzeczywistą, a nie całkowitą. Tymczasem komputer po podzieleniu liczby 21 przez 8 otrzymał w wyniku 2...

To nie jest żadna pomyłka. Operator / jest nazywany czasem operatorem dzielenia całkowitego, a więc bez reszty. Gdybyśmy wpisali zamiast / operator % uzyskalibyśmy wynik reszty z dzielenia. Ale nie znaczy to jednak, że uzyskanie wyniku 2,625 nie jest możliwe. Sekret tkwi w typie argumentów użytych do operacji dzielenia, czyli w typie zmiennych a i b. Gdybyśmy zadeklarowali je jako liczby rzeczywiste (a więc float a,bWink operacja dzielenia byłaby traktowana jako normalne dzielenie, a nie dzielenie całkowite.

Tak mogłoby już zostać, ale skoro pokusiliśmy się o zmianę typów wczytywanych liczb, warto zmienić również typ wyników wszystkich działań na rzeczywisty. Proszę jednak nie zapominać, po zmianach w deklaracji zmiennych, należy zmienić także wzorce konwersji z %d na %f!

Tak naprawdę wcale nie trzeba było deklarować osobnych zmiennych dla przedstawienia wyniku działan. Chodziło mi jednak o przedstawienie operacji przypisania (=). Funkcja printf umożliwia bowiem takie samo wyświetlenie wyniku przy następujacej konstrukcji: printf("Suma: %d",a+b);

Na koniec ostatnia rada przy używaniu liczb rzeczywistych. Nie zawsze zależy nam na tak dużej dokładności, aby znać aż 6 miejsc po przecinku. Zaokrąglić liczbę do mniej dokładnej możemy w bardzo prosty sposób. Przyda się nam do tego wzorzec konwersji, który należy trochę uzupełnić. Przekształćmy wzorzec w funkcji printf wyświetlającej wynik dzielenia z postaci %f na %.3f. Wydaje się to mało czytelne, ale spowoduje, że liczba przy wyświetleniu zostanie obcięta do 3 miejsc po przecinku.

Podsumowując:

1. Zmienna służy do przechowania danych, których wartość ustala się w trakcie działania programu i może być zmieniana.
2. Każda zmienna musi być zadeklarowana przed jej użyciem jako zmienna odpowiedniego typu (int, float itp.).
3. Do wypisywania komunikatów służy funkcja printf, a do wczytywania zmiennych funkcja scanf.
4. Do poprawnego użycia obu funkcji należy znać podstawowe wzorce konwersji (%d, %f, %s).



LEKCJA 3 - OPERACJE NA ŁAŃCUCHACH


Ostatnia lekcja była bardzo ważna. Poznałeś pojęcie zmiennej i podstawowe jej typy. Ta lekcja będzie pewnym uzupełnieniem, gdyż w poprzednich przykładach operowaliśmy tylko na liczbach. Konkretnie był to typ int (liczby całkowite) i float (liczby rzeczywiste). Zmienne tych typów mogą przyjmować wartości tylko z określonych przedziałów liczbowych. Dla prostych programów nie ma to większego znaczenia, ale dobrze jest wiedzieć, że te podstawowe zakresy są dosyć wąskie. Tak więc, zanim przejdziemy do operacji na łańcuchach znaków, krótkie podsumowanie typów liczbowych:

typ zmiennej zakres
int -32 768 do 32 767
long -2 147 483 648 do 2 147 483 647
float 3,4* 10^(-3Cool do 3,4*10^(3Cool
double 1,7* 10^(-308) do 1,7*10^(308)
long double 3,4* 10^(-4932) do 3,4*10^(4932)

Zapis 10^ oznacza "10 do potęgi". Należy więc zauważyć, że przy niektórych typach mamy bardzo szerokie możliwości. Warto jednak wiedzieć, że w różnych implementacjach języka typy te mogą nieco się różnić oferowanym zakresem lub nazywać się nieco inaczej (choć ja się z tym jeszcze nie spotkałam).

Zajmiemy się teraz typem znakowym, który będzie istotą tej lekcji. Jak wygląda deklaracja zmiennych tego typu już wiemy: char zmienna;. Wzorzec konwersji przy wyświetleniu lub wczytywaniu zmiennej typu char to %s dla łańcucha dłuższego niż 1 znak i %c dla łańcucha jednoznakowego.

Pora na przykład:

#include <stdio.h>
#include <conio.h>
#include <string.h>
main (void)
{
char znak1,znak2,znak3; //deklaracja znaków
char *slowo1, *slowo2; //deklaracja słów
clrscr();
znak1='a';
znak2=102;
slowo1="Anna";

printf("Podaj znak3: \n");
scanf("%c",&znak3);

printf("Podaj slowo2: \n");
scanf("%s",&slowo2);

printf("Zmienne zawierają:\n");
printf("znak1, znak2,znak3: %c %c %c\n",znak1,znak2,znak3);
printf("słowo1, słowo2: %s %s\n",slowo1, slowo2);

getch();
return 0 ;
}

A oto przykładowa zawartość ekranu po wykonaniu programu:

Podaj znak3
q
Podaj slowo2
programowanie
Zmienne zawierają:
znak1, znak2, znak3: a f q
slowo1, slowo2: Anna programowanie

W przykładzie widoczne są niewielkie różnice pomiędzy deklaracją i przypisywaniem wartości łańcuchom jedno- i wieloznakowym. Tak więc, przypisać wartość zmiennej jednoznakowej możemy na kilka sposobów:

* w apostrofach: zmienna='a';
* poprzez przypisanie kodu znaku: zmienna=97;
* poprzez wczytanie znaku z klawiatury funkcją scanf(): scanf("%c",&zmienna);

Szerszego omówienia wymaga jedynie drugi sposób. Otóż każdy znak widoczny na klawiaturze posiada swój kod (tzw. kod ASCII). Zamiast podawać określony znak w apostrofach można zatem podać tylko jego kod. Wydaje się to utrudnieniem, ale istnieją znaki, których nie ma na klawiaturze lub trudno je określić jednym znakiem (np. enter, escape, klawisze funkcyjne, kursory itp). Wtedy bez znajomości ich kodu nie da się ich opisać w programie. Użyty w przykładzie kod 102 dotyczy literki "f". Dokladny opis kodów znajdziesz tutaj.

Przypisanie wartości do zmiennej dla łańcucha dłuższego niż jeden znak odbywa się podobnie jak w pierwszym przypadku, z tą jednak różnicą, że zamiast apostrofów (') należy używać cydzysłowia ("). Prawda, że proste?

Podsumowując:

1. Zmienne liczbowe mogą zawierać się w pewnych zakresach, których nie można przekraczać.
2. Deklaracja zmiennej znakowej wygląda tak: char znak; a zmiennej łańcuchowej tak: char *slowo;
3. Wartość zmiennej znakowej można przypisać w programie poprzez umieszczenie znaku w apostrofach lub przez napisanie jego kodu.
4. Wartość zmiennej łańcuchowej można przypisać w programie poprzez umieszczenie wyrazu (lub kilku wyrazów) w cudzysłowie.
5. Zmienne znakowe i łańcuchowe można wczytywać z klawiatury używając funkcji scanf i odpowiednich wzorców konwersji (%s dla ciągu znaków i %c dla pojedynczego znaku).
6. Każdy znak posiada swój kod ASCII.
7. Kod ASCII mają również znaki nie przedstawione na klawiaturze komputera. np. ß, ö, à.

Wracając jeszcze na chwilę do tematu kodów, napiszmy prosty program, który sprawdzi kod wciśniętego przez nas klawisza:

#include <stdio.h>
#include <conio.h>
#include <string.h>
main (void)
{
char znak;
int kod;
clrscr();

printf("Wciśnij znak na klawiaturze: \n");
scanf("%c",&znak);
printf("Kod wciśniętego znaku to: %d \n",znak);

printf("Podaj kod znaku: \n");
scanf("%d",&kod);
printf("Znak o podanym kodzie to: %c \n",kod);

getch();
return 0 ;
}

Przykładowa zawartość ekranu po wykonaniu programu:

Wciśnij znak na klawiaturze:
a
Kod wciśniętego znaku to: 97
Podaj kod znaku: 100
Znak o podanym kodzie to: d

Program ten jest bardzo dobrym przykładem na poznanie kodów używanych znaków i jednocześnie na użycie wzorców konwersji. Zauważmy, że wczytując znak funkcją scanf() używamy wzorca %c, ale żeby odczytać jej kod wystarczy w następnym komunikacie zmienić wartość wzorca na %d (pomimo, że zmienna znak jest typu char!).

Analogicznie sprawa się ma, jeżeli chcemy poznać znak odpowiadający danemu kodowi. Funkcją scanf() wczytujemy kod (używając wzorca %d), a w następnym komunikacie zmieniamy wzorzec na %c i w ten sposób uzyskujemy szukany znak.

Tak więc natura zmiennych znakowych jest jakby dwoista. Nie można powiedzieć tego o innych zmiennych - dla nich obowiązują tylko pojedyncze wzorce (łańcuch ma zawsze wzorzec %s, liczba całkowita ma zawsze wzorzec %d itd).

I jeszcze jedna mała uwaga: zauważmy, że liczby mogą być traktowane i jako liczby całkowite i jako łańcuchy znaków, ale NIE jednocześnie! Znaczy to, ze musimy z góry określić typ zmiennej, choć jej wartości będą na pozór identyczne. Na pozór, ponieważ a="123"; i a=123; to dwa różne przypisania. W pierwszym przypadku zmienna a jest to ciąg znaków, a w drugim jest to liczba.

To jeszcze nie wszystko co należy wiedzieć o łańcuchach.

Łańcuch nie musi być jednym słowem - może stanowić nawet całe zdanie, jednakże długość tego łańcucha nie może przekroczyć pewnej (dosyć sporej) ilości znaków. Pozostałe znaki zostaną zignorowane. A jak odczytać długość podanego łańcucha? Służy do tego funkcja strlen(). Przykład:

#include <stdio.h>
#include <conio.h>
#include <string.h>
main (void)
{
int dlugosc;
char *lancuch;
clrscr();

lancuch="Anna Miedzianowska";
dlugosc=strlen(lancuch);
printf("Łańcuch '%s' ma: %d znaków \n",lancuch, dlugosc);

printf("Pierwsza litera łańcucha to: %c \n",lancuch[0]);
printf("Ostatnia litera łańcucha to: %c \n",lancuch[dlugosc-1]);
printf("A ostatni znak łańcucha to: %c \n",lancuch[dlugosc]);

getch();
return 0 ;
}

Przykładowa zawartość ekranu po wykonaniu programu:

Lancuch 'Anna Miedzianowska' ma: 18 znaków
Pierwsza litera lancucha to: A
Ostatnia litera lancucha to: a
A ostatni znak lancucha to:


Używając funkcji strlen(), której argumentem był nasz łańcuch sprawdziliśmy jego długość. Wszystko okazało się zgodne z prawdą, łańcuch ten ma 18 znaków (licząc ze spacją, która też jest znakiem, mimo, że jej nie widać). Udało nam się także odczytać poszczególne litery łańcucha posługując się nawiasami kwadratowymi dopisanymi do nazwy zmiennej. Zapewne zdziwiło Cię to, że znak numer 18 łańcucha to nie jest 'a', lecz dziwny kwadrat, a nic takiego przecież nie wpisywaliśmy. Otóż w języku C w wielu przypadkach liczenie zaczyna się od zera, a nie od jedynki. Dlatego właśnie na pierwszy znak łańcucha wskazuje odwołanie: lancuch[0], na drugi: lancuch[1] itd. Co kryje się więc za pojęciem lancuch[18]? Ostatni znak łańcucha jest to zawsze znak \0. Wskazuje on na koniec łańcucha. Nie musisz się tym przejmować, ale zapamiętaj, że liczenie znaków zaczynamy zawsze od zera!

Potrafisz już odczytywać poszczególne znaki łańcucha. Posługując się operacją przypisania w prosty sposób można zmienić poszczególne znaki. Np. gdyby po przypisaniu tekstu "Anna Miedzianowska" do zmiennej lancuch napisać: lancuch[2]='i'; to nasza zmienna przechowywałaby już tekst "Ania Miedzianowska". W ten sposób można zmienić dowolną literę w łańcuchu.

Przy bardziej skomplikowanych zmiennych, zwłaszcza przy tworzeniu rekordów, ważne jest, aby nie szastać zbyt pamięcią przydzielaną dla zmiennych przy ich deklaracji. Nie znaczy to, że nie można deklarować zbyt dużo zmiennych. Chodzi raczej o to, by bliżej określić ich zawartość. Np. jeżeli do programu będziemy wczytywali imiona naszych znajomych, to z góry można przewidzieć, że zmienne te nie będą zawierały więcej niż 15 liter. Deklaracja ograniczonego łańcucha wygląda następująco: char lancuch[15];. Powrócimy do tego tematu w lekcjach dotyczących rekordów.

Jest wiele funkcji podobnych do strlen(), które potrafią działać na łańcuchach. Ciekawsze z nich to:
strcat() - łączy dwa łańcuchy,
strcmp() - porównuje dwa łańcuchy rozróżniając małe i duże litery,
strlwr() i strupr() - zamienia w danym łańcuchu duże litery na małe i odwrotnie,
strrev() - odwraca kolejność znaków w łańcuchu,
strset() - wypełnia łańcuch danym znakiem.

Użycie tych funkcji przedstawia następny przykład:

#include <stdio.h>
#include <conio.h>
#include <string.h>
main (void)
{
char *lancuch1, *lancuch2, *lancuch3;
clrscr();
lancuch1="Anna";
lancuch2="Miedzianowska";

printf("Lancuch1 to: %s \n",lancuch1);
printf("Lancuch2 to: %s \n",lancuch2);

printf("\nZmieniamy duze litery na male: \n");
strlwr(lancuch1);
printf("Lancuch1 wyglada teraz tak: %s \n",lancuch1);

printf("\nZmieniamy male litery na duze: \n");
strupr(lancuch2);
printf("Lancuch2 wyglada teraz tak: %s \n",lancuch2);

printf("\nLaczymy dwa lancuchy: \n );
lancuch3=strcat(lancuch1,lancuch2);
printf("Lancuch3 wyglada teraz tak: %s \n",lancuch3);

printf("\nOdwracamy kolejnosc znakow w lancuchu: \n );
strrev(lancuch3);
printf("Lancuch3 wyglada teraz tak: %s \n",lancuch3);

printf("\nWypelniamy lancuch znakiem 'i':\n );
strset(lancuch3,i);
printf("Lancuch3 wyglada teraz tak: %s \n",lancuch3);

getch();
return 0 ;
}

A oto wygląd ekranu po wykonaniu programu:

Lancuch1 to: Anna
Lancuch2 to:
Miedzianowska

Zmieniamy duze litery na male:
Lancuch1 wyglada teraz tak: anna

Zmieniamy male litery na duze:
Lancuch2 wyglada teraz tak: MIEDZIANOWSKA

Laczymy dwa lancuchy:
Lancuch3 wyglada teraz tak: annaMIEDZIANOWSKA

Odwracamy kolejnosc znakow w lancuchu
Lancuch3 wyglada teraz tak: AKSWONAIZDEIManna

Wypelniamy lancuch znakiem 'i':
Lancuch3 wyglada teraz tak: iiiiiiiiiiiiiiiii

Podsumowując:

1. Łańcuch, który wygląda jak liczba nie jest nią! Istnieją aczkolwiek funkcje, które potrafią przekonwertować łańcuch liczbowy do postaci liczby.
2. Mając dany łańcuch, możemy odczytać dowolny jego znak używając nawiasów kwadratowych. Pierwszy wpisany znak ma numer 0, a nie 1.
3. Każdy ciąg kończy znak '\0'.
4. Długość łańcucha można ograniczyć przy deklaracji, np.: char slowo[10];
5. Łańcuchy można ze sobą porównywać, łączyć, odwracać w nich kolejność liter, zmieniać małe litery na duże i odwrotnie, a także przeszukiwać, kopiować na siebie itp. Nazwy funkcji, które to wykonują zawsze zaczynają się na 'str' (z angielskiego: string - łańcuch).



LEKCJA 4 - STRUKTURY IF-ELSE, SWITCH-CASE I GOTO


Poznałeś już podstawowe typy zmiennych i niektóre sposoby ich użycia. Do omówienia pozostały nam jeszcze tablice i rekordy, ale ponieważ nie znasz jeszcze pętli, temat ten może wydać się dosyć nudny. Dlatego w tej lekcji zajmiemy się omówieniem instrukcji warunkowych i skoków.

Często zdarza się, że pisząc program należy rozważyć kilka możliwości. Na przykład, wykonując operację dzielenia, trzeba najpierw sprawdzić, czy liczba, przez którą dzielimy, nie jest przypadkiem równa zero. Gdyby okazało się, że jest, zamiast podzielić liczby należałoby wystosować odpowiedni komunikat, np.: "nie wolno dzielić przez zero!".

Podobną sytuację przedstawia sposób obliczania pierwiastków równania kwadratowego. Bo jeśli delta jest mniejsza od zera, to nie istnieją pierwiastki rzeczywiste! Na pierwszy rzut oka widać, że należy rozpatrzyć przynajmniej 3 różne możliwości (delta<0, delta=0, delta>0).

Wszystkie te możliwości można rozpatrzyć przy pomocy instrukcji if().

Zajmiemy się teraz pierwszym przykładem: sprawdzeniem czy liczby można przez siebie podzielić.

#include <stdio.h>
#include <conio.h>
main (void)
{
int liczba1,liczba2;
clrscr();

printf("Podaj pierwszą liczbę: \n");
scanf("%d",&liczba1);

printf("Podaj drugą liczbę: \n");
scanf("%d",&liczba2);

if (liczba2==0)
printf("Nie wolno dzielić przez 0!\n");
else
printf("Wynik dzielenia: %d\n",liczba1/liczba2);

getch();
return 0 ;
}

Po wykonaniu programu ekran może mieć zawartość:

Podaj pierwszą liczbę
12
Podaj drugą liczbę
3
Wynik dzielenia: 4

lub:

Podaj pierwszą liczbę
15
Podaj drugą liczbę
0
Nie wolno dzielić przez 0!

Jak widać, struktura instrukcji if() ma postać:

if (warunek) instrukcja1;
else instrukcja2;

Znaczy to:
Jeżeli (warunek) jest spełniony, to wykonaj instrukcję1.
W innym przypadku (jeśli warunek ten nie jest spełniony), wykonaj instrukcję2.

Warunek logiczny to taki, na który można opdowiedzieć "tak" lub "nie". Warunek na to, czy jedna liczba jest większa od drugiej można zapisać następująco: if (liczba1<liczba2)

W powyższym programie mamy jednak do czynienia z przypadkiem porównywania dwóch liczb w sensie sprawdzenia czy są one sobie równe. Operację takiego porównania zapisujemy w postaci dwóch znaków '=': if (liczba2 == 0)

Jest bardzo ważne, aby umieć odróżnić operację przypisywania od operacji porównywania, zwłaszcza, że gdybyśmy w instrukcji if powyższego programu napisali: (liczba2=0) zamiast (liczba2==0), kompilator nie wskazałby tego jako błąd. Program uruchomiłby się bez problemu, ale nie działałby prawidłowo!

Po napisaniu warunku należy napisać, co program w danym przypadku powinien zrobić. Często się zdarza, że dla danego przypadku program powinien wykonać więcej niż jedną instrukcję. Wtedy wszystkie te instrukcje należy zgrupować poprzez zastosowanie nawiasów klamrowych:

if (warunek)
{
instrukcja1;
instrukcja2;
instrukcja3;
}

Jeżeli o tym zapomnimy, po spełnieniu warunku zostanie wykonana tylko pierwsza instrukcja, a pozostałe zostaną wykonane niezależnie od spełnienia warunku. Warto też zapamiętać, że po napisaniu warunku nie stawiamy średnika (stawiamy go dopiero po napisaniu instrukcji do wykonania). Jeżeli i o tym zapomnimy, w momencie spełnienia określonego warunku program wykona tzw. pustą instrukcję, czyli po prostu nic nie zrobi.

Jak widać, strukturę z przykładu można pozbawić możliwości rozpatrywania drugiego przypadku (else...). Wtedy jednak cała ta nasza procedura zareaguje tylko w określonym (jednym) przypadku. Na przykład można sprawdzić warunek następująco:

if (liczba2!=0)
printf("Liczby można przez siebie podzielić");

Z reguły jednak rozpatruje się zawsze kilka przypadków, a nie jeden lub dwa. Jak to zrobić? Weźmy pod uwagę przypadek szukania pierwiastków dwumianu:

#include <stdio.h>
#include <conio.h>
main (void)
{
float A,B,C,delta;
clrscr();

printf("Podaj współczynnik A: \n");
scanf("%f",&A);
printf("Podaj współczynnik B: \n");
scanf("%f",&B);
printf("Podaj współczynnik C: \n");
scanf("%f",&C);

delta=b*b-4*a*c;

if (delta<0)
printf("Nie istnieją pierwiaski rzeczywiste!\n");
if (delta==0)
printf("Istnieje jeden pierwiastek rzeczywisty.\n");
if (delta>0)
printf("Istnieją dwa pierwiaski rzeczywiste.\n");

getch();
return 0 ;
}

Przy tak napisanym kodzie program sprawdzi wszystkie trzy podane warunki, niezależnie od tego, czy poprzedni warunek został spełniony czy też nie. Gdyby jednak w stosownych miejsach umieścić instrukcję else, program sprawdziłby najpierw pierwszy warunek. Gdyby nie był on spełniony program sprawdziłby drugi warunek, a kiedy ten również nie byłby spełniony program sprawdziłby trzeci warunek. Wydaje się to właściwie bez różnicy, ale jeżeli warunków do sprawdzenia jest 50 i pierwszy z nich jest spełniony, to po co sprawdzać następne 49? To straszne marnotrawienie czasu. Poprawmy więc nasz program do postaci:

#include <stdio.h>
#include <conio.h>
main (void)
{
float A,B,C,delta;
clrscr();

printf("Podaj współczynnik A: \n");
scanf("%f",&A);
printf("Podaj współczynnik B: \n");
scanf("%f",&B);
printf("Podaj współczynnik C: \n");
scanf("%f",&C);

delta=b*b-4*a*c;

if (delta<0)
printf("Nie istnieją pierwiaski rzeczywiste!\n");
else
if (delta==0)
printf("Istnieje jeden pierwiastek rzeczywisty.\n");
else
printf("Istnieją dwa pierwiaski rzeczywiste.\n");

getch();
return 0 ;
}

Jak widać, ostatnią instrukcję if można było usunąć, ponieważ nie istnieje więcej możliwych przypadków na znak delty niż trzy. Warunek logiczny nie musi być warunkiem pojedynczym. Można łączyć ze sobą kilka warunków w jedną całość zamiast dla każdego używać osobnej instrukcji if. Na przykład, zamiast pisać:

if (warunek1)
if (warunek2)
printf("komunikat");

można napisać:

if ((warunek1)&&(warunek2)) printf("komunikat");

W obu przypadkach komunikat zostanie wyświetlony, jeśli obydwa warunki zostaną spełnione, jednakże w drugim przypadku kod jest bardziej elastyczny. Operator && (logiczne I) można zmienić do postaci || (logiczne lub):

if ((warunek1)||(warunek2)) printf("komunikat");

Wtedy wystarczy, aby tylko jeden warunek był spełniony, aby program wypisał komunikat. Wyrażenia takie można łączyć w bardziej skomplikowane, jednakże całość zawsze należy ująć w okrągły nawias.

Podsumowując:

1. Jeżeli do rozpatrzenia mamy kilka przypadków, stosujemy instrukcję warunkową if.
2. Instrukcję zapisujemy: if (warunek) instrukcja1; else instrukcja2.
3. Dla więcej niż jednej instrukcji należy zgrupować je za pomocą nawiasów klamrowych.
4. W warunku logicznym instrukcji if zawsze stosujemy operator porównania (==), a nie przypisania (=).
5. Jeśli jednocześnie powinno być sprawdzone kilka warunków, łączymy je za pomocą operatorów logicznych.

Jeżeli chcemy sprawdzić więcej warunków struktura if ... else ... może się bardzo skomplikować. W takim przypadku lepiej jest użyć instrukcji case(). Zakłada ona z góry, że sprawdzeniu ulegnie sporo warunków. Strukturę instrukcji case pokaże następny przykład:

#include <stdio.h>
#include <conio.h>
main (void)
{
char znak;
clrscr();

printf("Wciśnij cyfrę od 0 do 5\n");
scanf("%c",&znak);
switch(znak)
{
case '0': pritntf("nacisnąłeś klawisz 0");break;
case '1': pritntf("nacisnąłeś klawisz 1");break;
case '2': pritntf("nacisnąłeś klawisz 2");break;
case '3': pritntf("nacisnąłeś klawisz 3");break;
case '4': pritntf("nacisnąłeś klawisz 4");break;
case '5': pritntf("nacisnąłeś klawisz 5");break;
default: pritntf("nacisnąłeś jakiś inny klawisz");
}

getch();
return 0 ;
}

Oczywiście pisanie reakcji na wciśnięty klawisz ma sens przy bardziej złożonych programach (np. bazach danych). Funkcja ta spełnia często rolę menu - w zależności od tego jaki klawisz naciśniemy, wykonywana jest określona część programu. Na przykład jeśli wciśniemy klawisz 1 dopiszemy dane do bazy, a jeśli naciśniemy klawisz 2 to wyświetlimy bazę na ekranie itp.

Struktura case jest bardzo prosta i w zasadzie nawet bardziej czytelna od if (dla dużej ilości warunków). Rozpoczynamy ją sółwkiem switch i w nawiasie piszemy nazwę zmiennej, której wartości będziemy rozpatrywać. Wszystkie możliwe przypadki ujmujemy w nawias klamrowy. Każdy przypadek rozpoczynamy od słowa case, następnie piszemy określoną dla tego przypadku wartość, a za tym stawiamy dwukropek. Dalej wypisujemy wszystko, co program ma zrobić w danym przypadku i jeżeli nie chcemy, aby program sprawdzał następne możliwości, kończymy to słowem break. Powoduje to wyjście z całej struktury switch-case i wykonywanie dalszych instrukcji w programie.

Podobnie jak else w przypadku instrukcji if, tak i tu możemy jednocześnie określić "wszystkie pozostałe przypadki". Służy do tego określenie default, po którym definiujemy, co program ma zrobić, jeżeli określone wcześniej przypadki nie zdarzyły się. Strukturę tą najlepiej pokazuje powyższy przykład, więc zamiast zagłębiać się w opis, proponuję przeanalizować dokładniej treść programu.

Podsumowując:

1. Instrukcję if stosujemy dla mniejszej ilości warunków do sprawdzenia, lub dla bardziej skomplikowanych warunków (wtedy stosujemy operatory logiczne np. && lub ||).
2. Instrukcję case stosujemy dla dużej ilości prostych warunków.
3. Określenia else (w instrukcji if) i default (w instrukcji case) znaczą: "dla pozostałych przypadków"

Przy omawianiu instrukcji switch-case należy wspomnieć również o instrukcji skoku: goto. Jest to bardzo przydatna instrukcja przy skomplikowanych programach. Powróćmy do naszego przykładu z instrukcją case. Po naciśnięciu odpowiedniego klawisza zostaje wykonana odpowiednia instrukcja. A gdybyśmy chcieli, żeby wykonana została nie jedna czy dwie instrukcje, a 20? Można oczywiście wypisywać je jedna po drugiej, ale kod szybko straciłby na czytelności. Można się więc posłużyć instrukcją skoku, aby program na chwilę przeszedł do innego miejsca kodu, wykonał to co jest tam napisane i z powrotem powrócił do miejsca początkowego. Jak oznaczyć miejsce, do którego program ma wyskoczyć? Służą do tego etykiety. Zmodyfikujmy nasz przykład:

#include <stdio.h>
#include <conio.h>
main (void)
{
char znak;
clrscr();

[link widoczny dla zalogowanych] jest etykieta o nazwie jeszcze_raz
printf("Wciśnij cyfrę od 0 do 5\n");
scanf("%c",&znak);
switch(znak)
{
case '0': goto koniec; break;
case '1': goto jeden; break;
case '2': pritntf("nacisnąłeś klawisz 2"); goto koniec; break;
case '3': pritntf("nacisnąłeś klawisz 3"); goto koniec; break;
case '4': pritntf("nacisnąłeś klawisz 4"); goto koniec; break;
case '5': goto jeszcze_raz;break;
default: pritntf("nacisnąłeś jakiś inny klawisz");
}
[link widoczny dla zalogowanych] jest etykieta o nazwie jeden
instrukcja1;
instrukcja2;
instrukcja3;
instrukcja4;
...
instrukcja5;
instrukcja6;
instrukcja7;

koniec: //to jest etykieta o nazwie koniec

getch();
return 0 ;
}

Działanie tego programu jest bardzo proste:
wciśnij klawisz => jaki klawisz został wciśnięty? =>
jeśli 0 => idź do etykiety 'koniec' i zacznij wykonywać wszystko od tego miejsca;
jeśli 1 => idź do etykiety 'jeden' i zacznij wykonywać wszystko od tego miejsca;
jeśli 2 => napisz komunikat a potem idź do etykiety 'koniec' i zacznij wykonywać wszystko od tego miejsca;
jeśli 3 => napisz komunikat a potem idź do etykiety 'koniec' i zacznij wykonywać wszystko od tego miejsca;
jeśli 4 => napisz komunikat a potem idź do etykiety 'koniec' i zacznij wykonywać wszystko od tego miejsca;
jeśli 5 => idź do etykiety 'jeszcze_raz' i zacznij wykonywać wszystko od tego miejsca;

Podsumowując:

1. Instrukcja goto jest to instukcja skoku do pewnego miejsca w kodzie programu.
2. Miejsce skoku należy oznaczyć odpowiednią etykietą.
3. Za pomocą goto można robić pętle programowe lub szybko skończyć jego działanie.



LEKCJA 5 - TABLICE I REKORDY


W tej lekcji wrócimy do operowania zmiennymi. Znasz już podstawowe typy (int, float, char) i umiesz przechowywać je w pamięci. Dla każdej nowej zmiennej deklarowałeś nazwę i przypisywałeś ją do określonego typu. Niedługo zaczniesz pisać programy bardziej skomplikowane, w których będziesz używał wielu zmiennych. Deklarowanie każdej z nich z osobna okaże się wtedy zupełnie niepraktyczne.

Dlatego poznasz dziś tablice. Tablica jest to uporządkowany zbiór wielu zmiennych jednego typu. Typ tych zmiennych określa typ tablicy. Na przykład, jeśli w tablicy będziemy przechowywać liczby typu int, to tablica też jest typu int. Uporządkowanie tablicy oznacza, że jej elementy nie są przechowywane w niej ot tak, lecz każdy ma swoje miejsce.

Deklaracja i proste użycie tablicy wygląda tak:

#include <stdio.h>
#include <conio.h>
main (void)
{
int tablica[5];
int suma;
clrscr();

printf("Podaj pierwszą liczbę: \n");
scanf("%d",&tablica[0]);


printf("Podaj drugą liczbę: \n");
scanf("%d",&tablica[1]);

printf("Podaj trzecią liczbę: \n");
scanf("%d",&tablica[2]);

tablica[3]=5;
tablica[4]=23;

suma=(tablica[0]+tablica[1]+tablica[2]+tablica[3]+tablica[4]);

printf("Suma elementów tablicy wynosi: %d\n",suma);

getch();
return 0 ;
}

Jak łatwo zauważyć, deklaracja tablicy wygląda prawie identycznie jak deklaracja łańcucha (tak naprawdę jest jednak odwrotnie, bo to łańcuch był traktowany jako tablica znaków). Należy w niej jednak zaznaczyć ilość elementów znajdujących się później w tablicy. Nie musimy używać ich wszystkich, lecz np. pierwsze trzy, ale zawsze należy określić ich ilość i dopilnować, aby tej granicy nie przekroczyć. Inaczej mówiąc, jeśli na samym początku zadeklarujemy tablicę: int tablica[10], to nie możemy potem używać elementu tablica[11]. Zauważmy również, że zliczanie elementów tablicy zaczynamy od elementu numer zero. Dlatego tablica w powyższym przykładzie jest tablicą pięcioelementową, zawiera bowiem elementy o numerach: 0,1,2,3,4.

Nasz przykładowy program oblicza sumę z elementów tablicy. Elementy te można wczytać z klawiatury dzięki funkcji scanf() lub też przypisać im wartość w kodzie programu. Ponieważ wszystkie elementy tablicy są typu int, zatem tablica ta też jest typu int. Nie może się zdarzyć, że jeden z elementów byłby innego typu.

Przedstawiona tu tablica była niewielka, ale można też tworzyć większe tablice. Oprócz tego można również używać tablic dwu- i więcej wymiarowych. Tablica dwuwymiarowa w zasadzie nie różni się od układu współrzędnych kartezjańskich. Deklaracja tablicy dwuwymiarowej może wyglądać tak: int tablica[9][9];. Znaczy to, że tablica ma w sumie 100 elementów (np. 10 wierszy i 10 kolumn). Odwołanie do któregoś z elementów tej tablicy zapisujemy np. tablica[nr_kolumny][nr_wiersza] (choć, wydaje się, ze powinno być na odwrót, ale jest właśnie tak). Elementu tablicy możemy używać tak jak każdej innej zmiennej. Np. jeśli tablica zawiera liczby można napisać: a=9*tablica[3][1]+5;.

W rzeczywistości zdarza się jednak często, że potrzebujemy przechować w pamięci dane różnych typów, jednakże w wielu kopiach. Na przykład tworzymy bazę danych z informacjami na temat uczniów w jakiejś klasie. O każdej osobie potrzebujemy zapamiętać jego imię, nazwisko, numer w dzienniku i średnią. Widać więc, że wszystkie te dane nie mogą być jednego typu (imię i nazwisko - typ char*, numer - typ int, średnia - typ float). Oczywiście można stworzyć cztery tablice określonych typów, i w każdej z nich przechowywać określone informacje, np. w pierwszej imiona, w drugiej nazwiska itp. Jest to jednak niezbyt praktyczne wyjście, ponieważ łatwo poplątać informacje o każdej z osób.

Do rozwiązania tego problemu służą rekordy. Zbierają one w całość informacje różnych typów.

#include <stdio.h>
#include <conio.h>
main (void)
{
struct {
char *imie, *nazwisko;
int numer;
float srednia;
}uczen[30];

clrscr();

uczen[0].imie="Anna";
uczen[0].nazwisko="Miedzianowska";
uczen[0].numer=1;
uczen[0].srednia=4.5;

uczen[0].imie="Jan";
uczen[0].nazwisko="Kowalski";
uczen[0].numer=2;
uczen[0].srednia=4.0;

printf("Imię pierwszej osoby to %s.\n",uczen[0].imie);

printf("Nazwisko pierwszej osoby to %s.\n",uczen[0].nazwisko);

printf("Średnia drugiej osoby to %.2f.\n",uczen[0].srednia);

getch();
return 0 ;
}

Po uruchomieniu program napisze:

Imię pierwszej osoby to Anna.
Nazwisko pierwszej osoby to Miedzianowska.
Średnia drugiej osoby to 4.00

Rekord deklarujemy jak każdą inną zmienną. Deklarację rekordu rozpoczynamy słówkiem struct. Następnie między nawiasami klamrowymi deklarujemy zmienne wchodzące w skład rekordu. Nazywa się to polami rekordu. Po zamknięciu nawiasu klamrowego piszemy nazwę rekordu. Może to być pojedynczy rekord postaci:

struct{
int zmienna1;
float zmienna2;
char zmienna3;
}nazwa;

Takich rekordów możemy zadeklarować kilka lub też utworzyć zbiór takich samych rekordów w postaci tablicy (tak, jak w przykładzie). Pojedynczy rekord jest więc traktowany jako pojedyncza zmienna. Ta zmienna mówi nam jednak o wiele więcej niż pojedyncza zmienna typu np. int. Rekordy zebrane w tablicy deklaruje się na zasadzie:

struct{
int zmienna1;
float zmienna2;
char zmienna3;
}nazwa[ilosc_pol];

A jak odczytać wartości zapisane do rekordu? Nie można wypisać wartości rekordu (np. w funkcji printf), jeśli nie określimy pola, o które nam chodzi. Znaczy to, nie możemy zapytać programu jednocześnie o cały rekord numer1, ale możemy zapytać o każde z pól rekordu numer1. Uściślenie, o jakie pole nam chodzi następuje po napisaniu nazwy tablicy rekordów, numeru rekordu w nawiasie kwadratowym, a następnie po kropce wypisaniu nazwy interesującego pola. Tak właśnie zrobiliśmy w naszym przykładzie.

Podsumowując:

1. Tablica jest to uporządkowany zbiór elementów tego samego typu.
2. Zliczanie elementów zaczynamy od 0.
3. Numer elementu w tablicy umieszczamy za nazwą tablicy w nawiasie kwadratowym.
4. Rekord to powiązanie kilku zmiennych różnego typu w jedną całość.
5. Możemy tworzyć tablice, które jako swoje elementy przechowują rekordy.
6. Przy odwołaniu do elementu takiej tablicy należy sprecyzować konkretne pole rekordu.



LEKCJA 6 - PĘTLE FOR, WHILE I DO-WHILE


Znasz już podstawowe typy zmiennych i umiesz używać rekordów. Wiesz zatem już prawie wszystko o pisaniu bazy danych. Brakuje Ci jeszcze tylko niewielkiej informacji o tym, jak zoptymalizować operacje na wielu rekordach jednocześnie. W przykładzie wykorzystamy typ rekordowy uczen poznany na poprzedniej lekcji. Spróbujmy wpisać do bazy informacje o wszystkich uczniach:

#include <stdio.h>
#include <conio.h>
main (void)
{
struct {
char *imie, *nazwisko;
int numer;
float srednia;
}uczen[29];

clrscr();

printf("Podaj imię pierwszej osoby\n");
scanf("%s",&uczen[0].imie);
printf("Podaj nazwisko pierwszej osoby\n");
scanf("%s",&uczen[0].nazwisko);
printf("Podaj numer pierwszej osoby\n");
scanf("%d",&uczen[0].numer);
printf("Podaj średnią pierwszej osoby\n");
scanf("%f",&uczen[0].srednia);

printf("Podaj imię drugiej osoby\n");
scanf("%s",&uczen[1].imie);
printf("Podaj nazwisko drugiej osoby\n");
scanf("%s",&uczen[1].nazwisko);
printf("Podaj numer drugiej osoby\n");
scanf("%d",&uczen[1].numer);
printf("Podaj średnią drugiej osoby\n");
scanf("%f",&uczen[1].srednia);

printf("Podaj imię trzeciej osoby\n");
scanf("%s",&uczen[2].imie);
printf("Podaj nazwisko trzeciej osoby\n");
scanf("%s",&uczen[2].nazwisko);
printf("Podaj numer trzeciej osoby\n");
scanf("%d",&uczen[2].numer);
printf("Podaj średnią trzeciej osoby\n");
scanf("%f",&uczen[2].srednia);

getch();
return 0 ;
}

Jak widać, wypisanie zapytania o dane trzech pierwszych uczniów jest pracochłonne i sporo wydłuża kod programu. Gdybyśmy zapytali się o każdego z trzydziestu uczniów, kod wydłużyłby się niemiłosiernie. Łatwo byłoby się w nim zagubić.

Istnieje prosty sposób, aby czynności wykonywane wiele razy zgrupować. Służy do tego pętla for. Pozwala ona powtórzyć pewne czynności określoną ilość razy. Dla naszej bazy czynność zapytania o imię czy nazwisko musi powtórzyć się 30 razy. Gdyby nie pętla for byłoby to bardzo pracochłonne przedsięwzięcie.

Ponieważ pętla ma powtórzyć pewien ciąg instrukcji wiele razy, musimy utworzyć pewien licznik, który zliczy ile razy zadanie zostało już wykonane. Przy użyciu instrukcji for i licznika będzie więc trzeba zaznaczyć pewne warunki:

* jak nazywa się licznik, który zlicza kolejne wykonanie
* dla jakiej wartości licznika pętla ma się zakończyć
* o jaką wartość będziemy zwiększać licznik
* jakie instrukcje mają być powtarzane

Zmodyfikujmy teraz nasz poprzedni program:

#include <stdio.h>
#include <conio.h>
main (void)
{
int licznik;
struct {
char *imie, *nazwisko;
int numer;
float srednia;
}uczen[29];

clrscr();

for(licznik=0;licznik<=29;licznik++)
{
printf("Podaj imię osoby nr: %d\n",licznik);
scanf("%s",&uczen[licznik].imie);
printf("Podaj nazwisko osoby nr %d\n",licznik);
scanf("%s",&uczen[licznik].nazwisko);
printf("Podaj numer osoby nr %d\n",licznik);
scanf("%d",&uczen[licznik].numer);
printf("Podaj średnią osoby nr %d\n",licznik);
scanf("%f",&uczen[licznik].srednia);
}

getch();
return 0 ;
}

Użyliśmy zapisu: for(licznik=0;licznik<=29;licznik++) {instrukcje...}. Tak dosłownie tłumaczy się ten zapis:

* zmienna sterująca użyta przez nas do zliczania wykonań pętli ma nazwę licznik
* zaczyna on zliczać od wartości 0
* pętla ma się wykonywać, kiedy licznik pokazuje wartość mniejsza lub równa 29
* licznik ma się zwiększać o 1 po każdorazowym wykonaniu pętli
* instrukcje, które mają się powtarzać, ujęte są w nawias klamrowy (jeżeli byłaby to jedna instrukcja, nawias można by pominąć).

Tak napisany program 30 razy zapyta nas o te same dane różnych osób i przypisze je do wirtualnej bazy. Jako ćwiczenie proponuję dokończyć program: użyć pętli for do wypisania wszystkich danych z bazy na ekran.

Podsumowując:

1. Instrukcji for używamy, jeżeli chcemy wykonać kilka instrukcji określoną ilość razy.
2. Przy użyciu instrukcji for należy ustawić warunki na licznik: stan początkowy, warunek wykonywania pętli i wartość o jaką zmienia się wartość licznika po wykonaniu pętli.
3. Licznik jest to dodatkowa zmienna typu int.
4. Licznik nie musi byc zwiększany, równie dobrze może liczyć w odwrotną stronę.
5. Licznik nie musi zmieniać się o 1, lecz o dowolną wartość, aczkolwiek pierwszy przypadek jest częściej wykorzystywany w praktyce

Instrukcja for jest bardzo wygodna, ale ma jedną wadę: trzeba z góry wiedzieć, ile razy zostanie wykonana. Może o tym decydować inna zmienna, ale zawsze trzeba ją określić przed pierwszym wykonaniem pętli. Czasami zależy nam jednak w programie na tym, aby przerwać działanie pętli w momencie, kiedy pewien warunek przestanie być spełniany, ale nie wiadomo, kiedy to nastąpi. Np. program dotąd pyta użytkownika o odpowiedź, aż ten odpowie poprawnie.

Pętle, o których mowa to while i do-while. Różnią się one bardzo niewiele od siebie, ale wykazują sporo różnic w porównaniu z pętlą for. Po pierwsze: nie zawierają zmiennej sterującej, czyli licznika, który określał, ile razy pętla została wykonana (nic nie stoi jednak na przeszkodzie, aby taki licznik sobie tam umieścić, jeśli zajdzie taka potrzeba). Pora na przykład:

#include <stdio.h>
#include <conio.h>
main (void)
{
int odp;

clrscr();
while(odp!=7344)
{
printf("Ile jest 153 razy 48?\n");
scanf("%d",&odp);
if (odp<7344) printf("Spróbuj jeszcze raz (wynik jest większy)");
else
if (odp>7344) printf("Spróbuj jeszcze raz (wynik jest mniejszy)");
else
printf("Dobrze!");
}

getch();
return 0 ;
}

Ekran po wykonaniu programu mógłby wyglądać tak:

Ile jest 153 razy 48?
5000
Spróbuj jeszcze raz (wynik jest większy)
Ile jest 153 razy 48?
10000
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7000
Spróbuj jeszcze raz (wynik jest większy)
Ile jest 153 razy 48?
8000
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7500
Spróbuj jeszcze raz (wynik jest mniejszy)
Ile jest 153 razy 48?
7344
Dobrze!

W przykładzie warunkiem na to, aby pętla się wykonywała jest zła odpowiedź na pytanie. W momencie kiedy warunek ten przestanie być spełniany (użytkownik poda prawidłową odpowiedź) pętla zostanie zakończona. Zauważmy, że warunek sprawdzany jest jeszcze przed wykonaniem pętli! Może się więc zdarzyć, że pętla nie zostanie wykonana ani razu.

Ten sam program można napisać przy użyciu pętli do-while:

#include <stdio.h>
#include <conio.h>
main (void)
{
int odp;

clrscr();
do {
printf("Ile jest 153 razy 48?\n");
scanf("%d",&odp);
if (odp<7344) printf("Spróbuj jeszcze raz (wynik jest większy)");
else
if (odp>7344) printf("Spróbuj jeszcze raz (wynik jest mniejszy)");
else
printf("Dobrze!");
} while(odp!=7344)

getch();
return 0 ;
}

Działanie programu będzie na pozór identyczne. Różnica polega jednak na tym, że najpierw zostanie wykonane ciało pętli (instrukcje, które mają się powtarzać), a dopiero później sprawdzony zostanie warunek. Oznacza to, że taka pętla zawsze wykona się przynajmniej raz.

Dla programu z naszego przykładu nie ma znaczenia, której z tych pętli użyjemy. Gdybyśmy jednak jeszcze przed samą pętlą przypisali do zmiennej odp wartość 7344, dopiero zauważylibyśmy różnicę. W pierwszym przypadku pętla nie uruchomiłaby się ani razu, ponieważ program najpierw sprawdza warunek, a potem dopiero przechodzi do wykonania pętli. W drugim przypadku program najpierw zapytałby nas o podanie prawidłowego wyniku. Podaną odpowiedź przypisałby do zmiennej odp i dopiero sprawdził warunek. Działanie programu w drugim przypadku nie zmieniłoby się.

Kiedy używać while a kiedy do-while? Wybór należy do programisty, który sam powinien ocenić, która będzie bardziej przydatna. Ja osobiście cześciej używam do-while.

Podsumowując:

1. Pętlę for stosujemy, gdy wiemy ile razy ma się ona powtórzyć.
2. Pętle while i do-while stosujemy, gdy powtarzanie pętli chcemy uzależnić od spełnienia pewnego warunku i nie wiemy ile razy będzie trzeba ja powtórzyć.
3. Pętla while najpierw sprawdza warunek, więc instrukcje w niej zawarte mogą nigdy nie zostać wykonane.
4. Pętla do-while najpierw wykonuje instrukcje, a potem sprawdza warunek, więc instrukcje zostaną wykonane co najmniej raz.



LEKCJA 7 - WŁASNE FUNKCJE


Wiesz już bardzo dużo na temat programowania. Za pomocą tych prostych funkcji i instrukcji, które poznałeś w poprzednich lekcjach, możesz już tworzyć bardzo skomplikowane programy. Nieraz będą miały one bardzo długi kod, w którym łatwo sie będzie pogubić (a tym bardziej, jeśli nie zastosujesz komentarzy do opisywania różnych części kodu, odpowiedzialnych za wykonanie określonej czynności). Zwykle do wykonania jakiejś bardziej złożonej czynności służy kilka lub kilkanaście instrukcji. Jeżeli taką czynność będzie trzeba wykonać kilka razy w różnych miejscach programu, należy zdefiniować funkcję, która będzie grupowała i określała wszystkie te instrukcje.

Główną funkcją programu będzie jednak zawsze funkcja main(). To od niej zacznie się wykonywanie programu. Może się ona jednak odwoływać do innych funkcji, które sam zdefiniujesz. Definicja takiej funkcji, czyli przypisanie do jakiejś nazwy fragmentu kodu, musi odbyć się poza ciałem funkcji głównej main. Struktura programu wygląda więc następująco:

definicje plików nagłówkowych (dyrektywa #include)
definicje funkcji napisanych przez programistę i ich kod
funkcja główna main() i jej kod

Funkcja zdefiniowana przez programistę nie różni się dużo od funkcji głównej. Programista może jej nadać dowolną (no, prawie dowolną) nazwę. Deklaracja takiej funkcji odbywa się na zasadach analogicznych jak przy main(). Np.:

int mojafunkcja(int parametr)
{
deklaracja zmiennych tylko w obrebie funkcji;
instrukcje;
instrukcje;
return costam_typu_int;
}

Pora na przykład:

#include <stdio.h>
#include <conio.h>

int moja_funkcja(int a, int b, int c)
{
int suma;
suma=a*a+b*b+c*c;
return suma;
}

main (void)
{
int a;
a=moja_funkcja(1,2,3);
printf("%d",a);
}

getch();
return 0 ;
}

Zdefiniowalismy sobie własną funkcję o nazwie moja_funkcja(). Pobiera ona do działania 3 parametry - trzy liczby całkowite, a następnie oblicza sumę ich kwadratów. Wewnątrz funkcji zadeklarowaliśmy zmienną suma. Jest to tak zwana zmienna lokalna, to znaczy taka, która działa tylko w obrębie danej funkcji. Gdybyśmy spróbowali operować na zmiennej suma w ciele funkcji main(), kompilator zwróciłby błąd, że zmienna nie została zadeklarowana. Analogicznie sytuacja się ma ze zmienną a. W naszej funkcji została ona zadeklarowana jako parametr do wczytania. W ciele funkcji main znowu zadeklarowaliśmy zmienną a. Sęk w tym, że to nie jest już ta sama zmienna. Na tym właśnie polega istota zmiennych lokalnych- działają tylko w obrębie "swoich" funkcji.

Oprócz zmiennych lokalnych mamy jeszcze zmienne globalne. Jak nazwa wskazuje, mają one szersze znaczenie niż zmienne lokalne. Zmienna taka działa we wszystkich funkcjach jako ta sama zmienna (w powyższym przykładzie zmienna a jest czymś innym w funkcji main i czymś innym w funkcji moja_funkcja). Deklaruje się ją na samym początku programu, tuż po deklaracji plików nagłówkowych dyrektywą include. Spróbujmy zastosować teraz w ostatnim przykładzie zmienną globalną:

#include <stdio.h>
#include <conio.h>
int suma;

int moja_funkcja(int a, int b, int c)
{
suma=a*a+b*b+c*c;
return suma;
}

main (void)
{
moja_funkcja(1,2,3);
printf("%d",suma);
}

getch();
return 0 ;
}

Zmienną globalną w tym przykładzie jest suma. Jak widać, nie trzeba było deklarować jej ani w funkcji main ani w moja_funkcja. W obu tych funkcjach zmienna ta oznaczała tę samą zmienną. Dlatego po przepisaniu na nią pewnej wartości w funkcji w funkcji moja_funkcja zmiana jest też widoczna w funkcji main(). Zmienne lokalne i globalne różnią się w momencie przydzielania pamięci. Musisz sam zdecydować, które zmienne mają byc lokalne, a które globalne. Na razie będzie to zapewne wybór losowy, ale im więcej napiszesz programów, tym łatwiej będzie Ci o tym zdecydować.

Podsumowując:

1. Grupę instrukcji, które mają się gdzieś powtórzyć, możesz zgrupować w jedną funkcję, która będzie je wykonywać.
2. Funkcja może (ale nie musi) pobierać parametry.
3. Własne funkcje należy deklarować poza ciałem funkcji main().
4. Zmienna lokalna działa tylko wewnątrz określonej funkcji.
5. Zmienna globalna obowiązuje we wszystkich funkcjach jako ta sama zmienna.



LEKCJA 8 - WYGLĄD PROGRAMU W TRYBIE TEKSTOWYM


Wszystkie programy, które dotąd napisałeś, są bardzo podobne z wyglądu: czarne tło i szare komunikaty. Na tym poziomie, kiedy znasz już wszystkie najważniejsze zasady (wszystkie najważniejsze to nie znaczy wszystkie!), może to wydać się nudne. Nadszedł więc czas aby urozmaicić wygląd programu kolorami.

Do wyboru mamy 16 kolorów o numerach od 0 do 15 (przyjmować będziemy zapis dziesiętny).

Standardowymi kolorami są jasnoszary dla tekstu i czarny jeśli chodzi o tło. Aby zmienić kolor tekstu wystarczy zaznaczyć to funkcja textcolor(nr_koloru);. Od tej pory wszystkie następne komunikaty będą wypisywane w danym kolorze. Przykład:

#include <stdio.h>
#include <conio.h>
main (void)
clrscr();

for(int i=1;i<=15;i++)
{
textcolor(i);
cprintf("Anna Miedzianowska");
printf("\n");
}

getch();
return 0;
}

Efekt działania programu to wygląd ekranu:

W programie użyliśmy pętli, aby w prosty sposób zilustrować wszystkie dostępne kolory napisów (oczywiście oprócz czarnego, którego nie byłoby widać). Do wyświetlenia kolorowego komunikatu służy funkcja cprintf. Działa ona identycznie jak printf, jednak nie obsłuży nam znaku specjalnego "\n", czyli przejścia do nowej linii. Aby to zrobić należy użyć dodatkowo funkcji printf(), która nic nie wypisze, tylko umieści kursor w nowej linii.

Numery użytych kolorów przyjmują kolejne wartości od 1 do 15 i takie właśnie wartości przyjmuje nasz licznik i w pętli for. Mam nadzieję, że zauważyłeś, iż zmienna i nie jest zadeklarowana na samym początku tak jak robiliśmy to dotychczas, lecz bezpośrednio przed użyciem. Można tak postępować, jednakże lepiej jest wszystkie zmienne deklarować w tym samym miejscu, czyli np. na początku programu. Od momentu deklaracji takiej zmiennej (czyli w dalszej części kodu) można jej używać normalnie, czyli tak jakby została zadeklarowana na początku.

Tło, czyli to, co na razie jest czarne, również możemy zmienić na inny kolor. W tym przypadku mamy jednak do dyspozycji tylko pierwszych 8 kolorów (od 0 do 7). Do zmiany koloru tła służy funkcja textbackround(nr_koloru); Użycie jej nie zmieni nam jednak całego tła na ekranie, lecz tylko tło komunikatu. Uzyskujemy w ten sposób kolorowy pasek z tekstem. Na przykład:

#include <stdio.h>
#include <conio.h>
main (void)
clrscr();

textcolor(15); for(int i=0;i<=7;i++)
{
textbackground(i);
cprintf("Anna Miedzianowska");
printf("\n");
}

getch();
return 0 ;
}

I efekt:

Kolory tła i tekstu można zmienić za jednym razem za pomocą funkcji textattr(liczba);. W jaki sposób w jednej liczbie zapisać dwie? Zapis dziesiętny staje się tu mało czytelny, chyba, że zastosujemy zapis w postaci niewielkiego działania matematycznego. Liczbę możemy zapisać: liczba=16*tlo+tekst;. Tak przedstawione atrybuty składają się na liczbę czytelną dla kompilatora i zawierają informacje jednocześnie o dwóch cechach: kolorze tła i kolorze tekstu.

Który sposób jest lepszy? Wybór należy do programisty. W


Post został pochwalony 0 razy
Zobacz profil autora
sykus




Dołączył: 19 Cze 2006
Posty: 23 Przeczytał: 0 tematów

Ostrzeżeń: 0/5

PostWysłany: Śro 13:52, 21 Cze 2006 Powrót do góry

moze bys zaczal od czegos prostszego np. Pascala a nie od razu porywac sie z motyka na slonce.
i brak informacji i autorze kursu...


Post został pochwalony 0 razy
Zobacz profil autora
Gość






PostWysłany: Czw 14:30, 22 Cze 2006 Powrót do góry

haha umiesz c++ ? napisz lepiej .. albo sie w cale nieodzywaj
sykus




Dołączył: 19 Cze 2006
Posty: 23 Przeczytał: 0 tematów

Ostrzeżeń: 0/5

PostWysłany: Czw 16:26, 22 Cze 2006 Powrót do góry

nie umiem i dlatego sie odzywam, C++ na poczatek jest dosc trudny, bardzo dobrze ze zamiescil ten kurs ale powinno znalesc sie cos latwego na poczatek


Post został pochwalony 0 razy
Zobacz profil autora
Wyświetl posty z ostatnich:      
Napisz nowy tematOdpowiedz do tematu


 Skocz do:   



Zobacz następny temat
Zobacz poprzedni temat
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach


fora.pl - załóż własne forum dyskusyjne za darmo
Powered by phpBB © 2001/3 phpBB Group :: FI Theme :: Wszystkie czasy w strefie EET (Europa)